Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Admin Panel / Deploy Admin Panel (push) Waiting to run
Deploy Admin Panel / Admin Panel Verification (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
879 lines
24 KiB
Markdown
879 lines
24 KiB
Markdown
# 🎴 Mnemo Cards Backend
|
||
|
||
Backend сервер для приложения Mnemo Cards - платформы для изучения иностранных слов с использованием мнемотехники.
|
||
|
||
## 📋 Оглавление
|
||
|
||
- [Технологии](#-технологии)
|
||
- [Архитектура](#-архитектура)
|
||
- [Быстрый старт](#-быстрый-старт)
|
||
- [Структура проекта](#-структура-проекта)
|
||
- [API документация](#-api-документация)
|
||
- [Разработка](#-разработка)
|
||
- [Деплой](#-деплой)
|
||
- [Тестирование](#-тестирование)
|
||
- [Конфигурация](#-конфигурация)
|
||
|
||
---
|
||
|
||
## 🚀 Технологии
|
||
|
||
### Backend Stack
|
||
- **Язык:** Dart 3.8+
|
||
- **HTTP сервер:** Shelf
|
||
- **База данных:** PostgreSQL 16 + Drift ORM
|
||
- **Аутентификация:** JWT (jaguar_jwt)
|
||
- **DI:** get_it + injectable
|
||
- **API:** RESTful API v2
|
||
|
||
### Интеграции
|
||
- **Платежи:** YooKassa (Российские платежи), Google Play, RuStore
|
||
- **Telegram Bot API:** Авторизация через Telegram
|
||
- **PostgreSQL:** Production-ready реляционная БД
|
||
|
||
### DevOps
|
||
- **Контейнеризация:** Docker + Docker Compose
|
||
- **Deployment:** Coolify (или любой Docker хостинг)
|
||
- **CI/CD:** GitHub Actions (опционально)
|
||
|
||
---
|
||
|
||
## 🏗️ Архитектура
|
||
|
||
```
|
||
┌─────────────────┐
|
||
│ Web Client │
|
||
│ (Flutter Web) │
|
||
└────────┬────────┘
|
||
│ HTTPS
|
||
▼
|
||
┌─────────────────┐ ┌──────────────┐
|
||
│ Mnemo Backend │◄────►│ PostgreSQL │
|
||
│ (Dart/Shelf) │ │ Database │
|
||
└────────┬────────┘ └──────────────┘
|
||
│
|
||
├─► YooKassa API (Payments)
|
||
├─► Telegram Bot API (Auth)
|
||
├─► Google Play API (IAP)
|
||
└─► RuStore API (IAP)
|
||
```
|
||
|
||
### Основные компоненты
|
||
|
||
- **API Server** (`lib/api/mnemo_shelf.dart`) - HTTP сервер на Shelf
|
||
- **Database** (`lib/database/`) - Drift ORM + PostgreSQL
|
||
- **Managers** (`lib/user/`, `lib/packs/`, etc.) - Бизнес-логика
|
||
- **Cron Jobs** (`lib/cron/`) - Фоновые задачи
|
||
- **Auth** (`lib/auth/`, `lib/api/authorize/`) - JWT аутентификация
|
||
|
||
---
|
||
|
||
## ⚡ Быстрый старт
|
||
|
||
### Требования
|
||
|
||
- **Dart SDK:** 3.8.0+
|
||
- **PostgreSQL:** 16+ (локально или Docker)
|
||
- **Docker & Docker Compose** (опционально, для PostgreSQL)
|
||
|
||
### 1. Клонирование репозитория
|
||
|
||
```bash
|
||
git clone <repository-url>
|
||
cd mnemo_cards_backend
|
||
```
|
||
|
||
### 2. Установка зависимостей
|
||
|
||
```bash
|
||
# Установка Dart зависимостей
|
||
dart pub get
|
||
|
||
# Генерация кода (Drift, Injectable, JSON)
|
||
dart run build_runner build --delete-conflicting-outputs
|
||
```
|
||
|
||
### 3. Настройка PostgreSQL
|
||
|
||
#### Вариант A: Docker (рекомендуется для разработки)
|
||
|
||
```bash
|
||
# Запустить PostgreSQL через Docker Compose
|
||
docker-compose up -d postgres
|
||
|
||
# Проверить статус
|
||
docker-compose ps
|
||
```
|
||
|
||
#### Вариант B: Локальная установка
|
||
|
||
```bash
|
||
# macOS
|
||
brew install postgresql@16
|
||
brew services start postgresql@16
|
||
|
||
# Linux
|
||
sudo apt install postgresql-16
|
||
sudo systemctl start postgresql
|
||
```
|
||
|
||
Создать базу данных:
|
||
|
||
```sql
|
||
CREATE DATABASE mnemo_cards_dev;
|
||
CREATE USER mnemo_user WITH PASSWORD 'dev_password';
|
||
GRANT ALL PRIVILEGES ON DATABASE mnemo_cards_dev TO mnemo_user;
|
||
```
|
||
|
||
### 4. Настройка переменных окружения
|
||
|
||
```bash
|
||
# Создать .env файл из примера
|
||
cp .env.example .env
|
||
|
||
# Отредактировать .env (указать реальные значения)
|
||
nano .env
|
||
```
|
||
|
||
**Минимальная конфигурация** для `.env`:
|
||
|
||
```bash
|
||
# PostgreSQL
|
||
DB_HOST=localhost
|
||
DB_PORT=5432
|
||
DB_NAME=mnemo_cards_dev
|
||
DB_USER=mnemo_user
|
||
DB_PASSWORD=dev_password
|
||
DB_SSL_MODE=disable
|
||
|
||
# Backend
|
||
PORT=3000
|
||
SERVER_ADDRESS=0.0.0.0
|
||
WORK_DIR=/root/mnemo_cards_backend
|
||
DEBUG=true
|
||
|
||
# Admin IDs
|
||
ADMIN_IDS=1
|
||
|
||
# JWT Secrets (сгенерировать случайные!)
|
||
JWT_SECRET=dev_jwt_secret_change_me_12345
|
||
JWT_REFRESH_SECRET=dev_refresh_secret_change_me_12345
|
||
```
|
||
|
||
> ⚠️ **Важно:** Сгенерируйте надежные JWT секреты для продакшена:
|
||
> ```bash
|
||
> openssl rand -base64 32
|
||
> ```
|
||
|
||
### 5. Запуск сервера
|
||
|
||
```bash
|
||
# Development mode
|
||
./run_dev.sh
|
||
|
||
# Или напрямую
|
||
dart run lib/main.dart
|
||
```
|
||
|
||
Сервер запустится на `http://localhost:3000`
|
||
|
||
### 6. Проверка работоспособности
|
||
|
||
```bash
|
||
# Health check
|
||
curl http://localhost:3000/health
|
||
|
||
# API version info
|
||
curl http://localhost:3000/api/v2/health
|
||
```
|
||
|
||
---
|
||
|
||
## 📁 Структура проекта
|
||
|
||
```
|
||
mnemo_cards_backend/
|
||
├── lib/
|
||
│ ├── api/ # API endpoints и middleware
|
||
│ │ ├── v2/ # RESTful API v2
|
||
│ │ │ ├── auth_api_v2.dart # Авторизация
|
||
│ │ │ ├── users_api_v2.dart # Пользователи
|
||
│ │ │ ├── packs_api_v2.dart # Наборы карточек
|
||
│ │ │ ├── tests_api_v2.dart # Тесты
|
||
│ │ │ ├── subscriptions_api_v2.dart # Подписки
|
||
│ │ │ ├── promocodes_api_v2.dart # Промокоды
|
||
│ │ │ ├── admin_*_api_v2.dart # Админ панель
|
||
│ │ │ └── ...
|
||
│ │ ├── authorize/ # Middleware для авторизации
|
||
│ │ ├── purchase/ # Платежи (YooKassa, Google Play, RuStore)
|
||
│ │ ├── subscription/ # Управление подписками
|
||
│ │ ├── di/ # Dependency Injection (get_it)
|
||
│ │ └── mnemo_shelf.dart # Главный HTTP сервер
|
||
│ │
|
||
│ ├── database/ # PostgreSQL + Drift ORM
|
||
│ │ ├── database.dart # Главный класс БД
|
||
│ │ ├── tables/ # Определения таблиц
|
||
│ │ │ ├── users.dart
|
||
│ │ │ ├── packs.dart
|
||
│ │ │ ├── auth.dart
|
||
│ │ │ ├── payments.dart
|
||
│ │ │ ├── word_statistics.dart # Статистика ответов на карточки
|
||
│ │ │ ├── audit.dart # Audit trail (инфраструктура)
|
||
│ │ │ └── ...
|
||
│ │ └── daos/ # Data Access Objects
|
||
│ │ ├── user_dao.dart
|
||
│ │ ├── pack_dao.dart
|
||
│ │ ├── word_statistics_dao.dart # Работа со статистикой слов
|
||
│ │ ├── audit_dao.dart # Audit logging
|
||
│ │ └── mixins/
|
||
│ │ └── soft_delete_mixin.dart # Soft delete функциональность
|
||
│ │
|
||
│ ├── user/ # User management
|
||
│ │ └── user_manager.dart
|
||
│ │
|
||
│ ├── packs/ # Pack management
|
||
│ │ ├── pack_manager.dart
|
||
│ │ └── free_packs_distributor.dart
|
||
│ │
|
||
│ ├── tests/ # Test management
|
||
│ │ └── test_manager.dart
|
||
│ │
|
||
│ ├── tasks/ # Task management
|
||
│ │ └── task_manager.dart
|
||
│ │
|
||
│ ├── promo_codes/ # Promo codes
|
||
│ │ └── promo_codes_manager.dart
|
||
│ │
|
||
│ ├── discounts/ # Discounts
|
||
│ │ └── discounts_manager.dart
|
||
│ │
|
||
│ ├── statistics/ # User statistics
|
||
│ │ ├── session_tracker.dart
|
||
│ │ ├── statistics_calculator.dart
|
||
│ │ ├── word_statistics_manager.dart # Управление статистикой ответов
|
||
│ │ └── session_tracking_middleware.dart
|
||
│ │
|
||
│ ├── cron/ # Background jobs
|
||
│ │ ├── cron_executor.dart
|
||
│ │ ├── check_payment.dart
|
||
│ │ ├── backup.dart
|
||
│ │ ├── add_free_packs.dart
|
||
│ │ └── ...
|
||
│ │
|
||
│ ├── auth/ # Authentication utilities
|
||
│ │ ├── hash.dart
|
||
│ │ └── password.dart
|
||
│ │
|
||
│ └── main.dart # Entry point
|
||
│
|
||
├── test/ # Unit & integration tests
|
||
│ ├── api/v2/ # API tests
|
||
│ ├── database/ # Database tests
|
||
│ ├── models/ # Model tests
|
||
│ └── statistics/ # Statistics tests
|
||
│
|
||
├── data/ # Static data (images, audio)
|
||
├── public/ # Public files
|
||
├── docs/ # Documentation
|
||
│
|
||
├── docker-compose.yml # Docker Compose для разработки
|
||
├── Dockerfile # Production Docker image
|
||
├── pubspec.yaml # Dart dependencies
|
||
├── .env.example # Пример переменных окружения
|
||
│
|
||
├── run_dev.sh # Скрипт запуска (dev)
|
||
├── run_http_production.sh # Скрипт запуска (prod)
|
||
├── build_app.sh # Скрипт сборки
|
||
├── codegen.sh # Генерация кода
|
||
│
|
||
├── COOLIFY_SETUP.md # Инструкции по деплою в Coolify
|
||
├── ENVIRONMENT_VARIABLES.md # Описание env переменных
|
||
├── DB_PLAN.md # План миграции БД
|
||
└── README.md # Этот файл
|
||
```
|
||
|
||
---
|
||
|
||
## 🌐 API документация
|
||
|
||
### Base URL
|
||
|
||
- **Local:** `http://localhost:3000/api/v2`
|
||
- **Production:** `https://your-domain.com/api/v2`
|
||
|
||
### Авторизация
|
||
|
||
Backend использует **JWT Bearer tokens** для авторизации:
|
||
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
```
|
||
|
||
### Основные endpoints
|
||
|
||
#### Аутентификация
|
||
|
||
```http
|
||
POST /api/v2/auth/register # Регистрация
|
||
POST /api/v2/auth/login # Логин
|
||
POST /api/v2/auth/refresh # Обновить токен
|
||
POST /api/v2/auth/telegram # Авторизация через Telegram
|
||
GET /api/v2/auth/telegram/code # Получить код для Telegram
|
||
```
|
||
|
||
#### Пользователи
|
||
|
||
```http
|
||
GET /api/v2/users/me # Текущий пользователь
|
||
PATCH /api/v2/users/me # Обновить профиль
|
||
GET /api/v2/users/:id # Получить пользователя
|
||
GET /api/v2/users/:id/statistics # Статистика пользователя
|
||
POST /api/v2/users/:id/balance # Обновить баланс
|
||
```
|
||
|
||
#### Наборы карточек (Packs)
|
||
|
||
```http
|
||
GET /api/v2/packs # Список паков (preview)
|
||
GET /api/v2/packs/:id # Детали пака
|
||
GET /api/v2/packs/:id/cards # Карточки пака
|
||
POST /api/v2/packs/:id/purchase # Купить пак
|
||
```
|
||
|
||
#### Тесты
|
||
|
||
```http
|
||
GET /api/v2/tests # Список тестов
|
||
GET /api/v2/tests/:id # Детали теста
|
||
POST /api/v2/tests/:id/start # Начать тест
|
||
POST /api/v2/tests/:id/submit # Отправить ответы
|
||
GET /api/v2/tests/:id/results # Результаты теста
|
||
```
|
||
|
||
#### Подписки
|
||
|
||
```http
|
||
GET /api/v2/subscriptions/plans # Доступные планы
|
||
POST /api/v2/subscriptions/purchase # Купить подписку
|
||
GET /api/v2/subscriptions/my # Мои подписки
|
||
```
|
||
|
||
#### Промокоды
|
||
|
||
```http
|
||
POST /api/v2/promocodes/apply # Применить промокод
|
||
GET /api/v2/promocodes/:code # Проверить промокод
|
||
```
|
||
|
||
#### Админ панель
|
||
|
||
```http
|
||
GET /api/v2/admin/users # Все пользователи
|
||
GET /api/v2/admin/packs # Все паки
|
||
POST /api/v2/admin/packs # Создать пак
|
||
PUT /api/v2/admin/packs/:id # Обновить пак
|
||
DELETE /api/v2/admin/packs/:id # Удалить пак
|
||
GET /api/v2/admin/analytics # Аналитика
|
||
```
|
||
|
||
### Health Check
|
||
|
||
```http
|
||
GET /health # Health check endpoint
|
||
```
|
||
|
||
**Response:**
|
||
```
|
||
OK
|
||
```
|
||
|
||
---
|
||
|
||
## 💻 Разработка
|
||
|
||
### Генерация кода
|
||
|
||
Backend использует code generation для:
|
||
- **Drift** (database code)
|
||
- **Injectable** (dependency injection)
|
||
- **Shelf Router** (routing)
|
||
- **JSON Serializable** (JSON mapping)
|
||
|
||
```bash
|
||
# Генерация кода
|
||
dart run build_runner build --delete-conflicting-outputs
|
||
|
||
# Watch mode (автоматическая генерация при изменениях)
|
||
dart run build_runner watch --delete-conflicting-outputs
|
||
|
||
# Или использовать скрипт
|
||
./codegen.sh
|
||
```
|
||
|
||
### Работа с базой данных
|
||
|
||
#### Создание новой таблицы
|
||
|
||
1. Создать файл в `lib/database/tables/`:
|
||
|
||
```dart
|
||
// lib/database/tables/my_table.dart
|
||
import 'package:drift/drift.dart';
|
||
|
||
class MyTables extends Table {
|
||
IntColumn get id => integer().autoIncrement()();
|
||
TextColumn get name => text()();
|
||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||
}
|
||
```
|
||
|
||
2. Добавить таблицу в `lib/database/database.dart`:
|
||
|
||
```dart
|
||
@DriftDatabase(
|
||
tables: [
|
||
// ... existing tables
|
||
MyTables,
|
||
],
|
||
// ...
|
||
)
|
||
```
|
||
|
||
3. Сгенерировать код:
|
||
|
||
```bash
|
||
dart run build_runner build --delete-conflicting-outputs
|
||
```
|
||
|
||
#### Создание DAO
|
||
|
||
```dart
|
||
// lib/database/daos/my_dao.dart
|
||
import 'package:drift/drift.dart';
|
||
import '../database.dart';
|
||
|
||
part 'my_dao.g.dart';
|
||
|
||
@DriftAccessor(tables: [MyTables])
|
||
class MyDao extends DatabaseAccessor<AppDatabase> with _$MyDaoMixin {
|
||
MyDao(super.db);
|
||
|
||
Future<List<MyTable>> getAll() => select(myTables).get();
|
||
Future<MyTable?> getById(int id) =>
|
||
(select(myTables)..where((t) => t.id.equals(id))).getSingleOrNull();
|
||
Future<int> create(MyTablesCompanion entry) => into(myTables).insert(entry);
|
||
}
|
||
```
|
||
|
||
### Добавление нового API endpoint
|
||
|
||
1. Создать файл в `lib/api/v2/`:
|
||
|
||
```dart
|
||
// lib/api/v2/my_api_v2.dart
|
||
import 'package:shelf/shelf.dart';
|
||
import 'package:shelf_router/shelf_router.dart';
|
||
import 'package:injectable/injectable.dart';
|
||
|
||
@lazySingleton
|
||
class MyApiV2 {
|
||
final AppDatabase _db;
|
||
|
||
MyApiV2(this._db);
|
||
|
||
Router get router {
|
||
final router = Router();
|
||
|
||
router.get('/my-endpoint', _handleGet);
|
||
router.post('/my-endpoint', _handlePost);
|
||
|
||
return router;
|
||
}
|
||
|
||
Future<Response> _handleGet(Request request) async {
|
||
// Implementation
|
||
return Response.ok('{"status": "ok"}');
|
||
}
|
||
|
||
Future<Response> _handlePost(Request request) async {
|
||
// Implementation
|
||
return Response.ok('{"status": "created"}');
|
||
}
|
||
}
|
||
```
|
||
|
||
2. Зарегистрировать в `lib/api/mnemo_shelf.dart`:
|
||
|
||
```dart
|
||
v2Router.mount('/', getIt.get<MyApiV2>().router);
|
||
```
|
||
|
||
### Cron Jobs
|
||
|
||
Фоновые задачи запускаются автоматически при старте сервера.
|
||
|
||
Создание нового cron job:
|
||
|
||
```dart
|
||
// lib/cron/my_task.dart
|
||
import 'package:neat_periodic_task/neat_periodic_task.dart';
|
||
import 'task.dart';
|
||
|
||
class MyTask extends Task {
|
||
@override
|
||
String get name => 'My Task';
|
||
|
||
@override
|
||
Duration get interval => const Duration(hours: 1);
|
||
|
||
@override
|
||
Duration get timeout => const Duration(minutes: 5);
|
||
|
||
@override
|
||
Future<void> run() async {
|
||
print('Running my task...');
|
||
// Implementation
|
||
}
|
||
}
|
||
```
|
||
|
||
Добавить в `lib/main.dart`:
|
||
|
||
```dart
|
||
CronManager([
|
||
// ... existing tasks
|
||
MyTask(),
|
||
]).init();
|
||
```
|
||
|
||
### Debugging
|
||
|
||
```bash
|
||
# Запуск с дебагом
|
||
DEBUG=true dart run lib/main.dart
|
||
|
||
# Логи PostgreSQL
|
||
docker-compose logs -f postgres
|
||
|
||
# Логи backend
|
||
docker-compose logs -f backend
|
||
|
||
# Подключение к PostgreSQL
|
||
docker-compose exec postgres psql -U mnemo_user -d mnemo_cards_dev
|
||
```
|
||
|
||
---
|
||
|
||
## 🚢 Деплой
|
||
|
||
### Docker (рекомендуется)
|
||
|
||
#### 1. Сборка образа
|
||
|
||
```bash
|
||
# Build Docker image
|
||
docker build -t mnemo_backend:latest .
|
||
|
||
# Или использовать скрипт
|
||
./build_app.sh
|
||
```
|
||
|
||
#### 2. Запуск через Docker Compose
|
||
|
||
```bash
|
||
# Production
|
||
docker-compose -f docker-compose.prod.yml up -d
|
||
|
||
# Проверка
|
||
docker-compose ps
|
||
docker-compose logs -f backend
|
||
```
|
||
|
||
### Coolify (PaaS)
|
||
|
||
Подробная инструкция по деплою в Coolify: **[COOLIFY_SETUP.md](./COOLIFY_SETUP.md)**
|
||
|
||
**Краткая версия:**
|
||
|
||
1. Создать PostgreSQL в Coolify
|
||
2. Создать приложение (Dockerfile)
|
||
3. Настроить environment variables
|
||
4. Deploy
|
||
|
||
### Переменные окружения для продакшена
|
||
|
||
Полное описание всех переменных: **[ENVIRONMENT_VARIABLES.md](./ENVIRONMENT_VARIABLES.md)**
|
||
|
||
**Критически важные:**
|
||
|
||
```bash
|
||
# PostgreSQL (используйте internal hostname в Coolify)
|
||
DB_HOST=mnemo-postgres
|
||
DB_PORT=5432
|
||
DB_NAME=mnemo_cards
|
||
DB_USER=mnemo_user
|
||
DB_PASSWORD=<сгенерированный_пароль>
|
||
DB_SSL_MODE=require
|
||
|
||
# Backend
|
||
PORT=3000
|
||
SERVER_ADDRESS=0.0.0.0
|
||
DEBUG=false
|
||
|
||
# JWT (минимум 32 символа!)
|
||
JWT_SECRET=<сгенерированный_секрет>
|
||
JWT_REFRESH_SECRET=<другой_сгенерированный_секрет>
|
||
|
||
# Admin IDs
|
||
ADMIN_IDS=1,2,3
|
||
|
||
# YooKassa (если используете)
|
||
YOOKASSA_SHOP_ID=<ваш_shop_id>
|
||
YOOKASSA_SECRET_KEY=<ваш_secret_key>
|
||
```
|
||
|
||
### Health Checks
|
||
|
||
Backend предоставляет `/health` endpoint для мониторинга:
|
||
|
||
```bash
|
||
curl https://your-domain.com/health
|
||
# Response: OK
|
||
```
|
||
|
||
Настройка в Docker Compose:
|
||
|
||
```yaml
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
start_period: 40s
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 Тестирование
|
||
|
||
### Запуск тестов
|
||
|
||
```bash
|
||
# Все тесты
|
||
dart test
|
||
|
||
# Конкретный файл
|
||
dart test test/api/v2/users_api_v2_test.dart
|
||
|
||
# С coverage
|
||
dart test --coverage=coverage
|
||
dart pub global activate coverage
|
||
format_coverage --lcov --in=coverage --out=coverage/lcov.info --report-on=lib
|
||
```
|
||
|
||
### Структура тестов
|
||
|
||
```
|
||
test/
|
||
├── api/v2/ # API endpoint tests
|
||
│ ├── auth_api_v2_test.dart
|
||
│ ├── users_api_v2_test.dart
|
||
│ ├── packs_api_v2_test.dart
|
||
│ └── ...
|
||
├── database/ # Database tests
|
||
├── models/ # Model tests
|
||
└── statistics/ # Statistics tests
|
||
```
|
||
|
||
### Написание тестов
|
||
|
||
```dart
|
||
import 'package:test/test.dart';
|
||
import 'package:mockito/mockito.dart';
|
||
import 'package:mnemo_cards_backend/database/database.dart';
|
||
|
||
void main() {
|
||
late AppDatabase db;
|
||
|
||
setUpAll(() async {
|
||
// Setup test database
|
||
db = AppDatabase.connect(
|
||
host: 'localhost',
|
||
port: 5433, // Test port
|
||
database: 'mnemo_cards_test',
|
||
username: 'test_user',
|
||
password: 'test_pass',
|
||
);
|
||
|
||
await db.migrator.createAll();
|
||
});
|
||
|
||
tearDownAll(() async {
|
||
await db.close();
|
||
});
|
||
|
||
group('UserDao', () {
|
||
test('создание пользователя', () async {
|
||
// Arrange
|
||
final user = UsersCompanion.insert(
|
||
name: 'Test User',
|
||
externalUserId: 'test123',
|
||
);
|
||
|
||
// Act
|
||
final userId = await db.userDao.createUser(user);
|
||
final created = await db.userDao.getUserById(userId);
|
||
|
||
// Assert
|
||
expect(created, isNotNull);
|
||
expect(created!.name, equals('Test User'));
|
||
});
|
||
});
|
||
}
|
||
```
|
||
|
||
### API тестирование
|
||
|
||
```bash
|
||
# Используйте ./test_api.sh или curl
|
||
curl -X POST http://localhost:3000/api/v2/auth/register \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email": "test@example.com", "password": "password123"}'
|
||
```
|
||
|
||
---
|
||
|
||
## ⚙️ Конфигурация
|
||
|
||
### Основные переменные окружения
|
||
|
||
| Переменная | Описание | По умолчанию | Обязательная |
|
||
|-----------|----------|--------------|--------------|
|
||
| `DB_HOST` | PostgreSQL host | `localhost` | ✅ |
|
||
| `DB_PORT` | PostgreSQL port | `5432` | ✅ |
|
||
| `DB_NAME` | Database name | `mnemo_cards` | ✅ |
|
||
| `DB_USER` | Database user | `mnemo_user` | ✅ |
|
||
| `DB_PASSWORD` | Database password | - | ✅ |
|
||
| `DB_SSL_MODE` | SSL mode | `disable` | ❌ |
|
||
| `PORT` | Backend port | `3000` | ✅ |
|
||
| `SERVER_ADDRESS` | Bind address | `0.0.0.0` | ✅ |
|
||
| `WORK_DIR` | Working directory | `/app` | ✅ |
|
||
| `DEBUG` | Debug mode | `false` | ❌ |
|
||
| `JWT_SECRET` | JWT secret | - | ✅ |
|
||
| `JWT_REFRESH_SECRET` | Refresh token secret | - | ✅ |
|
||
| `ADMIN_IDS` | Admin user IDs | - | ✅ |
|
||
| `YOOKASSA_SHOP_ID` | YooKassa shop ID | - | ❌ |
|
||
| `YOOKASSA_SECRET_KEY` | YooKassa secret | - | ❌ |
|
||
|
||
Полное описание: **[ENVIRONMENT_VARIABLES.md](./ENVIRONMENT_VARIABLES.md)**
|
||
|
||
### Генерация секретов
|
||
|
||
```bash
|
||
# JWT Secret (минимум 32 символа)
|
||
openssl rand -base64 32
|
||
|
||
# Database password
|
||
openssl rand -base64 24
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 Дополнительные ресурсы
|
||
|
||
### Документация
|
||
|
||
- **[COOLIFY_SETUP.md](./COOLIFY_SETUP.md)** - Деплой в Coolify
|
||
- **[ENVIRONMENT_VARIABLES.md](./ENVIRONMENT_VARIABLES.md)** - Переменные окружения
|
||
- **[DB_PLAN.md](./DB_PLAN.md)** - План миграции БД (Isar → PostgreSQL)
|
||
|
||
### Полезные команды
|
||
|
||
```bash
|
||
# Генерация кода
|
||
./codegen.sh
|
||
|
||
# Запуск dev сервера
|
||
./run_dev.sh
|
||
|
||
# Подключение к PostgreSQL
|
||
./connect.sh
|
||
|
||
# Сборка для продакшена
|
||
./build_app.sh
|
||
|
||
# Тестирование API
|
||
./test_api.sh
|
||
```
|
||
|
||
### Troubleshooting
|
||
|
||
#### Backend не запускается
|
||
|
||
1. Проверить PostgreSQL:
|
||
```bash
|
||
docker-compose ps postgres
|
||
docker-compose logs postgres
|
||
```
|
||
|
||
2. Проверить переменные окружения:
|
||
```bash
|
||
cat .env
|
||
```
|
||
|
||
3. Проверить подключение к БД:
|
||
```bash
|
||
docker-compose exec postgres psql -U mnemo_user -d mnemo_cards_dev
|
||
```
|
||
|
||
#### Ошибка "Connection refused"
|
||
|
||
- Убедитесь, что PostgreSQL запущен
|
||
- Проверьте `DB_HOST` и `DB_PORT`
|
||
- В Docker используйте service name (`postgres`), а не `localhost`
|
||
|
||
#### Ошибка "Invalid JWT secret"
|
||
|
||
- JWT секрет должен быть минимум 32 символа
|
||
- Сгенерируйте новый: `openssl rand -base64 32`
|
||
|
||
#### Drift генерация не работает
|
||
|
||
```bash
|
||
# Очистить кэш
|
||
rm -rf .dart_tool/
|
||
dart pub get
|
||
dart run build_runner build --delete-conflicting-outputs
|
||
```
|
||
|
||
---
|
||
|
||
## 🤝 Контрибуция
|
||
|
||
1. Fork the repository
|
||
2. Create feature branch (`git checkout -b feature/amazing-feature`)
|
||
3. Commit changes (`git commit -m 'Add amazing feature'`)
|
||
4. Push to branch (`git push origin feature/amazing-feature`)
|
||
5. Open Pull Request
|
||
|
||
### Code Style
|
||
|
||
- Следуйте [Dart Style Guide](https://dart.dev/guides/language/effective-dart/style)
|
||
- Используйте `dart format` перед коммитом
|
||
- Пишите unit тесты для новой функциональности
|
||
|
||
---
|
||
|
||
## 📝 Лицензия
|
||
|
||
[Your License Here]
|
||
|
||
---
|
||
|
||
## 📧 Контакты
|
||
|
||
Если возникли вопросы или проблемы, создайте Issue в репозитории.
|
||
|
||
---
|
||
|
||
**Made with ❤️ using Dart & PostgreSQL**
|