Загрузить файлы в «/»
This commit is contained in:
@@ -0,0 +1,62 @@
|
|||||||
|
# Application
|
||||||
|
APP_ENV=development
|
||||||
|
APP_SECRET_KEY=change-me
|
||||||
|
CORS_ORIGINS=http://localhost:5173
|
||||||
|
ACCESS_TOKEN_TTL_SECONDS=28800
|
||||||
|
INITIAL_ADMIN_EMAIL=admin@example.local
|
||||||
|
INITIAL_ADMIN_PASSWORD=change-me-admin
|
||||||
|
INITIAL_ADMIN_NAME=Администратор
|
||||||
|
|
||||||
|
# Database
|
||||||
|
POSTGRES_DB=meeting_assistant
|
||||||
|
POSTGRES_USER=meeting
|
||||||
|
POSTGRES_PASSWORD=password
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
DATABASE_URL=postgresql+psycopg://meeting:password@postgres:5432/meeting_assistant
|
||||||
|
DATABASE_CONNECT_TIMEOUT_SECONDS=3
|
||||||
|
|
||||||
|
# Queue
|
||||||
|
REDIS_URL=redis://redis:6379/0
|
||||||
|
|
||||||
|
# Jitsi
|
||||||
|
JITSI_DOMAIN=meet.company.local
|
||||||
|
VITE_JITSI_BASE_URL=https://meet.company.local
|
||||||
|
VITE_JITSI_REQUIRE_JWT=false
|
||||||
|
JITSI_APP_ID=meeting-assistant
|
||||||
|
JITSI_APP_SECRET=change-me
|
||||||
|
JITSI_TOKEN_TTL_SECONDS=7200
|
||||||
|
|
||||||
|
# Internal processing
|
||||||
|
PROCESSING_TOKEN=change-me
|
||||||
|
PROCESSING_JOB_TIMEOUT_SECONDS=10800
|
||||||
|
FFMPEG_BINARY=ffmpeg
|
||||||
|
FFMPEG_TIMEOUT_SECONDS=1800
|
||||||
|
RECORDINGS_ROOT=/data/recordings
|
||||||
|
RECORDING_VIDEO_RETENTION_DAYS=30
|
||||||
|
RECORDING_CLEANUP_INTERVAL_SECONDS=3600
|
||||||
|
AUDIO_STORAGE_DIR=/data/audio
|
||||||
|
AUDIO_ROOT=/data/audio
|
||||||
|
TRANSCRIPTS_STORAGE_DIR=/data/transcripts
|
||||||
|
TRANSCRIPTS_ROOT=/data/transcripts
|
||||||
|
REPORTS_ROOT=/data/reports
|
||||||
|
|
||||||
|
# Whisper
|
||||||
|
WHISPER_ENGINE=faster-whisper
|
||||||
|
WHISPER_MODEL=large-v3
|
||||||
|
WHISPER_DEVICE=cpu
|
||||||
|
WHISPER_COMPUTE_TYPE=int8
|
||||||
|
WHISPER_LANGUAGE=ru
|
||||||
|
WHISPER_DOWNLOAD_ROOT=/models/faster-whisper
|
||||||
|
WHISPER_TIMEOUT_SECONDS=7200
|
||||||
|
|
||||||
|
# Ollama / Gemma
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
OLLAMA_MODEL=gemma3:12b
|
||||||
|
OLLAMA_TIMEOUT_SECONDS=1800
|
||||||
|
OLLAMA_CHUNK_MAX_CHARS=12000
|
||||||
|
|
||||||
|
# Email workflow
|
||||||
|
N8N_WEBHOOK_URL=http://n8n:5678/webhook/meeting-report
|
||||||
|
N8N_WEBHOOK_SECRET=change-me
|
||||||
|
N8N_TIMEOUT_SECONDS=30
|
||||||
|
AUTO_SEND_EMAILS=true
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
.pytest_cache/
|
||||||
|
.mypy_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
.pyre/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
coverage.xml
|
||||||
|
htmlcov/
|
||||||
|
pytest-tmp*/
|
||||||
|
.pytest_tmp/
|
||||||
|
*.egg-info/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# Node / frontend
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.vite/
|
||||||
|
.cache/
|
||||||
|
coverage/
|
||||||
|
*.tsbuildinfo
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Logs and local process files
|
||||||
|
*.log
|
||||||
|
*.pid
|
||||||
|
*.pid.lock
|
||||||
|
.dev-server*.log
|
||||||
|
|
||||||
|
# Environment and secrets
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
.envrc
|
||||||
|
*.local
|
||||||
|
!.env.example
|
||||||
|
!**/.env.example
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
data/recordings/*
|
||||||
|
data/audio/*
|
||||||
|
data/transcripts/*
|
||||||
|
data/reports/*
|
||||||
|
!data/recordings/.gitkeep
|
||||||
|
!data/audio/.gitkeep
|
||||||
|
!data/transcripts/.gitkeep
|
||||||
|
!data/reports/.gitkeep
|
||||||
|
|
||||||
|
# Infrastructure runtime mounts and generated state
|
||||||
|
infrastructure/jitsi/config/
|
||||||
|
infrastructure/jitsi/transcripts/
|
||||||
|
infrastructure/jibri/config/
|
||||||
|
infrastructure/jibri/recordings/
|
||||||
|
infrastructure/worker-mac/logs/
|
||||||
|
infrastructure/ollama-mac/logs/
|
||||||
|
docker-compose.override.yml
|
||||||
|
infrastructure/**/docker-compose.override.yml
|
||||||
|
|
||||||
|
# Local release/archive artifacts
|
||||||
|
meeting-assistant-code-update-*.zip
|
||||||
|
meeting-assistant-code-update-*.zip.sha256
|
||||||
|
|
||||||
|
# OS/editor
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
desktop.ini
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
# Обновление кода на Ubuntu из архива
|
||||||
|
|
||||||
|
Этот архив предназначен для обновления кода проекта `meeting-assistant` поверх уже настроенного сервера.
|
||||||
|
|
||||||
|
Архив не должен заменять серверные секреты, данные и runtime-артефакты:
|
||||||
|
|
||||||
|
- `.env`
|
||||||
|
- `data/`
|
||||||
|
- `backend/.venv/`
|
||||||
|
- `frontend/node_modules/`
|
||||||
|
- `frontend/dist/`
|
||||||
|
- `.git/`
|
||||||
|
- модели Whisper/Gemma/Ollama
|
||||||
|
- данные n8n
|
||||||
|
- записи, аудио, транскрипты и отчёты
|
||||||
|
|
||||||
|
## 1. Перенести архив на сервер
|
||||||
|
|
||||||
|
С Fedora или другой машины:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp meeting-assistant-code-update-*.zip deploy@UBUNTU_SERVER:/tmp/
|
||||||
|
```
|
||||||
|
|
||||||
|
Если пользователь на сервере другой, замени `deploy`.
|
||||||
|
|
||||||
|
## 2. Зайти на сервер
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh deploy@UBUNTU_SERVER
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Сделать резервную копию текущего кода
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo cp -a /opt/ai_agent_bobik /opt/ai_agent_bobik.backup.$(date +%Y%m%d-%H%M%S)
|
||||||
|
```
|
||||||
|
|
||||||
|
Если проект лежит не в `/opt/ai_agent_bobik`, используй свой путь.
|
||||||
|
|
||||||
|
## 4. Распаковать архив во временную папку
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf /tmp/meeting-assistant-update
|
||||||
|
mkdir -p /tmp/meeting-assistant-update
|
||||||
|
unzip /tmp/meeting-assistant-code-update-*.zip -d /tmp/meeting-assistant-update
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Синхронизировать код поверх проекта
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rsync -avh --delete \
|
||||||
|
--exclude='.env' \
|
||||||
|
--exclude='.git/' \
|
||||||
|
--exclude='data/' \
|
||||||
|
--exclude='backend/.venv/' \
|
||||||
|
--exclude='frontend/node_modules/' \
|
||||||
|
--exclude='frontend/dist/' \
|
||||||
|
--exclude='*.log' \
|
||||||
|
/tmp/meeting-assistant-update/ \
|
||||||
|
/opt/ai_agent_bobik/
|
||||||
|
```
|
||||||
|
|
||||||
|
Важно: слэш в конце `/tmp/meeting-assistant-update/` означает “скопировать содержимое папки”.
|
||||||
|
|
||||||
|
## 6. Проверить, что серверные настройки остались
|
||||||
|
|
||||||
|
```bash
|
||||||
|
test -f /opt/ai_agent_bobik/.env && echo ".env на месте"
|
||||||
|
ls -la /opt/ai_agent_bobik/data
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Применить миграции и пересобрать только сервисы приложения
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/ai_agent_bobik
|
||||||
|
docker compose -f infrastructure/docker-compose.yml run --rm migrator
|
||||||
|
docker compose -f infrastructure/docker-compose.yml up -d --build backend frontend worker recording-cleanup
|
||||||
|
```
|
||||||
|
|
||||||
|
Если n8n, Ollama/Gemma, Whisper-модели и FFmpeg уже установлены отдельно, их не переустанавливай. Для n8n на другой машине достаточно, чтобы в серверном `.env` был правильный `N8N_WEBHOOK_URL`.
|
||||||
|
|
||||||
|
## 8. Проверить после обновления
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
curl http://localhost:8000/health/db
|
||||||
|
docker compose -f infrastructure/docker-compose.yml ps
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Если нужно откатиться
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl stop docker
|
||||||
|
sudo rm -rf /opt/ai_agent_bobik
|
||||||
|
sudo cp -a /opt/ai_agent_bobik.backup.YYYYMMDD-HHMMSS /opt/ai_agent_bobik
|
||||||
|
sudo systemctl start docker
|
||||||
|
cd /opt/ai_agent_bobik
|
||||||
|
docker compose -f infrastructure/docker-compose.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Подставь фактическое имя backup-папки.
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
.PHONY: help backend-test backend-lint backend-format-check backend-typecheck backend-alembic-heads backend-seed frontend-lint frontend-format-check frontend-build check
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "meeting-assistant"
|
||||||
|
@echo "Stage 0 scaffold is in progress."
|
||||||
|
@echo ""
|
||||||
|
@echo "Backend:"
|
||||||
|
@echo " cd backend && .venv\\Scripts\\uvicorn app.main:app --reload"
|
||||||
|
@echo " make backend-test"
|
||||||
|
@echo " make backend-lint"
|
||||||
|
@echo " make backend-format-check"
|
||||||
|
@echo " make backend-typecheck"
|
||||||
|
@echo " make backend-alembic-heads"
|
||||||
|
@echo " make backend-seed"
|
||||||
|
@echo ""
|
||||||
|
@echo "Frontend:"
|
||||||
|
@echo " cd frontend && npm install"
|
||||||
|
@echo " cd frontend && npm run dev"
|
||||||
|
@echo " make frontend-build"
|
||||||
|
@echo " make frontend-lint"
|
||||||
|
@echo " make frontend-format-check"
|
||||||
|
@echo ""
|
||||||
|
@echo "All checks:"
|
||||||
|
@echo " make check"
|
||||||
|
@echo ""
|
||||||
|
@echo "Docker:"
|
||||||
|
@echo " docker compose -f infrastructure/docker-compose.yml up --build"
|
||||||
|
|
||||||
|
backend-test:
|
||||||
|
cd backend && .venv\Scripts\python.exe -m pytest
|
||||||
|
|
||||||
|
backend-lint:
|
||||||
|
cd backend && .venv\Scripts\python.exe -m ruff check .
|
||||||
|
|
||||||
|
backend-format-check:
|
||||||
|
cd backend && .venv\Scripts\python.exe -m ruff format --check .
|
||||||
|
|
||||||
|
backend-typecheck:
|
||||||
|
cd backend && .venv\Scripts\python.exe -m mypy
|
||||||
|
|
||||||
|
backend-alembic-heads:
|
||||||
|
cd backend && .venv\Scripts\python.exe -m alembic heads
|
||||||
|
|
||||||
|
backend-seed:
|
||||||
|
cd backend && .venv\Scripts\python.exe -m app.seed
|
||||||
|
|
||||||
|
frontend-lint:
|
||||||
|
cd frontend && npm run lint
|
||||||
|
|
||||||
|
frontend-format-check:
|
||||||
|
cd frontend && npm run format:check
|
||||||
|
|
||||||
|
frontend-build:
|
||||||
|
cd frontend && npm run build
|
||||||
|
|
||||||
|
check: backend-lint backend-format-check backend-typecheck backend-test backend-alembic-heads frontend-lint frontend-format-check frontend-build
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
# meeting-assistant
|
||||||
|
|
||||||
|
Локальная система записи, транскрибации и рассылки итогов встреч.
|
||||||
|
|
||||||
|
Текущий этап: **Этап 3. Авторизация организатора и защищённое создание встречи**.
|
||||||
|
|
||||||
|
## Планируемый стек
|
||||||
|
|
||||||
|
- Backend: FastAPI, SQLAlchemy 2, Alembic, PostgreSQL, Redis, RQ
|
||||||
|
- Frontend: React, TypeScript, Vite
|
||||||
|
- Встречи и запись: Jitsi Meet, Jibri
|
||||||
|
- Локальный AI: faster-whisper/MLX Whisper, Ollama/Gemma
|
||||||
|
- Рассылка: n8n/SMTP
|
||||||
|
|
||||||
|
## Структура
|
||||||
|
|
||||||
|
```text
|
||||||
|
backend/
|
||||||
|
frontend/
|
||||||
|
infrastructure/
|
||||||
|
data/
|
||||||
|
recordings/
|
||||||
|
audio/
|
||||||
|
transcripts/
|
||||||
|
reports/
|
||||||
|
docs/
|
||||||
|
```
|
||||||
|
|
||||||
|
## PostgreSQL
|
||||||
|
|
||||||
|
PostgreSQL теперь является частью проекта. При Docker-развёртывании сервис `postgres` создаёт пустую базу, `migrator` применяет Alembic-миграции, затем `seeder` добавляет начальные справочники до запуска backend.
|
||||||
|
|
||||||
|
Backend берёт подключение из `DATABASE_URL`:
|
||||||
|
|
||||||
|
```env
|
||||||
|
DATABASE_URL=postgresql+psycopg://meeting:password@postgres:5432/meeting_assistant
|
||||||
|
```
|
||||||
|
|
||||||
|
Схема создаётся первой миграцией `backend/alembic/versions/20260714_0001_initial_schema.py` и включает таблицы из ТЗ:
|
||||||
|
|
||||||
|
- `departments`
|
||||||
|
- `department_recipients`
|
||||||
|
- `meeting_types`
|
||||||
|
- `meetings`
|
||||||
|
- `meeting_recipients`
|
||||||
|
- `processing_events`
|
||||||
|
- `users`
|
||||||
|
|
||||||
|
Начальные данные добавляются модулем `backend/app/seed.py`:
|
||||||
|
|
||||||
|
- отделы: `ksb`, `sales`, `marketing`, `ved`, `trade-operations`
|
||||||
|
- служебный тип встречи: `default`
|
||||||
|
- получатели отделов: `ksb@osk-group.ru`, `rop@osk-group.ru`, `marketing3@osk-group.ru`,
|
||||||
|
`Ved2@osk-group.ru`, `Assistved2@osk-group.ru`, `bai@osk-group.ru`
|
||||||
|
|
||||||
|
## Backend
|
||||||
|
|
||||||
|
Backend пока содержит минимальное FastAPI-приложение с endpoint:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /health
|
||||||
|
GET /health/db
|
||||||
|
POST /api/auth/login
|
||||||
|
GET /api/auth/me
|
||||||
|
GET /api/departments
|
||||||
|
GET /api/departments/{id}/recipients
|
||||||
|
GET /api/meeting-types
|
||||||
|
POST /api/meetings
|
||||||
|
GET /api/meetings/{id}
|
||||||
|
GET /api/meetings/{id}/status
|
||||||
|
POST /api/meetings/{id}/recording/request-start
|
||||||
|
POST /api/meetings/{id}/recording/confirmed
|
||||||
|
POST /api/meetings/{id}/recording/stopped
|
||||||
|
GET /api/meetings/{id}/preview
|
||||||
|
PUT /api/meetings/{id}/preview
|
||||||
|
POST /api/meetings/{id}/send
|
||||||
|
POST /api/internal/recordings/finalized
|
||||||
|
POST /api/internal/email-delivery
|
||||||
|
```
|
||||||
|
|
||||||
|
Пример создания встречи:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"department_id": 1,
|
||||||
|
"meeting_type_id": 1,
|
||||||
|
"title": "КСБ",
|
||||||
|
"organizer_email": "organizer@example.local"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`POST /api/meetings` создаёт уникальный `room_name` и сохраняет снимок активных получателей отдела в `meeting_recipients`.
|
||||||
|
`GET /api/meetings/{id}` возвращает карточку встречи со статусом, room name и сохранёнными получателями.
|
||||||
|
`GET /api/meetings/{id}/status` возвращает компактный статус обработки: `status`, `progress`, ошибки и пути к артефактам.
|
||||||
|
Recording endpoints фиксируют контур серверной записи: `created -> recording_starting -> recording -> recording_finalizing`.
|
||||||
|
Internal endpoint для Jibri переводит встречу в `recorded` и сохраняет путь к файлу записи:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:8000/api/internal/recordings/finalized \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "X-Internal-Token: change-me" \
|
||||||
|
-d "{\"meeting_id\":\"<uuid>\",\"recording_path\":\"/data/recordings/example.mp4\"}"
|
||||||
|
```
|
||||||
|
|
||||||
|
Готовый пример Jibri finalize-скрипта находится в `infrastructure/jibri/finalize.sh`. Его нужно подключить на стороне Jibri вместе с переменными `BACKEND_INTERNAL_URL`, `PROCESSING_TOKEN` и `RECORDING_PATH`. `MEETING_ID` можно передать явно, но для реального Jibri-callback достаточно `ROOM_NAME`, metadata записи или пути записи, из которого скрипт выведет `room_name`. Backend принимает только пути внутри `RECORDINGS_ROOT`.
|
||||||
|
|
||||||
|
Processing worker после статуса `recorded` извлекает через FFmpeg mono PCM WAV 16 kHz, запускает настроенный Whisper engine и сохраняет два артефакта:
|
||||||
|
|
||||||
|
- `transcript_path` - `transcript.txt` с полным текстом;
|
||||||
|
- `transcript_json_path` - `transcript.json` со структурой `{ "full_text": "...", "segments": [{ "start": 0.0, "end": 1.5, "text": "..." }] }`.
|
||||||
|
|
||||||
|
Исходный файл Jibri используется только как временный источник аудиодорожки. В письма и n8n payload путь к видео не передаётся; рассылка содержит протокол и, если разрешено получателю, стенограмму. Отдельный cleanup-процесс удаляет исходные видео старше `RECORDING_VIDEO_RETENTION_DAYS` дней, по умолчанию 30, и очищает `meetings.recording_path`. В Docker Compose это сервис `recording-cleanup`; вручную его можно запустить так:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
.venv\Scripts\python -m app.recording_cleanup
|
||||||
|
```
|
||||||
|
|
||||||
|
Для Mac Studio основной режим - `mlx-whisper` на Apple Silicon; `faster-whisper` остаётся fallback для CPU/Linux/NVIDIA. FFmpeg нужно ставить там же, рядом с RQ worker-ом. Инструкция: `infrastructure/worker-mac/README.md`.
|
||||||
|
|
||||||
|
Ollama/Gemma поднимается сервисом `ollama` внутри Docker Compose без публикации порта наружу. Worker обращается к нему по внутреннему адресу `http://ollama:11434`. После первого запуска нужно загрузить модель:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd infrastructure
|
||||||
|
docker compose exec ollama ollama pull gemma3:12b
|
||||||
|
```
|
||||||
|
|
||||||
|
Модель выбирается через `OLLAMA_MODEL`, максимальный размер части стенограммы для chunking - через `OLLAMA_CHUNK_MAX_CHARS`.
|
||||||
|
|
||||||
|
Если Gemma/Ollama нужно вынести на Mac Studio, готовый full deploy находится в `infrastructure/ollama-mac`. Там есть launchd-сервис, загрузка модели, health-check и инструкция, как связать Mac Ollama с processing worker.
|
||||||
|
|
||||||
|
Рассылка выполняется через n8n, а не через локальный SMTP-скрипт. По умолчанию `AUTO_SEND_EMAILS=true`, поэтому после подготовки протокола встреча с `auto_send=true` автоматически переводится в `sending` и отправляет `POST` на `N8N_WEBHOOK_URL` с заголовками `X-N8N-Webhook-Secret` и `X-Idempotency-Key`. Payload содержит раздельные группы `to`/`cc`/`bcc` и массив `deliveries`; в каждой delivery уже лежат только те материалы, которые разрешены конкретному получателю. n8n после фактической доставки должен вызвать `POST /api/internal/email-delivery` с тем же `X-N8N-Webhook-Secret`, чтобы backend обновил `meeting_recipients.delivery_status` и перевёл встречу в `completed` или `failed`. Endpoint `POST /api/meetings/{id}/send` остаётся для ручного повторного запуска/административных сценариев.
|
||||||
|
|
||||||
|
`POST /api/meetings` требует Bearer token. Email организатора берётся из авторизованного пользователя, а не из формы.
|
||||||
|
|
||||||
|
Начальный пользователь создаётся seed-скриптом из переменных:
|
||||||
|
|
||||||
|
```env
|
||||||
|
INITIAL_ADMIN_EMAIL=admin@example.local
|
||||||
|
INITIAL_ADMIN_PASSWORD=change-me-admin
|
||||||
|
INITIAL_ADMIN_NAME=Администратор
|
||||||
|
```
|
||||||
|
|
||||||
|
Локальный запуск после установки зависимостей:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python -m venv .venv
|
||||||
|
.venv\Scripts\pip install -r requirements-dev.txt
|
||||||
|
.venv\Scripts\uvicorn app.main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверка:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
.venv\Scripts\python -m ruff check .
|
||||||
|
.venv\Scripts\python -m ruff format --check .
|
||||||
|
.venv\Scripts\python -m mypy
|
||||||
|
.venv\Scripts\pytest
|
||||||
|
```
|
||||||
|
|
||||||
|
Docker-запуск PostgreSQL + миграции + backend + frontend + Redis:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
copy .env.example .env
|
||||||
|
docker compose -f infrastructure/docker-compose.yml up --build
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверка:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
curl http://localhost:8000/health/db
|
||||||
|
```
|
||||||
|
|
||||||
|
`GET /health/db` выполняет короткий `SELECT 1`. Если PostgreSQL недоступна, endpoint вернёт `503`.
|
||||||
|
|
||||||
|
Alembic находится в `backend/alembic`. Конфигурация берёт URL из `DATABASE_URL` через `backend/alembic/env.py`.
|
||||||
|
|
||||||
|
Создание новой ревизии, когда модели уже описаны:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
.venv\Scripts\python -m alembic revision --autogenerate -m "describe change"
|
||||||
|
```
|
||||||
|
|
||||||
|
Ручное применение миграций:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
.venv\Scripts\python -m alembic upgrade head
|
||||||
|
```
|
||||||
|
|
||||||
|
Ручное заполнение начальных справочников:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
.venv\Scripts\python -m app.seed
|
||||||
|
```
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
|
||||||
|
Frontend содержит React + TypeScript + Vite экран подготовки встречи. Он читает справочники из backend:
|
||||||
|
|
||||||
|
- вход организатора: `POST /api/auth/login`
|
||||||
|
- отделы: `GET /api/departments`
|
||||||
|
- получатели выбранного отдела: `GET /api/departments/{id}/recipients`
|
||||||
|
- типы встреч: `GET /api/meeting-types`
|
||||||
|
- создание встречи: `POST /api/meetings`
|
||||||
|
|
||||||
|
После создания встречи frontend показывает `room_name` и ссылку на корпоративный Jitsi из `VITE_JITSI_BASE_URL`. Авторизация в Jitsi остаётся на стороне корпоративной Jitsi-инфраструктуры.
|
||||||
|
|
||||||
|
Локальный запуск после установки зависимостей:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверка сборки:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm run lint
|
||||||
|
npm run format:check
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Единая проверка этапа
|
||||||
|
|
||||||
|
Если доступен `make`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make check
|
||||||
|
```
|
||||||
|
|
||||||
|
Те же проверки вручную:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
.venv\Scripts\python -m ruff check .
|
||||||
|
.venv\Scripts\python -m ruff format --check .
|
||||||
|
.venv\Scripts\python -m mypy
|
||||||
|
.venv\Scripts\python -m pytest
|
||||||
|
|
||||||
|
cd ..\frontend
|
||||||
|
npm run lint
|
||||||
|
npm run format:check
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Правило разработки
|
||||||
|
|
||||||
|
Работа идёт строго по этапам. Следующий этап не начинается, пока текущий не запускается, не проверен и не соответствует критериям приёмки.
|
||||||
Reference in New Issue
Block a user