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>
This commit is contained in:
parent
cf85326558
commit
5190e5ef13
3
.claude/code-paths
Normal file
3
.claude/code-paths
Normal file
@ -0,0 +1,3 @@
|
||||
api/src/
|
||||
api/alembic/
|
||||
web/src/
|
||||
@ -1,15 +1,42 @@
|
||||
# Архитектура
|
||||
|
||||
{{Карта модулей на одну страницу: что где лежит, границы, потоки данных. Читается агентом перед architectural brainstorming. Обновляется вместе со спеками.}}
|
||||
Монорепозиторий: `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 в репозитории нет.
|
||||
|
||||
49
CLAUDE.md
49
CLAUDE.md
@ -1,32 +1,51 @@
|
||||
# harness-describe
|
||||
# DFiP_Budget_planing
|
||||
|
||||
## Что это
|
||||
{{ОДНИМ АБЗАЦЕМ: что делает система, для кого, главный сценарий.}}
|
||||
Система бюджетного планирования ДФиП РСХБ (платформа raisa). Исполнители ССП и региональных филиалов (РФ) совместно, в реальном времени заполняют бюджетные формы (сметы) по листам, статьям расходов и кварталам. Что и когда может править каждая роль, задают этапы (окна редактирования колонок). ДФиП и ДУРРС корректируют (секвестр), администратор ведёт пользователей, оргструктуру, шаблоны этапов и журнал аудита. Поверх форм строятся своды 1 и 2, реестр проектов РФ (открытие, закрытие и переезд ВСП и т.п.) с отчётами по годам, справочник ВСП и фоновая выгрузка в Excel.
|
||||
|
||||
Формы (`v3.form_type`): FORM_1 «Смета ГО» (AHR/CAP/OPER/SMETA, AHR и CAP делятся по direction Support/Development), FORM_2 «ПД» (плюс сателлиты AHR_LIMIT/RENT/UTILITY/SECURITY, OTCH9F), FORM_3 «Отчёт РФ развитие» (хранится в project → rf_project_year → rf_project_report), FORM_4 «Смета РФ поддержка» (плюс STRUCTURE — программы и проекты). Названия на фронте (`web/src/constants/constants.jsx`) расходятся с БД, источник истины — БД.
|
||||
|
||||
Роли (`api/src/db/models/role.py`): 1 ADMIN; 2 EXECUTOR_DFIP (несколько ССП/РФ); 3 EXECUTOR_RF (одна оргединица); 4 EXECUTOR_DURRS.
|
||||
|
||||
## Стек и ограничения
|
||||
- {{Язык, сборка, тесты — например: Python 3.12, uv, pytest.}}
|
||||
- {{Жёсткие ограничения среды исполнения — без чего код не должен собираться.}}
|
||||
- Backend `api/`: Python, FastAPI 0.111, SQLAlchemy 2 async + asyncpg, Alembic, pydantic-settings, JWT (python-jose, HS256) + argon2.
|
||||
- **БД — только PostgreSQL**, всё в схеме `v3`. Бизнес-логика в основном в PL/pgSQL-функциях `v3.add_*`/`upd_*`/`del_*`/`v_*`, их зовут через `text("SELECT ... FROM v3.fn(...)")` из `api/src/repository/`. Функции живут в `api/alembic/versions/sql/*.sql` и переопределяются `CREATE OR REPLACE` в последующих миграциях: актуальна последняя версия. SQLite в `DATABASE_URL` по умолчанию — ловушка, на нём приложение не работает.
|
||||
- Frontend `web/`: React 18 на Rsbuild, **JavaScript (JSX)**, хотя есть tsconfig. UI — MUI и material-react-table. Основная таблица — собственный `components/RealtimeTable/`. Состояние в React Context, роутинг react-router-dom 6, axios. Biome для линта. Tailwind/daisyui остались от шаблона и не используются.
|
||||
- Платформа raisa: обязателен `api/run_server.py`; хост и порт из `SERVER__HOST`/`SERVER__PORT`. CI — внешний шаблон `cicd/ci/fastapi-app.yml` (`.gitlab-ci.yml`), ресурсы в `raisa_config.yml`. Собранный фронт отдаёт сам API из `api/web` (StaticFiles).
|
||||
- Зависимости ставятся из корпоративного Nexus (`setup/pip.conf`, `setup/.npmrc`). `raisa-fastapi-protected-api` есть только там.
|
||||
- cwd процессов API, тестов и alembic — `api/`: пути `alembic.ini`, `.env`, `web`, `back_static`, `tmp/exports` относительные.
|
||||
- Состояние WebSocket-блокировок ячеек и менеджер выгрузок живут в памяти процесса: один процесс, без нескольких воркеров.
|
||||
- Настройки (`api/src/core/config.py`): `OPENBAO__SETTINGS__*` или короткое имя (`DATABASE_URL`, `DEBUG`, `DATABASE_SCHEMA`). `DEBUG` по умолчанию true. При false на старте выполняются `alembic upgrade head` и цикл чистки аудита.
|
||||
|
||||
## Архитектура
|
||||
- `src/core/` (или {{ваш путь}}) — чистая логика без зависимостей от фреймворка/платформы. Покрывается тестами полностью.
|
||||
- `src/{{adapter}}/` — тонкая обёртка над платформой. Тестируется руками или интеграционно.
|
||||
- {{Ключевые интерфейсы/порты между ними, если есть.}}
|
||||
Подробная карта — в ARCHITECTURE.md.
|
||||
- `api/src/api/v1/` — роутеры (`/api/v1/...`) и `deps.py` (текущий пользователь, гарды `require_admin`/`require_executor*`). `websocket.py` — realtime-редактирование и блокировки ячеек.
|
||||
- `api/src/services/` — сервисы `*Service(db)`; `export_service/` — Excel-выгрузки в ProcessPool.
|
||||
- `api/src/repository/` — `*Repository(db)`: SQLAlchemy и вызовы SQL-функций. Текущий пользователь передаётся в SQL через `SET LOCAL app.user_id` (для аудита `v3.log_event`).
|
||||
- `api/src/db/models/` — ORM (36 моделей), `api/src/domain/schemas.py` — pydantic-схемы, `api/src/core/` — конфиг, безопасность, ошибки.
|
||||
- Права на ячейки проверяет SQL (`role_not_allowed:`, `window_closed:`). `core/exception_handlers.py` по тексту ошибки Postgres превращает их в 403/409/400/404/422.
|
||||
- `web/src/app/Routes.jsx` — страницы, `web/src/api/*.js` — клиент API, `web/src/components/RealtimeTable/` — редактируемая таблица, конфиги колонок по формам в `constants/FORM_*`.
|
||||
|
||||
## Команды
|
||||
- `{{npm test / pytest}}` — весь набор тестов. Зелёным считается только весь набор.
|
||||
- `{{npm run build / ...}}` — сборка.
|
||||
- `{{npm run dev / ...}}` — локальный запуск.
|
||||
- Установка: `cd setup && ./setup.sh` (venv в `api/.venv`, `npm i` в `web/`). Для тестов дополнительно `pip install -r api/requirements-dev.txt`.
|
||||
- API: `cd api && python run_server.py` (нужен Postgres в `DATABASE_URL`). Миграции: `cd api && alembic upgrade head`.
|
||||
- Web: `cd web && npm run start` (dev), `npm run build` (результат в `web/dist`). Линт: `cd web && npx biome check src`.
|
||||
- Тесты backend: `cd api && pytest` — весь набор. Зелёным считается только весь набор. `pytest tests/unit` — без БД. `pytest tests/integration` — нужен живой Postgres; `--init_db` накатывает миграции и сид `tests/sqls/fixture.sql`.
|
||||
- Тесты frontend: `cd web && node --test src/components/RealtimeTable/utils/*.test.js`.
|
||||
|
||||
## Тесты
|
||||
- Golden-тесты: `tests/fixtures/<name>.*` + эталон `<name>.expected.*`. Внешние сервисы в тестах мокаются.
|
||||
- {{Где лежит тестовое окружение (vault, БД, песочница).}}
|
||||
- `api/tests/unit/` — моки сессии и репозиториев (`AsyncMock`, `monkeypatch`), БД не нужна.
|
||||
- `api/tests/integration/` — `TestClient(app)` с полным lifespan, сессия с rollback. Фикстуры `admin_tokens`/`isp_tokens` (`api/tests/conftest.py`, `tests/integration/conftest.py`). Тестовое окружение — Postgres из `DATABASE_URL`, пароли `OPENBAO__TEST_ADMIN_PASSWORD`/`OPENBAO__TEST_EXECUTOR_PASSWORD`. Часть тестов делает `skip` при отсутствии данных.
|
||||
- Новая логика в SQL-функциях покрывается интеграционными тестами через API. Логику без БД выносить в сервисы и покрывать unit-тестами.
|
||||
|
||||
## Первая подсистема
|
||||
{{Что делается первым и почему. Тестовая инфраструктура — Task 1 первого плана.}}
|
||||
## Ветки и PR
|
||||
- **Базовая ветка — `test`**, не `main`: в неё идут все PR, `main` — устаревший шаблон. Везде, где процесс обвязки говорит «main» (база worktree, PR, `openspec archive`, `git pull --ff-only` в основном checkout), читать `test`.
|
||||
- Хук guard-main защищает только main/master, `test` он не охраняет. Прямые коммиты в `test` запрещены так же, как в main; исключение — только коммит `openspec archive`.
|
||||
- PR создаётся с `--base test`.
|
||||
|
||||
## OpenSpec и superpowers
|
||||
- Вход в любую задачу — superpowers:brainstorming. Skills openspec-propose и openspec-explore сами по себе не запускать.
|
||||
- Когда brainstorming классифицировал задачу как architectural, структуру change создать через `openspec new change <id>` (или `/opsx:propose <id>`), а содержимое proposal.md, specs/ и design.md написать по итогам brainstorming. tasks.md из OpenSpec не заполнять — задачи живут в плане superpowers.
|
||||
- `/opsx:apply` не использовать: исполнение идёт через writing-plans и SDD/executing-plans.
|
||||
- `openspec archive <id>` — после merge PR, как часть чеклиста закрытия.
|
||||
- Хук require-plan защищает любой каталог `src/` на любой глубине. Если код лежит иначе — перечислить каталоги (префиксы от корня, по одному в строке) в `.claude/code-paths`.
|
||||
- Хук require-plan защищает каталоги из `.claude/code-paths`: `api/src/`, `api/alembic/` (SQL-логика), `web/src/`.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user