14 KiB
Тикеты реализации «Контракт-чек» (production refactor)
Актуальная архитектура:
ARCHITECTURE.md(supersedesIMPLEMENTATION_PLAN.mdдля этапов 1+). Состояние кода на момент синхронизации: реализованыapi/(вкл. B2B-роуты),core/,worker_extract/,worker_analyze/,bot/,prototype/; все 5 Dockerfile-ов вsrv/;docker-compose.ymlполностью разводит профильservices; миграции0001_initial+0002_api_keys; unit-тесты зелёные. DoD:ruff check .,mypy src,pytestзелёные;.env.exampleактуален.Статусы:
todo/in_progress/done/blocked.
Аудит реализации (текущее состояние)
Проверено: код собирается (
pyproject.toml+uv.lock), миграции накатываются,api/стартует, unit-тесты проходят (58 тестов зелёные).
| Компонент | Статус | Доказательство / пробел |
|---|---|---|
| Stage 0 prototype | done | src/contract_check/prototype/ работает; tests/unit/test_checklist_report.py, test_chunker.py, test_extractor.py зелёные. |
core/ — общий домен |
done | db/, mq/, s3/, llm/, analysis/, credits.py, tokens.py, api_keys.py, rate_limit.py, redis_client.py, config.py, logging.py, metrics.py, telemetry.py, sentry.py. |
| Миграции / БД | done | 0001_initial.py (6 таблиц) + 0002_api_keys.py (api_keys, api_key_requests). |
api/ — FastAPI ядро |
done | POST /api/v1/documents, GET /api/v1/reports/{id}, GET /api/v1/documents/{id}, GET /api/v1/me, /healthz, /readyz, /metrics; user JWT auth via /api/v1/auth/telegram/*; reserve-on-enqueue (services.py). |
worker_extract/ |
done | consumer.py/handler.py/extract_document.py/__main__.py: consume DocumentUploaded → MinIO dl → extract/OCR → .txt upload → publish DocumentExtracted; failure-class + refund. |
worker_analyze/ |
done | consumer.py/handler.py/__main__.py: consume DocumentExtracted → LLM → Report → status=done; refund-on-DLQ по политике. |
bot/ — Telegram adapter |
done | client.py/config.py/handlers.py/__main__.py: /start, upload→POST /documents, poll→deliver; граница импортов проверяется tests/unit/test_bot_boundary.py. |
| Dockerfile-ы | done | srv/{api,worker-extract,worker-analyze,bot,prototype}/Dockerfile — все 5 (deps-группы PEP 735 заточены на сервис). |
| Docker Compose | done | Инфра (default) + профиль services (api, worker-extract, worker-analyze, bot) с depends_on: service_healthy. Профили obs/edge — позже. |
| Observability / edge | todo | Пром/Grafana/Tempo/OTel-collector/Nginx/certbot — не развёрнуты (нет deploy/). |
| Stage 2 — веб + подписки | todo | React SPA, Telegram Login, recurring ЮKassa — не начаты. |
| Stage 3 — B2B API | done | api/routes/b2b.py, core/api_keys.py, core/rate_limit.py, core/redis_client.py, миграция 0002_api_keys.py, tests/integration/test_b2b_api.py, tests/unit/test_rate_limit.py; X-API-Key auth + token-bucket rate-limit. |
Этап 0 — Прототип (go/no-go)
T-E0-001 — Аккаунт Ollama Cloud + каркас прототипа
Статус: done · Оценка: S
.env.example содержит OLLAMA_HOST/OLLAMA_API_KEY/OLLAMA_MODEL=qwen2.5:14b/OLLAMA_FALLBACK_MODEL=qwen2.5:7b.
python -m contract_check --help работает. Теги без -instruct.
T-E0-002 — Экстрактор текста (PDF/DOCX)
Статус: done · Оценка: S
src/contract_check/core/analysis/extractor.py; покрыт tests/unit/test_extractor.py.
T-E0-003 — Чек-лист анализа (v1)
Статус: done · Оценка: S
src/contract_check/core/analysis/checklist.py — 10 пунктов с id/title/description.
T-E0-004 — Ollama Cloud-клиент + repair-loop
Статус: done · Оценка: M
src/contract_check/core/llm/ollama_cloud.py; мок-тесты 200/429-fallback/битый-JSON в tests/unit/test_llm_ollama_cloud.py.
T-E0-005 — Промпт + JSON-отчёт (с чанками)
Статус: done · Оценка: M
core/analysis/analyzer.py, chunker.py, report_schema.py; disclaimer в markdown.
T-E0-006 — Замеры метрик и economics go/no-go
Статус: todo · Оценка: M
Требует живых прогонов 3–5 договоров через Ollama Cloud + docs/stage0-results.md.
Этап 1 — Production refactor (api + core + workers + bot)
Архитектура: hexagonal, RabbitMQ pipeline (
extract.q→analyze.q), MinIO, Postgres, Redis. Профили Docker Compose: default = инфра;services= api + workers + bot.
T-E1-001 — Ядро contract_check.core
Статус: done · Оценка: L
Пакет src/contract_check/core/ содержит db/, mq/, s3/, llm/, analysis/, credits.py, tokens.py, config.py, logging.py, metrics.py, telemetry.py, sentry.py.
T-E1-002 — Миграции БД (6 таблиц)
Статус: done · Оценка: M
migrations/versions/0001_initial.py: users, documents, reports, jobs, service_tokens, invoices (stub).
T-E1-003 — FastAPI ядро: документы, кредиты, enqueue, отчёты
Статус: done · Оценка: L
src/contract_check/api/: POST /api/v1/documents, GET /api/v1/reports/{id}, GET /api/v1/me, /healthz, /metrics.
Reserve-on-enqueue (core/credits.py) и user JWT auth (core/auth.py, api/routes/auth.py).
T-E1-004 — Worker-extract (CPU: pymupdf + tesseract)
Статус: done · Оценка: M · Зависимости: T-E1-001, T-E1-002
src/contract_check/worker_extract/ (consumer.py/handler.py/extract_document.py/__main__.py):
consume DocumentUploaded из extract.q → скачать blob из MinIO →
extractor + ocr.ocr_pdf() → загрузить .txt → publish DocumentExtracted в analyze.q.
Failure-classification + refund-on-DLQ. Образ srv/worker-extract/Dockerfile.
T-E1-005 — Worker-analyze (I/O: LLM provider)
Статус: done · Оценка: M · Зависимости: T-E1-001, T-E1-002, T-E1-004
src/contract_check/worker_analyze/ (consumer.py/handler.py/__main__.py):
consume DocumentExtracted из analyze.q → скачать .txt → chunk → LLM (через core/llm port)
→ validate/repair → сохранить Report, status=done; refund при terminal failure (core/credits.py).
Образ srv/worker-analyze/Dockerfile.
T-E1-006 — Telegram-бот (aiogram 3) — HTTP-адаптер
Статус: done · Оценка: M · Зависимости: T-E1-003
src/contract_check/bot/ (client.py/config.py/handlers.py/__main__.py):
/start, приём PDF/DOCX → POST /api/v1/documents, poll GET /api/v1/reports/{id}
→ отправка отчёта (разбивка/файл >4096 симв.), реакция на 402/400/202.
Образ srv/bot/Dockerfile. Не импортирует core.db/core.s3/core.llm/core.mq/core.credits
(проверяется tests/unit/test_bot_boundary.py).
T-E1-007 — Docker Compose: сервисы и профили
Статус: done · Оценка: M · Зависимости: T-E1-004, T-E1-005, T-E1-006
docker-compose.yml: default-профиль = инфра (postgres, redis, rabbitmq, minio, minio-init);
профиль services = api, worker-extract, worker-analyze, bot с depends_on: service_healthy.
Все 5 Dockerfile-ов в srv/. Профили obs/edge — позже (T-E1-009/T-E1-010).
T-E1-008 — Оплата (ЮKassa) и пополнение кредитов
Статус: todo · Оценка: M · Зависимости: T-E1-003, T-E1-006
Роут для создания платежа 199 ₽ = 1 документ; webhook succeeded → credits_left += 1.
T-E1-009 — Деплой + edge (Nginx/certbot)
Статус: done · Оценка: M · Зависимости: T-E1-007
deploy/nginx/templates/contract-check.conf.template, deploy/nginx/certbot-init.sh, DEPLOY.md §13, docker-compose.yml профиль edge.
T-E1-010 — Мониторинг (Prometheus/Grafana/Tempo/Sentry)
Статус: todo · Оценка: M · Зависимости: T-E1-007
deploy/observability/ + compose профиль obs. Дашборды: queue depth, job latency, LLM tokens, credits.
Этап 2 — Веб + подписки
T-E2-001 — Миграция БД: планы и счета
Статус: todo · Оценка: M · Зависимости: T-E1-002
users.plan (free|solo|team), users.plan_renews_at. Таблица invoices уже существует (stub); наполнить логикой.
T-E2-002 — Telegram Login Widget auth
Статус: done · Оценка: M · Зависимости: T-E1-003
Реализовано в core/auth.py + api/routes/auth.py: /api/v1/auth/telegram/web и /api/v1/auth/telegram/miniapp проверяют HMAC-подпись Telegram и выдают тот же user JWT, что и бот.
T-E2-003 — React SPA (Vite)
Статус: todo · Оценка: L · Зависимости: T-E2-002
Загрузка, история, профиль, подписка. Сборка в статику; api отдаёт index.html на /.
T-E2-004 — Подписки ЮKassa recurring
Статус: todo · Оценка: M · Зависимости: T-E2-001, T-E2-003
Тарифы solo (1 490 ₽), team (3 990 ₽). Ежемесячное продление/reset.
Этап 3 — B2B API
Примечание: в текущей архитектуре B2B API строится не после веба, а поверх уже готового
apiи существующей очереди. Зависимость от T-E2-002 снята.
T-E3-001 — Миграция БД: api_keys и api_key_requests
Статус: done · Оценка: M · Зависимости: T-E1-002
migrations/versions/0002_api_keys.py: таблицы
api_keys(id, user_id FK, name, key_hash, rate_limit_rps, monthly_quota, monthly_used, resets_at, revoked, created_at, last_used_at)api_key_requests(id, api_key_id FK, document_id FK, created_at)Накатывается/откатывается чисто; SQLAlchemy-модели вcore/db/models.py.
T-E3-002 — Redis-клиент и token-bucket rate limiter
Статус: done · Оценка: M · Зависимости: T-E3-001
core/redis_client.py (async Redis из redis_url), core/rate_limit.py (token bucket per api_key_id,
с MemoryRateLimiter-фолбэком для unit-тестов без Redis). Лимит по умолчанию = B2B_DEFAULT_RATE_LIMIT_RPS (3),
переопределяется api_keys.rate_limit_rps. Покрыт tests/unit/test_rate_limit.py; 429 при превышении.
T-E3-003 — X-API-Key auth dependency
Статус: done · Оценка: M · Зависимости: T-E3-001, T-E3-002
api/deps.py: require_api_key — проверяет X-API-Key по key_hash (core/api_keys.py),
отклоняет revoked, обновляет last_used_at, применяет rate-limit. api/routes/b2b.py:
POST /api/v1/analyze, GET /api/v1/b2b/reports/{document_id}, GET /api/v1/b2b/usage.
Покрыт tests/integration/test_b2b_api.py (вкл. 401/429).
T-E3-004 — Управление API-ключами (user JWT auth)
Статус: done · Оценка: S · Зависимости: T-E3-001
api/routes/b2b.py под user JWT auth: POST /api/v1/b2b/keys (plaintext ключ возвращается
только один раз), GET /api/v1/b2b/keys, POST /api/v1/b2b/keys/{id}/revoke,
GET /api/v1/b2b/keys/{id}/usage. Revoke мгновенно отключает аутентификацию.
T-E3-005 — Интеграционные тесты B2B API
Статус: done · Оценка: M · Зависимости: T-E3-003
tests/integration/test_b2b_api.py: upload → 202 → poll report; ветки 401/429.
Seed API key в tests/integration/conftest.py.
Сводка порядка (обновлённая)
- E0 — прототип (done, кроме живых замеров T-E0-006).
- E1.001–007 — ядро + БД + FastAPI
api+ worker-extract + worker-analyze + bot + Docker/compose (done). - E3 — B2B API (done: миграция, rate-limit, auth, роуты, тесты).
- E1.008 — оплата ЮKassa (todo — блокирует первых платящих).
- E1.009–010 — деплой/edge (Nginx/certbot) и observability (Prometheus/Grafana/Tempo/Sentry) (todo).
- E2 — веб + подписки (todo; после 10–50 платящих).
Ближайшие работы: E1.008 (оплата), затем E1.009–010 (edge + observability), затем E2 (веб + подписки).