evening_detective_server
Шалон для Go сервисов (имя репо должно быть snake case) Методы http должны быть с префиксом /api
Инициализация
make generate
go mod tidy
docker compose -f docker-compose-db.yml up -d
cp .env.example .env
mkdir migrations
Запуск
make run
Сборка
make build-builder
make build-linux
По умолчанию используется архитектура Docker-среды. Для другой архитектуры укажите, например, make build-linux GOARCH=arm64 или make build-linux GOARCH=amd64.
Миграции
goose -dir ./migrations create {migration name} sql
goose -dir ./migrations postgres "user=postgres password=postgres host=localhost dbname=evening_detective_server sslmode=disable" up
Тестирование
make test
PDF с QR-кодами команд
Кнопка «QR команд» на странице управления игрой скачивает GET /api/games/{id}/teams/qr.pdf с авторизацией организатора, автора или администратора. Без команд кнопка скрыта; прямой запрос для пустой игры возвращает FailedPrecondition.
Модуль internal/modules/team_qr_pdf формирует A4 в книжной ориентации, 12 карточек (3 × 4) с названиями команд и пунктирными линиями для разрезания. Имя файла: YYYY-MM-DD_Название игры.pdf, дата берётся из games.start_at. Недопустимые символы имени файла заменяются на _.
Для рабочих ссылок задайте APP_BASE_URL — тот же публичный адрес приложения, который используется существующими QR-кодами фронтенда (VITE_API_URL). Пустой или некорректный адрес приводит к ошибке скачивания. PDF не сохраняется в хранилище и отдаётся с Cache-Control: no-store.
Шрифт DejaVu Sans Condensed встроен в бинарник вместе с лицензией; системные шрифты не нужны. Поддерживается кириллица, длинные названия переносятся и уменьшаются до размера 6 pt. Символы вне BMP (например, emoji) вызывают явную ошибку генерации из-за ограничения PDF-библиотеки.
Закрывашка сценария
Автор (или администратор) сохраняет закрывашку через PUT /api/scenarios/{id}/conclusion:
{"conclusion":{"text":"Разгадка дела","video":"ending_abc.mp4"}}
Видео сначала загружается через POST /api/files/upload (MP4/WebM, до 64 МБ); в video передаётся возвращённое имя файла. Текст и видео можно задавать отдельно. {"conclusion":null} удаляет закрывашку. Она возвращается в story.conclusion полного сценария, но не передаётся в историю игроков, включая MCP. Закрывашка переносится вместе с ZIP-архивом; действуют общие лимиты импорта архива (32 МБ на архив и отдельный файл).
Документация и юридические документы
docs/TERMS.md— Пользовательское соглашение (оферта); раздаётся сервером по постоянному URL/api/terms;docs/PRIVACY.md— Политика конфиденциальности и обработки персональных данных (152-ФЗ); раздаётся сервером по постоянному URL/api/privacy;docs/CONSENT.md— текст согласия на обработку ПДн для формы регистрации (URL/api/consent);docs/COMPLIANCE.md— чек-лист приведения сервиса в соответствие с документами.
Юридические эндпоинты:
POST /api/auth/signup— регистрация; требуетaccept_terms: trueиaccept_privacy: true(факт акцепта фиксируется в таблицеuser_agreements);DELETE /api/auth/delete-account— удаление учётной записи и персональных данных (авторизован JWT, подтверждение паролем в HTTP-заголовкеX-Password).
Агент «Юрист по ПО» (DSH)
В каталоге agents/software-lawyer лежит агент-пресет для DeepSeek Harness: специализированный консультант по правовым вопросам разработки ПО (лицензии, авторские права, персональные данные 152-ФЗ/GDPR, договоры). Отвечает на основе встроенной базы знаний (skills/software-law/references/), без внешних API.
Установка (копирует пресет в ~/.dsh/.agent-presets/software-lawyer):
./agents/software-lawyer/install.sh
После установки пресет «Юрист по ПО» появится в списке агентов при создании новой сессии в веб-интерфейсе DSH. Повторная установка с перезаписью: ./agents/software-lawyer/install.sh --force.
Структура:
agent.cordis.yml— композиция агента (полный набор инструментов, как у пресетаstandard, + персона юриста и скилл-база);preset.yml— отображаемое имя и описание;skills/software-law/— база знаний:SKILL.md(правила консультаций) иreferences/(лицензии, авторские права, ПДн, договоры).
MCP-сервер (встроен в основной сервис)
MCP-сервер (Model Context Protocol) встроен в основной бинарь и доступен как HTTP-эндпоинт /api/mcp (streamable HTTP) на REST-gateway — чтобы LLM-клиент (Claude Desktop, IDE с MCP-поддержкой и т.п.) мог играть в «Вечерний детектив». Инструменты вызывают игровые сервисы напрямую, отдельный процесс не нужен.
Ходы через make_move сохраняются с actions.via_mcp = true; через REST/gRPC — с false. Отметку задаёт сервер, клиент её не передаёт. У старых ходов значение false: их источник не отслеживался. Это отметка канала MCP, а не гарантия того, кто фактически играет.
Инструменты:
| Инструмент | Назначение |
|---|---|
connect |
Подключиться к игре по ссылке /team-story/{id}?password=...; возвращает id команды, пароль и текущую историю |
get_team_story |
История команды: точки, двери, улики, вопросы дела + инфо об игре (по паролю команды, без авторизации) |
make_move |
Ход команды в точку по её коду; возвращает обновлённую историю (по паролю команды, без авторизации) |
submit_answers |
Ответы команды на вопросы дела (массив {question_code, answer}); возвращает обновлённую историю (по паролю команды, без авторизации) |
Ссылку на игру (/team-story/{id}?password=...) выдаёт команде организатор личным каналом — например, вместе с паролем. Принимаются относительные и абсолютные ссылки (в т.ч. с любым хостом): HTTP-запросы по ним не выполняются, из ссылки берутся только id команды и пароль. Игроку авторизация не нужна: команда идентифицируется паролем из ссылки.
Запуск — обычный запуск основного сервиса:
make run
MCP-эндпоинт: http://localhost:8090/api/mcp. ВНИМАНИЕ: REST-gateway слушает :8090 (gRPC — :8080), а docker-compose.yml публикует наружу только 8080 — для доступа к /api/mcp извне нужна публикация порта 8090 в compose либо проксирование пути /api/mcp через reverse-proxy (nginx/caddy). Эндпоинт публичный (как и REST /api/teams/{id}/story); секрет — пароль команды.
Подключение к MCP-клиенту (пример для Claude Desktop / аналогов):
{
"mcpServers": {
"evening-detective": {
"type": "http",
"url": "http://localhost:8090/api/mcp"
}
}
}