# Архитектура Contracts App ## Обзор Сервис **Сверка договоров** — автоматизированная обработка договоров и допников (docx/pdf) с извлечением структурированных данных, отслеживанием изменений и восстановлением истории договора во времени. ## Принципы 1. **НЕ МОНОЛИТ** — каждый слой независим, отдельный файл, своя зона ответственности 2. **Данные не покидают облако** — всё в PostgreSQL внутри кластера 3. **Ничего не терять** — парсер отдаёт полный слепок документа, LLM решает что важно 4. **Исключения — не фантазировать** — нерешаемые подзадачи отмечать явно --- ## Слои приложения ``` ┌─────────────────────────────────────────────┐ │ app.py │ │ ContractsApp (сборка) │ ├──────────┬──────────┬──────────┬────────────┤ │ db.py │ parser.py│ test_ │ (будущие) │ │ (БД) │ (парсинг)│ routes.py │ llm.py │ │ │ │ (/test) │ upload.py│ └──────────┴──────────┴──────────┴────────────┘ ``` | Слой | Файл | Что делает | Статус | |---|---|---|---| | Ядро | `app.py` | Flask-приложение, инициализация, регистрация Blueprint | ✅ | | БД | `db.py` | `connect()`, `query()`, `_pg_connect()` | ✅ | | Тесты | `test_routes.py` | Blueprint `/test` — мост к БД извне | ✅ | | Парсер | `parser.py` | `parse(bytes, mime) → elements` для docx/pdf/doc/zip | ✅ | | LLM | `llm.py` | Нормализация строк через aillm.ru (120B) | ⬜ | | Загрузка | `upload.py` | Приём файлов, сохранение в БД | ⬜ | --- ## Поток обработки документа ``` Пользователь │ ▼ POST /upload (файл .docx/.pdf/.doc/.zip) │ ▼ upload.py: сохранить в contract_docs (original_bytes) │ ▼ parser.py: parse(bytes, mime) → elements JSON │ ▼ db.py: сохранить parsed_json в contract_docs │ ▼ llm.py: отправить elements → LLM → нормализованные spec_rows │ ▼ db.py: сохранить в spec_rows, сравнить с предыдущими → spec_history │ ▼ GET /contract/{id}/history → полная история изменений ``` --- ## Схема БД (план) ``` contract_docs — исходные файлы + сырой парсинг id UUID PK contract_id → contracts.id filename TEXT mime_type TEXT original_bytes BYTEA ← сам файл parsed_json JSONB ← выдача parser.py created_at TIMESTAMPTZ contracts — договоры id UUID PK number TEXT ← номер договора client TEXT ← клиент date DATE status TEXT supplements — допники id UUID PK contract_id → contracts.id number TEXT date DATE type TEXT ← новый / изменение / расторжение doc_id → contract_docs.id spec_rows — строки спецификаций id UUID PK supplement_id → supplements.id row_num INT name TEXT ← наименование услуги price NUMERIC qty NUMERIC sum NUMERIC date_start DATE date_end DATE spec_history — история изменений id UUID PK spec_row_id → spec_rows.id supplement_id → supplements.id change_type TEXT ← added / changed / deleted / unchanged old_values JSONB new_values JSONB ``` --- ## API эндпоинты | Метод | Путь | Слой | Что | |---|---|---|---| | GET | `/` | app.py | Главная (HTML) | | GET | `/health` | app.py | Health check → "OK" | | GET | `/test` | test_routes | Статус БД + список команд | | POST | `/test` `{"action":"status"}` | test_routes | Статус БД | | POST | `/test` `{"action":"createdb"}` | test_routes | Создать БД contracts | | POST | `/test` `{"action":"tables"}` | test_routes | Список таблиц | | POST | `/test` `{"action":"sql","sql":"..."}` | test_routes | Произвольный SQL | --- ## Технологии | Компонент | Выбор | |---|---| | Язык | Python 3.12 | | Фреймворк | Flask | | БД | PostgreSQL (внутрикластерный) | | Парсинг docx | python-docx | | Парсинг .doc | LibreOffice (headless) | | Парсинг PDF | pdfplumber | | LLM | aillm.ru API (120B модель) | | Деплой | pythonk8s.services.ngcloud.ru | | Репозиторий | gitea.services.ngcloud.ru/Nail/contracts-app.git | --- ## Конфигурация (переменные окружения) | Переменная | Назначение | |---|---| | `DB_HOST` | Хост PostgreSQL | | `DB_PORT` | Порт (5432) | | `DB_NAME` | Имя БД (contracts) | | `DB_USER` | Пользователь | | `DB_PASS` | Пароль | | `DB_SSLMODE` | SSL mode (disable) | | `LLM_API_KEY` | Ключ aillm.ru (будет) | | `LLM_API_URL` | URL LLM API (будет) |