DFiP_Budget_planing/ARCHITECTURE.md
Andrey Epifancev 5190e5ef13 docs: описать проект в CLAUDE.md и ARCHITECTURE.md
Домен, стек, слои, команды, тесты, базовая ветка test.
.claude/code-paths: api/src/, api/alembic/, web/src/.

Refs #198

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 20:24:22 +04:00

43 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Архитектура
Монорепозиторий: `api/` (FastAPI) отдаёт REST, WebSocket и собранный фронт; `web/` — SPA на React. Основная бизнес-логика — PL/pgSQL-функции схемы `v3` в Postgres. Python-слой проверяет роли, валидирует запрос, вызывает функцию и маппит её ошибки.
Поток редактирования ячейки: `RealtimeTable` → WebSocket `/api/v1/ws/form/{id}/sheet/{sheet}` (`cell_edit_start` — блокировка, `cell_updated`) → `SheetService` → `v3.upd_form_cell(s)`. Функция проверяет роль и окно этапа и пишет аудит `v3.log_event`, после чего изменение рассылается остальным подключённым.
## Модули
| Модуль | Ответственность | Зависит от |
|---|---|---|
| `api/src/api/v1/` | Роутеры: auth, users, admin, audit, forms, projects, form_phases (`/stages`), phase_template, export, websocket, org_unit, vsp (`/dict/info`), expense_item, summary (`/svod`) | services, deps |
| `api/src/api/v1/deps.py` | Текущий пользователь из JWT, гарды ролей | repository.user_repository, core.security |
| `api/src/api/v1/websocket.py` | ConnectionManager, блокировки ячеек в памяти, события форм и FORM_4/проектов, синхронизация сателлитов AHR | services |
| `api/src/services/` | Сервисы по сущностям, контроль доступа (`access_control_service.py`) | repository |
| `api/src/services/export_service/` | Фоновые выгрузки в Excel: ProcessPool, таблица `export_job`, файлы в `tmp/exports`, маппинг колонок `export_mappings.py` | repository, openpyxl/XlsxWriter |
| `api/src/repository/` | SQLAlchemy-запросы и вызовы SQL-функций `v3.*`, `SET LOCAL app.user_id` | db |
| `api/src/db/` | engine, `Base`, сессия, ORM-модели (36) | core.config |
| `api/src/domain/` | pydantic-схемы API, enums | — |
| `api/src/core/` | Настройки, JWT/argon2, исключения и маппинг ошибок Postgres в HTTP | — |
| `api/alembic/` | Миграции (около 49 ревизий); `versions/sql/*.sql` — DDL, функции, сиды, около 43 тыс. строк | Postgres |
| `web/src/app/` | Роуты, AuthProvider (токены в localStorage) | pages |
| `web/src/pages/` | Задачи (формы), карточка формы или проекта, проекты и их своды, свод 1 и 2, админка, справочники | components, api |
| `web/src/components/RealtimeTable/` | Редактируемая таблица листа: WebSocket, блокировки, конфиги колонок `constants/FORM_*` | api |
| `web/src/api/` | axios-клиент `/api/v1`, модули по сущностям, WebSocket выгрузок | — |
## Границы
- Роутеры не ходят в БД напрямую, только через сервисы и репозитории. Сейчас нарушают `admin.py`, `main.py` (engine) и `websocket.py` (бизнес-логика в слое API).
- Проверка прав на ячейки и окна этапов — в SQL. Python её не дублирует, только маппит ошибки.
- Изменения схемы и функций — только новой миграцией alembic; старые миграции не правятся.
- Фронт обращается только к `/api/v1` через `web/src/api/`.
## Открытые вопросы
- Prod-авторизация через Keycloak (`raisa_fastapi_protected_api`) закомментирована в `main.py`, `deps.py`, `auth.py`; сейчас всегда работает локальный JWT. Как будет устроен prod?
- `websocket.py:333`, `:357`: условие `form_key != form_key` всегда ложно, поэтому блокировки сравниваются по `line_id` между всеми формами; `release_locks_for_row` ничего не возвращает.
- Раскладка колонок дублируется: `web/.../constants/FORM_1|2|4/*.js` (около 4 тыс. строк каждый) и `api/.../export_mappings.py`. Источник правды не определён.
- Названия форм в БД и UI расходятся (FORM_2, FORM_4).
- Мёртвый код фронта: `pages/TablePage.jsx`, `FormsPage.jsx`, `TablesTest.jsx`, `TableTempPage/`, `api/tables.js`, `api/client_form.js`, `api/ws.js`, `constants/FORM_1/*_NO_LOCAL.js`.
- В `package.json` не объявлены `@mui/x-date-pickers`, `@mui/icons-material`; tailwind/daisyui не используются.
- `Settings.CORS_ORIGINS` не применяется (в `main.py` `allow_origins=["*"]`), `APP_ENV` не читается, `JWT_SECRET` по умолчанию небезопасный.
- `/` монтируется дважды в `api/src/main.py:289` и `:291`.
- Интеграционные тесты зависят от данных в общей БД и не изолированы; `downgrade()` в миграциях пустые.
- Python-линтеров и проверок CI в репозитории нет.