Полная реализация дипломного проекта на Go для разработки полнофункциональной системы управления блогом с REST API, JWT аутентификацией, PostgreSQL и планировщиком отложенной публикации.
- О проекте
- Структура проекта
- Технологический стек
- Быстрый старт
- Разработка
- API эндпоинты
- Планировщик отложенной публикации
- Тестирование
- Документация
- Архитектура приложения
Advanced Blog Management System - это полная реализация дипломного проекта для студентов, изучающих Go, REST API и работу с базами данных.
Проект включает:
- ✅ Управление пользователями (регистрация, вход)
- ✅ Управление постами (создание, редактирование, удаление)
- ✅ Управление комментариями (создание, редактирование, удаление)
- ✅ JWT аутентификация и авторизация
- ✅ Отложенная публикация постов с автоматическим планировщиком
- ✅ Логирование всех запросов с уникальными request_id
- ✅ Кеширование GET-запросов (5 минут по умолчанию)
- ✅ CORS поддержка
- ✅ Swagger документация
- ✅ Docker контейнеризация
- ✅ Полное покрытие тестами
advanced-blog-management-system/
├── cmd/api/
│ └── main.go # Точка входа приложения
├── docs/ # Swagger документация
│ ├── docs.go
│ ├── swagger.json
│ └── swagger.yaml
├── internal/
│ ├── apperrors/ # Ошибки приложения
│ │ └── errors.go
│ ├── handler/ # HTTP обработчики
│ │ ├── auth_handler.go
│ │ ├── post_handler.go
│ │ ├── comment_handler.go
│ │ ├── health.go
│ │ └── *_test.go
│ ├── middleware/ # HTTP middleware
│ │ ├── auth.go
│ │ ├── logging.go
│ │ ├── cors.go
│ │ ├── cache.go
│ │ ├── recovery.go
│ │ └── *_test.go
│ ├── model/ # Модели данных
│ │ ├── models.go
│ │ └── *_test.go
│ ├── repository/ # Слой доступа к БД
│ │ ├── interfaces.go
│ │ ├── user_repo.go
│ │ ├── post_repo.go
│ │ ├── comment_repo.go
│ │ └── *_test.go
│ └── service/ # Бизнес-логика
│ ├── user_service.go
│ ├── post_service.go
│ ├── comment_service.go
│ ├── scheduler.go
│ └── *_test.go
├── pkg/
│ ├── auth/ # Утилиты аутентификации
│ │ ├── jwt.go
│ │ ├── password.go
│ │ └── *_test.go
│ └── database/ # Утилиты БД
│ ├── db.go
│ └── *_test.go
├── migrations/ # SQL миграции
│ ├── 001_init_schema.sql
│ ├── 002_add_foreign_keys.sql
│ └── 003_create_indexes.sql
├── .env.example # Пример конфигурации
├── docker-compose.yml # Docker Compose
├── Dockerfile # Docker образ
├── go.mod # Зависимости проекта
└── README.md
- Язык: Go 1.24.5
- Веб-фреймворк: Chi Router
- База данных: PostgreSQL 15
- Аутентификация: JWT (golang-jwt)
- Хеширование: bcrypt (golang.org/x/crypto)
- Документация: Swagger/OpenAPI
- Контейнеризация: Docker, Docker Compose
- Валидация: go-playground/validator
- Go 1.24.5 или выше
- Docker и Docker Compose
- Git
# Клонировать репозиторий
git clone https://github.com/tim-zab/advanced-blog-management-system.git
cd advanced-blog-management-system
# Скопировать конфигурацию
cp .env.example .env
# Установить Go зависимости
go mod download# Запустить PostgreSQL в Docker
docker-compose up -d db
# Подождать пока БД запустится (примерно 15 секунд)
docker-compose logs db# Запустить приложение с race detector (рекомендуется)
go run -race ./cmd/api/main.go
# Или просто запустить
go run cmd/api/main.go
# Или собрать и запустить
go build -o api ./cmd/api/main.go
./apiПриложение будет доступно на http://localhost:8080
# Запустить всё через Docker Compose
docker-compose up --build
# Остановить
docker-compose down
# Очистить данные БД
docker-compose down -vПосле запуска:
- API доступен:
http://localhost:8080 - Swagger документация:
http://localhost:8080/swagger/index.html - JSON документация:
http://localhost:8080/swagger/doc.json
- Полная реализация всех компонентов
- Структура проекта и директории
- Модели данных (User, Post, Comment)
- Интерфейсы и реализация репозиториев
- SQL миграции (создание таблиц, внешних ключей и индексов)
- Функции хеширования паролей
- JWT генерация и валидация
- Middleware (аутентификация, логирование, CORS, кеширование, обработка ошибок)
- Все HTTP эндпоинты
- Планировщик отложенной публикации
- Swagger документация
- Полное покрытие тестами
- docker-compose.yml и Dockerfile
GET /api/health # Проверка здоровья приложения
POST /api/register # Регистрация нового пользователя
POST /api/login # Вход пользователя
GET /api/posts # Получить все посты (кешируется)
GET /api/posts/{id} # Получить пост по ID (кешируется)
GET /api/posts/{postId}/comments # Получить комментарии к посту (кешируется)
POST /api/posts # Создать пост
PUT /api/posts/{id} # Обновить пост
DELETE /api/posts/{id} # Удалить пост
POST /api/posts/{postId}/comments # Добавить комментарий
PUT /api/comments/{id} # Обновить комментарий
DELETE /api/comments/{id} # Удалить комментарий
- При создании поста с указанием
publish_atв будущем, пост сохраняется в статусе "draft" - Планировщик каждые 30 секунд проверяет посты со статусом "draft" и временем публикации <= текущего времени
- Найденные посты автоматически публикуются (статус меняется на "published", поле publish_at устанавливается в NULL)
- Обработка постов происходит конкурентно с использованием worker pool (5 воркеров по умолчанию)
- Все операции логируются для отслеживания процесса
- Интервал проверки: 30 секунд (настраивается в коде)
- Количество воркеров: 5 (настраивается в коде)
- Планировщик корректно завершается при остановке сервиса (graceful shutdown)
Создание поста с отложенной публикацией:
curl -X POST http://localhost:8080/api/posts \
-H "Authorization: Bearer <токен>" \
-H "Content-Type: application/json" \
-d '{
"title": "Отложенный пост",
"content": "Этот пост будет опубликован в указанное время",
"publish_at": "2025-12-31T23:59:59Z"
}'Проверка статуса поста (будет "draft" до указанного времени):
curl http://localhost:8080/api/posts/2 \
-H "Authorization: Bearer <токен>"# Запустить все тесты
go test ./...
# Запустить с подробным выводом
go test -v ./...
# Проверить на race conditions
go test -race ./...
# Посмотреть покрытие тестами
go test ./... -covercurl http://localhost:8080/api/healthОтвет:
{"status":"ok"}curl -X POST http://localhost:8080/api/register \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"email": "test@example.com",
"password": "password123"
}'Ответ (HTTP/1.1 201 Created):
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "2025-12-11T10:11:29.1543196+03:00",
"user": {
"id": 1,
"username": "testuser",
"email": "test@example.com",
"created_at": "2025-12-10T10:11:29.1493162+03:00"
}
}curl -X POST http://localhost:8080/api/login \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "password123"
}'Ответ (HTTP/1.1 200 OK):
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "2025-12-11T10:14:56.4065894+03:00",
"user": {
"id": 1,
"username": "testuser",
"email": "test@example.com",
"created_at": "2025-12-10T10:11:29.149316Z"
}
}curl -X POST http://localhost:8080/api/posts \
-H "Authorization: Bearer <токен>" \
-H "Content-Type: application/json" \
-d '{
"title": "Тестовый пост",
"content": "Содержание поста"
}'Ответ (HTTP/1.1 201 Created):
{
"id": 1,
"title": "Тестовый пост",
"content": "Содержание поста",
"author_id": 1,
"status": "published",
"created_at": "2025-12-10T10:17:23.9918739+03:00",
"updated_at": "2025-12-10T10:17:23.9918739+03:00"
}curl http://localhost:8080/api/postsОтвет (HTTP/1.1 200 OK):
{
"posts": [
{
"id": 1,
"title": "Тестовый пост",
"content": "Содержание поста",
"author_id": 1,
"status": "published",
"created_at": "2025-12-10T10:17:23.991874Z",
"updated_at": "2025-12-10T10:17:23.991874Z"
}
],
"total": 1,
"limit": 10,
"offset": 0
}curl -X POST http://localhost:8080/api/posts/1/comments \
-H "Authorization: Bearer <токен>" \
-H "Content-Type: application/json" \
-d '{
"content": "Отличный пост!"
}'Ответ (HTTP/1.1 201 Created):
{
"id": 1,
"content": "Отличный пост!",
"post_id": 1,
"author_id": 1,
"created_at": "2025-12-10T12:21:53.7135501+03:00",
"updated_at": "2025-12-10T12:21:53.7135501+03:00"
}Интерактивная документация доступна на:
http://localhost:8080/swagger/index.html- веб-интерфейс Swagger UIhttp://localhost:8080/swagger/doc.json- JSON документация
Проект использует чистую архитектуру с разделением ответственности:
┌─────────────────┐
│ HTTP Requests │
└────────┬────────┘
│
┌────────▼────────────────────────┐
│ Middleware (Auth, Logging, CORS)│
└────────┬────────────────────────┘
│
┌────────▼─────────────┐
│ Handlers (HTTP API) │ ← Парсинг JSON, валидация, HTTP коды
└────────┬─────────────┘
│
┌────────▼──────────────┐
│ Services (Business) │ ← Бизнес-логика, валидация, права
└────────┬──────────────┘
│
┌────────▼─────────────┐
│ Repositories (Data) │ ← SQL запросы, работа с БД
└────────┬─────────────┘
│
┌────────▼────────┐
│ PostgreSQL DB │
└─────────────────┘
- API: golang:1.24-alpine → компиляция → alpine:latest (многоэтапная сборка)
- База данных: postgres:15
- Сеть: bridge с именем blog-network
- Том: postgres_data для сохранения данных
- 001_init_schema.sql - создаёт таблицы users, posts, comments
- 002_add_foreign_keys.sql - добавляет внешние ключи для целостности данных
- 003_create_indexes.sql - создаёт индексы для улучшения производительности
Миграции запускаются автоматически при старте приложения.
Переменные окружения задаются в файле .env:
# Database
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=blog_db
DB_SSLMODE=disable
# JWT
JWT_SECRET=your-secret-key-change-in-production
# Server
SERVER_HOST=0.0.0.0
SERVER_PORT=8080
# Cache
CACHE_TTL=300
# Scheduler
SCHEDULER_INTERVAL=30
SCHEDULER_WORKERS=5
# Environment
ENV=developmentКаждый запрос логируется в формате:
20250405100000.123-456 | 172.18.0.1:54321 | POST /api/posts | 201 | 12.345ms
Где:
20250405100000.123-456- уникальный request_id172.18.0.1:54321- IP адрес клиентаPOST /api/posts- метод и путь201- HTTP статус код12.345ms- время обработки
GET-запросы кешируются на 5 минут (настраивается в конфиге):
- /api/posts
- /api/posts/{id}
- /api/posts/{postId}/comments
- JWT-аутентификация с HS256
- CORS разрешён для всех источников (можно настроить)
- Лимит одновременных запросов: 100
- Восстановление после паник (Recovery middleware)
- Параметризованные SQL-запросы (защита от SQL injection)
- Хеширование паролей с bcrypt
Приложение покрыто тестами:
| Пакет | Покрытие |
|---|---|
| cmd/api | 18.6% |
| internal/handler | 92.8% |
| internal/middleware | 51.9% |
| internal/model | 100.0% |
| internal/repository | 62.2% |
| internal/service | 76.1% |
| pkg/auth | 92.0% |
| pkg/database | 92.4% |
Для запуска тестов:
# Запустить все тесты
go test ./... -count=1
# Просмотреть покрытие
go test ./... -coverПримечание: Для запуска теста TestNewPostgresDB требуется наличие тестовой БД testdb или комментирование теста в pkg/database/init_test.go.
# Скачать и обновить зависимости
go mod download
go mod tidy
# Запустить приложение
go run -race ./cmd/api/main.go
# Собрать приложение
go build -o api ./cmd/api/main.go
# Запустить тесты
go test ./... -v
# Просмотреть логи БД
docker-compose logs db -f
# Подключиться к БД
docker-compose exec db psql -U postgres -d blog_db
# Остановить все сервисы
docker-compose down
# Очистить данные БД
docker-compose down -v-- Подключиться к БД
docker-compose exec db psql -U postgres -d blog_db
-- Просмотреть таблицы
\dt
-- Просмотреть пользователей
SELECT id, username, email, created_at FROM users;
-- Просмотреть посты
SELECT id, title, status, author_id, created_at FROM posts;
-- Просмотреть комментарии
SELECT id, content, post_id, author_id, created_at FROM comments;
-- Проверить посты в статусе draft
SELECT id, title, status, publish_at FROM posts WHERE status = 'draft';- ✅ Приложение запускается без ошибок
- ✅ Все 13+ API эндпоинтов работают
- ✅ JWT аутентификация работает правильно
- ✅ Пользователи могут редактировать только свои посты/комментарии
- ✅ Планировщик отложенной публикации работает
- ✅ Тесты проходят (go test ./...)
- ✅ Нет SQL injection уязвимостей
- ✅ Правильные HTTP статус коды
- ✅ Логирование работает
- ✅ Кеширование работает
- ✅ Приложение работает в Docker контейнере
Q: Как добавить нового пользователя вручную?
A: Используйте эндпоинт POST /api/register с валидными данными.
Q: Как получить JWT токен?
A: Отправьте POST /api/login с email и пароль - токен вернется в ответе.
Q: Что делать если БД не подключается?
A: Проверьте что docker-compose up запущен и подождите 15-20 секунд.
Q: Как сбросить БД?
A: Выполните docker-compose down -v для удаления всех данных.
Q: Как отсладжить проблемы с планировщиком?
A: Проверьте логи приложения - планировщик выводит информацию о каждой попытке публикации.