Домен, стек, слои, команды, тесты, базовая ветка test. .claude/code-paths: api/src/, api/alembic/, web/src/. Refs #198 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
8.6 KiB
Markdown
52 lines
8.6 KiB
Markdown
# 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/`.
|