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

52 lines
8.6 KiB
Markdown
Raw 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.

# 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.
## Стек и ограничения
- 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` и цикл чистки аудита.
## Архитектура
Подробная карта — в 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_*`.
## Команды
- Установка: `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`.
## Тесты
- `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-тестами.
## Ветки и 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 защищает каталоги из `.claude/code-paths`: `api/src/`, `api/alembic/` (SQL-логика), `web/src/`.