arm-core/web/ARCHITECTURE.md
Andrey Epifancev 7e8b035b17 Task 8: подключение таблицы корректировок к реальному API (#208)
Реальный контракт AURORA-1540/1751 не дал единой POST .../allocations:
решение по строке разбито на PUT/DELETE .../vgo-assignments/rule
(привязка/снятие правила) и PUT .../vgo-assignments/exclude (КФО),
ответ — список VgoAssignmentOut, а не вся таблица. allocate()
маршрутизирует по action и перечитывает таблицу сама — вызывающий код
(CorrectionContent, CorrectionEditorModal) не менялся.

Фейк контракта (CORRECTIONS_MOCK) убран — API уже есть. mockData/mockCalc
остаются тестовыми фикстурами (R-27).

Проверено на реальном стенде (Русский Бисквит — 2025 К1): загрузка
таблицы, EXCLUDE/INCLUDE, ASSIGN, снятие правила, сохранение
корректировки, экспорт — без ошибок в консоли.
2026-11-02 21:08:20 +04:00

79 lines
8.7 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.

# Архитектура фронта arm-core/web
SPA поверх API arm-core (`/api/v1`). Своих данных и бизнес-вычислений нет: всё производное (чек-лист, сводная ОСВ,
статусы) считает сервер, фронт показывает и отправляет действия пользователя. До 21.10.2026 фронт вёлся в отдельном
репозитории `RSHB/arm-web` и переносился сюда синхронизацией; теперь — только здесь.
## Модули
| Модуль | Ответственность | Зависит от |
|---|---|---|
| `src/api/` | HTTP-клиент, токен, разбор ошибок | `conf/`, `auth/token` |
| `src/auth/` | профиль `/me`, dev-вход, права для меню | `api/` |
| `src/services/api/` | вызовы ресурсов arm-core | `api/`, `types/` |
| `src/store/` | состояние экранов (Redux Toolkit) | `services/api/` |
| `src/utils/` | чистые функции: деньги, подписи, скачивание, правила консолидаций | `types/` |
| `src/hooks/` | общие React-хуки (виртуальный список, предупреждение `beforeunload`) | React |
| `src/types/` | DTO API (повторяют `../api/src/schemas/`) | — |
| `src/components/` | примитивы UI (таблица, теги, заголовок) | antd |
| `src/widgets/` | блоки экранов (`DocumentReview` — проверка документа со сканом, `ConsolidatedOsv` — сводная ОСВ, `FilesDrawer`; консолидации — см. ниже) | `components/`, `store/`, `services/api/`, `utils/` |
| `src/layouts/` | страницы-маршруты | `widgets/` |
### Виджеты экранов консолидаций
Требования — `../openspec/changes/consolidations-ui/` (после архивации — `../openspec/specs/consolidations-ui/`),
`consolidation-setup`, `consolidated-osv-ui`.
| Виджет | Экран | Что делает |
|---|---|---|
| `ConsoleTable/ConsoleTable.tsx` | [34] | список консолидаций ГК: дерево версий, «Только в работе» (`in_work_only`), действия строки, меню «⋯» |
| `ConsoleTable/LockModal.tsx` | [35] | «Взять в работу» (`POST …/lock`) и перехват с причиной (`takeover_reason`) |
| `../utils/consolidations.ts` | — | правила без React: подписи и пояснения статусов версии, ручные переходы (`MANUAL_TRANSITIONS` — зеркало бэка), своя блокировка, «Версия», `in_work_only`, причина ≤ 1000 |
| `ConsoleTable/consts.ts` | — | цвета бейджей статусов версии |
| `ConsolidatedOsv/OsvTabs.tsx` | [30] | вкладки шагов отчёта и модалка «Проверьте встречные записи участников» при уходе с «ОСВ» (список пар — `counter_pairs` сводки) |
| `ConsolidatedOsv/CounterPairsView.tsx` | [30] | режим «Встречные записи» вкладки «ОСВ»: пары, строки держателя, строки Б без ИНН с «Указать» |
| `ConsolidatedOsv/counterPairs.ts` | — | правила без React: подпись пары, параметры адреса режима (`?view=pairs&holder=&missing=`) |
| `ConsolidatedOsv/useNumberDisplay.tsx` | [30] | «Единицы» и «Знаков после запятой» сводной ОСВ (`formatScaledAmount` из `utils/money.ts`) |
| `../hooks/useBeforeUnload.ts` | — | предупреждение браузера о несохранённых правках в открытой модалке |
| `ConsoleLegalEntities/` | [34] | панель «Организации» выбранной версии и чек-лист |
| `NewConsoleModal/` (`CompanyOptionRow.tsx`) | [42] | «Новая консолидация»; строка ЮЛ с ИНН отдельной колонкой |
| `StatusChangeModal/ChangeStatusModal.tsx` | [33-01] | «Изменить статус» (`POST …/status`); открывается из шапки `layouts/ConsolidationReportPage.tsx` |
### Виджет «Таблица корректировки» (`widgets/CorrectionTable/`)
Требования — `../openspec/changes/corrections-table-ui/` (спека `corrections-table-ui`, решения — `design.md`). Контракт —
`../../docs/dev/api-contract-corrections.md`, типы — `src/types/corrections.ts`, вызовы — `src/services/api/corrections.ts`.
Поток данных: страница отчёта → `CorrectionContent` (вкладка: загрузка, ошибка с «Повторить», экспорт, полный экран)
→ хук `useCorrectionTable` (запрос; применяется только ответ последнего запроса, `latestOnly`) → таблица целиком хранится в
родителе; `CorrectionTable` только рисует, фильтры/раскрытие/колонки — состояние родителя. Решение по строке (флажок
нераспределённой, меню) → `allocate` — на сервере (arm-core #208) это две отдельные ручки (`vgo-assignments/rule`
привязка/снятие, `vgo-assignments/exclude` включение/исключение из КФО), `allocate` сама выбирает нужную по
`action` и перечитывает таблицу целиком; «Корректировать» → `CorrectionEditorModal` → `saveCorrection`
(`PUT`, `expected_version_no`, сервер сразу применяет) → подмена одного агрегата; отзыва корректировки нет. Черновик окна —
`localStorage` (`draftStorage`).
| Файл | Тип | Что делает |
|---|---|---|
| `tableModel.ts` | чистый | строки таблицы (агрегат, его строки ОСВ, нераспределённые), фильтры, пресет правила, итоги |
| `editorModel.ts` | чистый | состояние окна: исходное из агрегата, проверки ввода, контроль баланса, кандидаты в picker, пересборка |
| `editorView.ts` | чистый | тексты окна: ошибки сохранения, плашка черновика, строка контроля, подпись «Выбрать» |
| `readOnly.ts` | чистый | подсказки «только чтение», меню строки (`allocationMenu`), тело запроса разнесения |
| `draftStorage.ts` | чистый | черновик окна в `localStorage` (ключ: пользователь + версия + агрегат) |
| `columns.ts` | чистый | ключи и группы колонок для «Настройки таблицы» |
| `useCorrectionTable.ts` | хук | загрузка, `reload`/`replace`/`replaceAggregate` |
| `CorrectionContent.tsx`, `CorrectionToolbar.tsx`, `CorrectionTable.tsx`, `HeaderFilter.tsx` | компоненты | вкладка, панель, таблица с группами колонок, воронки в заголовках |
| `CorrectionEditorModal.tsx`, `EditorSide.tsx`, `AllocationPicker.tsx` | компоненты | окно «Корректировка операции», сторона окна, выбор нераспределённой строки |
| `mockData.ts`, `mockCalc.ts` | фикстуры | данные дизайна и пересчёт агрегата; остаются как тестовые фикстуры (R-27); фейк контракта `services/api/correctionsFake.ts` удаляется в Task 8 |
| `../../utils/money.ts` | чистый | деньги копейками (`toCents`, `percentOfSmaller`, порог 5 %) |
Чистые модули покрыты vitest (`*.test.ts`); компоненты тестов не имеют (нет DOM-библиотеки), их проверяют в браузере.
## Границы
- Сетевые запросы — только через `src/api/client.ts`; `fetch` напрямую не вызывается.
- `components/` не знают про store и API; `types/` ни от чего не зависят.
- `utils/` не импортирует React, store и API.
## Сборка
`npm run build` → `web/dist`, Dockerfile ядра кладёт его в `api/web/` и FastAPI отдаёт SPA (`../README.md`).