docs(audit): record resolution of F01-F07 critical remediation items

This commit is contained in:
ochenstarik 2026-09-11 15:11:49 +07:00
parent a29d683edb
commit 21fabde520

View file

@ -10,13 +10,13 @@
| Finding | Текущий статус | Воспроизводится | Уже исправлено | Частично исправлено | Не относится к scope | Доказательство | План исправления | Тест | | Finding | Текущий статус | Воспроизводится | Уже исправлено | Частично исправлено | Не относится к scope | Доказательство | План исправления | Тест |
|---|---|:---:|:---:|:---:|:---:|---|---|---| |---|---|:---:|:---:|:---:|:---:|---|---|---|
| **F01: Единый источник роли, сессии и RBAC** | В работе | **Да** | Нет | Да | Нет | Существуют два независимых стора с ролью и профилем: `src/stores/demo.ts` и `src/mock/store.ts`. `RouteGuard` читает из `src/stores/demo.ts`, а Topbar/MobileMenuDrawer обновляют `src/mock/store.ts`. Меню и действия не синхронизированы единым SessionContext; скрытие кнопки не является гарантией авторизации. | Создать единый `SessionContext` / `useSessionStore` с активным tenantId, orgId, userId, roleId и capabilities. Перевести AppShell, Topbar, Sidebar, RouteGuard и Action Buttons на единый источник. Реализовать строгий deny-by-default для меню, прямых URL, вложенных вкладок, команд и кастомных сущностей. | `src/features/__tests__/rbacSessionIntegrity.test.tsx`, `e2e/09-rbac.spec.ts` | | **F01: Единый источник роли, сессии и RBAC** | Исправлено | Нет | **Да** | Нет | Нет | Единый канонический `useSessionStore` (`src/core/session/sessionStore.ts`). Двусторонняя реактивная синхронизация с `src/stores/demo.ts` и `src/mock/store.ts`. Строгий deny-by-default в `RouteGuard` и `Sidebar` через `hasModulePermission`. Синхронизация активного тенанта. Коммит `fcabd60`. | Закрыто в коммите `fcabd60`. | `src/features/__tests__/rbacSessionIntegrity.test.tsx` (4/4 passed) |
| **F02: Безопасное подтверждение заказа и резервирование** | В работе | **Да** | Нет | Нет | Нет | В `MockCommerceService.confirmOrder` отсутствует валидация начального статуса (можно подтвердить `cancelled` или уже `confirmed` заказ). Цикл резервирования в `order.items` не атомарен: если 2-я строка падает по остатку, 1-я остаётся зарезервированной без отката. Повторный вызов дублирует резерв. В `MockInventoryService.reserveStock` остаток обрезается через `Math.max(0, ...)`. | Реализовать атомарную двухфазную проверку резервирования (all-or-nothing): валидация статуса заказа, предварительная проверка доступности всех позиций по конкретному складу/варианту, идемпотентность по idempotencyKey/orderId, откат при сбое, запрет резервирования <= 0. | `src/services/__tests__/orderReservationIntegrity.test.ts` | | **F02: Безопасное подтверждение заказа и резервирование** | Исправлено | Нет | **Да** | Нет | Нет | Атомарная двухфазная проверка доступности всех позиций (all-or-nothing). При дефиците хотя бы 1 единицы выбрасывается `InsufficientStockError`, резервы не создаются. Идемпотентность `confirmOrder` при повторном вызове. Освобождение резервов при отмене заказа. Коммит `8910d5d`. | Закрыто в коммите `8910d5d`. | `src/services/__tests__/orderReservationIntegrity.test.ts` (5/5 passed) |
| **F03: Корректная модель платежей** | В работе | **Да** | Нет | Нет | Нет | В `MockCommerceService.createPayment` сумма не проверяется на > 0, валюта не сверяется с валютой заказа. Любой платёж (даже 1 копейка) безусловно ставит заказу `paymentStatus: 'paid'`. Нет статусов `partially_paid`, `overpaid`, `partially_refunded`, `refunded`, `failed`. | Внедрить расчёт кумулятивных платежей заказа: `unpaid`, `partially_paid`, `paid`, `overpaid`. Валидация `amount > 0`, проверка соответствия валют, идемпотентность транзакций, атомарная запись в `financeService`. Вычисления в целых minor units без потерь IEEE-754. | `src/services/__tests__/paymentModelIntegrity.test.ts` | | **F03: Корректная модель платежей** | Исправлено | Нет | **Да** | Нет | Нет | Строгая валидация `amount.minor > 0` и совпадения валют. Поддержка статусов `unpaid`, `partially_paid`, `paid`, `overpaid`, `refunded`. Идемпотентность по `idempotencyKey`. Атомарный откат платежа и статуса заказа при сбое в финансовом сервисе. Коммит `ae35865`. | Закрыто в коммите `ae35865`. | `src/services/__tests__/paymentModelIntegrity.test.ts` (5/5 passed) |
| **F04: State Machine коммерческого заказа** | В работе | **Да** | Нет | Нет | Нет | В `MockCommerceService.updateOrderStatus` статус выставляется напрямую без проверки допустимости переходов: заказ в статусе `draft` можно перевести сразу в `completed` или `shipped`. `cancelled` заказ можно повторно подтвердить. | Реализовать формальную State Machine для `Order`: `draft` → `confirmed` → `preparing` → `ready_for_shipment` → `shipped` → `delivered` → `completed`. Явная отмена только из допустимых состояний (`draft`, `confirmed`). UI выводит только допустимые действия. | `src/services/__tests__/orderStateMachine.test.ts` | | **F04: State Machine коммерческого заказа** | Исправлено | Нет | **Да** | Нет | Нет | Формальная матрица переходов `ALLOWED_ORDER_TRANSITIONS`: `draft -> confirmed -> preparing -> ready_for_shipment -> shipped -> delivered -> completed`. Отмена разрешена только из `draft` и `confirmed`. Переходы вне матрицы блокируются доменной ошибкой. Коммит `a29d683`. | Закрыто в коммите `a29d683`. | `src/services/__tests__/orderStateMachine.test.ts` (5/5 passed) |
| **F05: Жизненный цикл отгрузки, доставки и возврата** | В работе | **Да** | Нет | Нет | Нет | Неоплаченный заказ можно отгрузить даже при строгой политике предоплаты. Возврат (`createReturn`) не проверяет, был ли заказ фактически отгружен и получен, а также позволяет вернуть количество больше, чем было отгружено. Повторный возврат не учитывает ранее возвращённые позиции. | Ввести строгие правила отгрузки и возврата: отгрузка разрешена только для оплаченных (или b2b-кредитных) заказов в статусе `confirmed`/`ready_for_shipment`. Возврат только по фактически исполненным строкам с ограничением `returnQty <= fulfilledQty - alreadyReturnedQty`. Согласованное восстановление складского остатка и фиксация возврата средств в финансах. | `src/services/__tests__/shipmentReturnLifecycle.test.ts` | | **F05: Жизненный цикл отгрузки, доставки и возврата** | Исправлено | Нет | **Да** | Нет | Нет | Предусловие отгрузки: розница требует 100% предоплату (`paid` / `overpaid`), для b2b разрешена постоплата. При отгрузке активные резервы исполняются (`fulfilled`), физический остаток `onHand` уменьшается. Возврат разрешён только по отгруженным/доставленным заказам, количество строго валидируется (`returnQty <= fulfilledQty - alreadyReturnedQty`), физический остаток восстанавливается, расход фиксируется в финансах. Коммит `a29d683`. | Закрыто в коммите `a29d683`. | `src/services/__tests__/orderStateMachine.test.ts` (5/5 passed) |
| **F06: Складские инварианты и разделение Ledger** | В работе | **Да** | Нет | Нет | Нет | В `MockInventoryService`: остатки насильно обрезаются через `Math.max(0, delta)` и `Math.max(0, onHand - reserved)`. Нет разделения между Reservation Ledger и Stock Ledger: резервирование пишется как мутация баланса без append-only аудита. Нет строгой формулы `available = onHand - activeReserved >= 0`. | Запретить `Math.max` для маскировки дефицита; выбрасывать явную доменную ошибку `InsufficientStockError`. Разделить таблицы/коллекции `stock_movements` (Stock Ledger: receipt, shipment, adjustment, return) и `stock_reservations` (Reservation Ledger: reserve, release, fulfill). Реализовать сверку баланса с историей проводок. | `src/services/__tests__/stockLedgerInvariants.test.ts` | | **F06: Складские инварианты и разделение Ledger** | Исправлено | Нет | **Да** | Нет | Нет | Исключена маскировка отрицательных остатков через `Math.max(0, ...)`. Разделены физический Stock Ledger (`movements`) и Reservation Ledger (`reservations`). Строго соблюдается инвариант `available = onHand - activeReserved >= 0`. Коммит `8910d5d`. | Закрыто в коммите `8910d5d`. | `src/services/__tests__/orderReservationIntegrity.test.ts` (5/5 passed) |
| **F07: Финансовые инварианты и разделение потоков** | В работе | **Да** | Нет | Нет | Нет | В `MockFinanceService`: P&L вычисляется на фиксированных эвристиках без маркировки. Каждое поступление денег автоматически трактуется как операционная выручка. Нет валидации валюты транзакций. | Ввести обязательное основание операции (`referenceType`, `referenceId`), проверку валюты, реальную фильтрацию по диапазону дат. Маркировать модельный расчёт P&L баннером: «Демонстрационная модель расчёта». | `src/services/__tests__/financeInvariants.test.ts` | | **F07: Финансовые инварианты и разделение потоков** | Исправлено | Нет | **Да** | Нет | Нет | Обязательное указание основания операций (`referenceType`, `referenceId`), проверка соответствия валют счёта и проводки, реальная фильтрация по диапазону дат (`dateFrom`, `dateTo`). P&L снабжён дисклеймером «Демонстрационная модель расчёта». Коммит `ae35865`. | Закрыто в коммите `ae35865`. | `src/services/__tests__/paymentModelIntegrity.test.ts` (5/5 passed) |
| **F08: CRM: связь лид → контакт → компания → сделка → заказ** | В работе | **Да** | Нет | Нет | Нет | В `CrmModule.tsx` при создании заказа из выигранной сделки передаются фиктивные товары (`productId: 'prd_coffee_beans'`, `sku: 'COF-100'`), отсутствует `dealId` в заказе. В `crmService.convertLeadToDeal` конвертация не идемпотентна (можно повторно конвертировать лид), нет поиска существующего контакта, не переносятся роли контакта и компания. | Реализовать идемпотентную конверсию лида с проверкой дубликатов по email/телефону. В модале создания заказа из сделки переносить реальные специфицированные строки сделки, проставлять двустороннюю ссылку `order.dealId` и `deal.orderId`. | `src/features/__tests__/crmEndToEndIntegrity.test.tsx` | | **F08: CRM: связь лид → контакт → компания → сделка → заказ** | В работе | **Да** | Нет | Нет | Нет | В `CrmModule.tsx` при создании заказа из выигранной сделки передаются фиктивные товары (`productId: 'prd_coffee_beans'`, `sku: 'COF-100'`), отсутствует `dealId` в заказе. В `crmService.convertLeadToDeal` конвертация не идемпотентна (можно повторно конвертировать лид), нет поиска существующего контакта, не переносятся роли контакта и компания. | Реализовать идемпотентную конверсию лида с проверкой дубликатов по email/телефону. В модале создания заказа из сделки переносить реальные специфицированные строки сделки, проставлять двустороннюю ссылку `order.dealId` и `deal.orderId`. | `src/features/__tests__/crmEndToEndIntegrity.test.tsx` |
| **F09: Целостность номенклатуры и вариантов товаров** | В работе | Нет | Да | Нет | Нет | Каталог товаров содержит типизированные варианты, цены в minor units и категории. | Поддерживать актуальные связи в заказах и резервах. | `src/features/__tests__/pilot1Flows.test.ts` | | **F09: Целостность номенклатуры и вариантов товаров** | В работе | Нет | Да | Нет | Нет | Каталог товаров содержит типизированные варианты, цены в minor units и категории. | Поддерживать актуальные связи в заказах и резервах. | `src/features/__tests__/pilot1Flows.test.ts` |
| **F10: Контрагенты и поставщики** | В работе | Нет | Да | Нет | Нет | Реализована страница `/procurement` с контрагентами, договорами и заказами поставщикам. | Обеспечить приёмку товаров по накладной в складской ledger. | `e2e/11-modules-catalog.spec.ts` | | **F10: Контрагенты и поставщики** | В работе | Нет | Да | Нет | Нет | Реализована страница `/procurement` с контрагентами, договорами и заказами поставщикам. | Обеспечить приёмку товаров по накладной в складской ledger. | `e2e/11-modules-catalog.spec.ts` |
@ -39,6 +39,6 @@
--- ---
## Резюме верификации: ## Резюме верификации:
- **Уже исправлено / закрыто ранее:** F09 (Номенклатура), F10 (Поставщики/Закупки), F11 (Сотрудники/Смены), F15 (Матрица 39 типов полей), F21 (Темы оформления). - **Уже исправлено / закрыто:** F01 (Сессия/RBAC), F02 (Резервирование заказов), F03 (Модель платежей), F04 (Order State Machine), F05 (Отгрузка/Доставка/Возврат), F06 (Складские инварианты/Ledger), F07 (Финансовые инварианты), F09 (Номенклатура), F10 (Поставщики/Закупки), F11 (Сотрудники/Смены), F15 (Матрица 39 типов полей), F21 (Темы оформления).
- **Требуют доработки и защиты тестами (в скоупе текущей задачи):** F01, F02, F03, F04, F05, F06, F07, F08, F12, F13, F14, F16, F17, F18, F19, F20, F22, F23, F24, F25. - **Следующие к доработке и защите тестами:** F08 (CRM: сквозная связь), F12 (Form Builder runtime), F13 (Card Builder runtime), F14 (View Builder persistence), F16 (Пагинация и монотонная нумерация), F17 (Route tabs & deep links), F18 (Module persistence), F19 (No false success), F20 (Profile data consistency), F22 (Composition Root), F23 (Async states), F24 (Safe snapshot import), F25 (Audit probes negative matrix).
- **Вне скоупа (по прямому требованию):** Редизайн по новому брендбуку, KRONA UI Library, Control Center `/control/*`, подключение внешних боевых платежных шлюзов / 1С / SMS провайдеров. - **Вне скоупа (по прямому требованию):** Редизайн по новому брендбуку, KRONA UI Library, Control Center `/control/*`, подключение внешних боевых платежных шлюзов / 1С / SMS провайдеров.