Dikkom ERP

← На главную

Источник: docs/development-plan.md

# Roadmap: Логистическая система (1–5 мая 2026)

**Назначение документа:** оперативная дорожная карта, **детальный план Спринта 1** (май 2026, закрыт) и **Спринта 2** — задачи, подзадачи, критерии приёмки, порядок работ, связь с кодом.

**В паре с планом эпиков:** стратегия этапов, потоки **A–E** и основной backlog — **[04-development-plan-and-backlog.md](04-development-plan-and-backlog.md)** (смотреть вместе с этим файлом при планировании и приёмке).

**Текущая волна (`04` **3.71**–**3.79**, `02` **2.66**–**2.74**, 30.04.2026):** закрыты **B.5** (UI **`/references/partner-rules`**, **`/references/partner-accruals`**, **`rebuildCalculationReportVitrineForOpenPeriod`** после мутаций); **B.3.3** (подписи партнёра в **`audit-log-display.ts`**); **поток C (MVP):** **`/reports/vitrine-dashboard`**; **Excel/PDF** в **`ReportFrame`** (**`xlsx`** в **`package.json`**); **B.6.2** — **`partner-accrual-report-aggregate.test.ts`**, **`docs/protocol-parity-4-4.md`** (+ **3.73:** **`parity-4-4-meeting-pack.md`**, проект протокола к подписанию); **`isDwellStorageLine`** + **`partner_accrual`** для **`site_dwell`**. **H.1** **3.72**/ **2.67** — сверка **`02`/`04`/`TODO`/`development-plan`/`project-handoff`** с фактами **3.71** (устранены формулировки «B.5 в бэклоге»). **H.1 / Epic 6** **3.73**/ **2.68** — черновик **`import-spec.md`**, **`fixtures/import/nsi_site_chain_pilot.csv`**. **H.1** **3.74**/ **2.69** — контроль: **`prisma`** без миграций после **`20260530250000_*`** (*на срезе **3.74***; позже — **`Application.createdByUserId`**, **`20260530260000_*`**); *снимок:* до **3.75** в **`src/`** не было **`src/lib/import/*`** и маршрута загрузки **4.2**; **`import_write`** не в **`Permission`**. **3.75** / **2.70:** **`/references/nsi-import`**, **`importNsiSiteChainV0`**, **`nsi-site-chain-v0.test.ts`**. **3.76** / **2.71:** **`docs/import-charge-lines-v0.md`**, **`parity-export-diff.ts`**, **`week-3-4-plan-4-3-4-5.md`**, расширение тестов НСИ. **3.77** / **2.72:** **`charge-lines-control-v0.ts`**, **`charge-lines-control-v0.test.ts`** — пре-валидация контрольного CSV **`ChargeLine`** без БД. **3.78** / **2.73:** единая сверка **`TODO`** / **`04`** / **`02`** / roadmap / handoff / сводка с **`prisma/migrations`** (на срезе **3.78** последняя по партнёру — **`20260530250000_partner_rules_accruals`**) и **`src/lib/import/*`**; **`npm run ci`**. **3.79** / **2.74:** миграция **`20260430260000_application_created_by_user`** (**`Application.createdByUserId`**); продуктовый импорт **`ChargeLine`** — **`charge-lines-import-v0.ts`**, **`/references/charge-lines-import`**, **`importChargeLinesControlV0`**; пересечения **`WagonStay`** — **`wagon-stay-interval-overlap.ts`**; дубликат папки **`20260430260000_application_created_by_user`** в **`prisma/migrations/`** — см. **`02` 2.74**; **H.1**-синхронизация доков с репозиторием. **Дальше:** подписанный **4.4**, полный паритет мартовской таблицы и хвост **Epic 4–5** — без расширения **MVP 4.3** (он уже в продукте).

**Связанные артефакты:** [`TODO.md`](../TODO.md) (чеклисты выполнения), [`project-handoff.md`](project-handoff.md) (краткий handoff для нового чата), [`04-development-plan-and-backlog.md`](04-development-plan-and-backlog.md) (эпики и этапы), [`02-data-model.md`](02-data-model.md) (модель **`AuditLog`** и др.), **[`import-spec.md`](import-spec.md)** / **[`fixtures/import/`](../fixtures/import/)** (**MVP 4.1–4.2** — **`04` 3.75**, **`02` 2.70**), **[`import-charge-lines-v0.md`](import-charge-lines-v0.md)** / **[`parity-export-diff.ts`](../src/lib/parity-export-diff.ts)** (черновик **4.3** / tooling — **`04` 3.76**, **`02` 2.71**), **[`charge-lines-control-v0.ts`](../src/lib/import/charge-lines-control-v0.ts)** (пре-валидация — **`04` 3.77**, **`02` 2.72**), **[`charge-lines-import-v0.ts`](../src/lib/import/charge-lines-import-v0.ts)** (**MVP импорт **4.3** — **`04` 3.79**, **`02` 2.74**); актуализация чеклистов и доков — **`04` 3.78**–**3.79**, **`02` 2.73**–**2.74**.

**Спринт 2 (детализация):** раздел **«Спринт 2: Операционное ядро и связи»** ниже.

**Версия плана Спринта 1:** 1.0 (май 2026). После закрытия подзадач отмечайте `[x]` здесь и зеркально в **`TODO.md`** → раздел «Спринт 1».

---

## Срез репозитория после Спринта 1 (актуализация плана)

| Область | Состояние |
|--------|------------|
| **`AuditLog`** | Модель, **`logActivity`**, индексы (в т.ч. **`[entityId, timestamp]`** для ленты по объекту, **`[timestamp]`** / **`[userId]`** для глобального журнала); UI **`/audit-log`** (**`getGlobalAuditLogPage`**, **`references_read`**). |
| **`withAuditedServerAction`** | `src/lib/audit-action-wrapper.ts`: `requirePermission`, санитизация, `outcome` success/error, **`{ ok: false }`**, **`getAuditTargetAfterSuccess`** для **CREATE**. |
| Мутации **заявок** | `src/app/orders/actions.ts` — обёртка (маршрутизация, статус, вагоны, этапы, время событий). |
| Мутации **НСИ** | `src/app/references/*/actions.ts` — обёртка; прямой **`logActivity`** в НСИ не используется. |
| UI аудита по заявке | «История изменений» на **`/orders/[id]`** (**`getOrderAuditLog`**). |
| Шапка / навигация | **`AppHeader`**, **`AppHeaderNav`**: Главная, Заявки, Справочники, Roadmap; при сессии — **Журнал** (**`/audit-log`**). **`AppHeaderAuth`**: email, выход, **`User.role`** / **`SystemRole.name`**. |
| Футер | **`AppFooter`** в корневом layout. |
| Защита маршрутов | **`middleware.ts`**: **`/references`**, **`/orders`**, **`/audit-log`**, **`/reports`** — с сессией; **`/`**, **`/roadmap`**, **`/login`** — без обязательного входа. |

**Контекст:** изначально Спринт 1 **дополнял** уже существующий каркас (аудит по заявке, часть НСИ); по завершении тем A–C чеклисты плана и **`TODO.md`** синхронизированы с таблицей выше.

---

## Спринт 1: Фундамент наблюдаемости и UX (верхний уровень)

- [x] **Тема A.** Глобальный журнал аудита (инфраструктура + UI списка).
- [x] **Тема B.** Политика и унификация использования **`withAuditedServerAction`** / **`logActivity`** (стандарт + миграция НСИ по плану) — *НСИ: см. B.2; заявки уже на обёртке.*
- [x] **Тема C.** Единая layout-оболочка (навигация, отображение контекста пользователя/ролей, хедер/футер).

---

## Детализация Спринта 1

### Тема A. Глобальный журнал аудита

**Цель:** одна точка входа для просмотра **`AuditLog`** по всей системе с фильтрами (без замены ленты по заявке).

#### A.1 Данные и индексы

- [x] Зафиксировать в **`02-data-model.md`** (кратко) сценарий глобального журнала: используемые поля **`AuditLog`** (`action`, `entityName`, `entityId`, `userId`, `timestamp`, `details`).
- [x] Проверить при росте объёма: достаточно ли индекса **`[timestamp]`** и **`[userId]`** для фильтров; при необходимости — отдельная миграция (например, составной индекс под типовые запросы). *Решение (30.04.2026): типовой запрос глобального журнала — диапазон по **`timestamp`** + сортировка **`timestamp desc`** и опциональные **`entityName`** / **`entityId`** / **`userId`** (**`getGlobalAuditLogPage`**, **`parseAuditLogListQuery`**). Индексы **`[timestamp]`**, **`[userId]`**, **`[entityName, entityId]`** из схемы покрывают MVP; составной индекс под смешанные фильтры — только после **`EXPLAIN`** на репрезентативном объёме. Не вводить индексы «наугад».*

#### A.2 Server layer

- [x] Вынести общий запрос в один модуль (например, `src/lib/audit-list-query.ts` или рядом с `audit.ts`): пагинация, сортировка по **`timestamp` desc**, фильтры:
  - диапазон дат (`dateFrom` / `dateTo` в UTC или явная зона «Москва» — **зафиксировать в коде и в комментарии**);
  - опционально `entityName` (строка или enum-список в UI);
  - опционально `entityId` (точное совпадение);
  - опционально `userId` (число, FK на **`User`**).
- [x] Ограничить глубину выборки по умолчанию (например, последние 30 дней), с расширением по явному запросу пользователя — **защита от случайного full scan**.
- [x] Право доступа: только пользователи с **`references_read`** или отдельное право **`audit_read`** — **решение зафиксировать** (минимально: `references_read` + роль admin/editor, либо новый `Permission` в Prisma + миграция + обновление **`02`** §2.1).

#### A.3 UI

- [x] Маршрут **`/audit-log`** (или `/admin/audit` — единое имя в навигации).
- [x] Таблица: время, действие, сущность (`entityName` + укороченный `entityId`), пользователь (email или id), итог (`details.outcome` / `actionKey` при наличии).
- [x] Форма фильтров в query-string (`?page=`, `?from=`, `?to=`, `?entityName=`, `?entityId=`, `?userId=`) для воспроизводимых ссылок.
- [x] Ссылка «Открыть связанную сущность» — только где однозначно (например, `Order` → `/orders/:id`); для остальных — без «угадывания» URL.

#### A.4 Критерии приёмки (Тема A)

- [x] Авторизованный пользователь с разрешённой ролью открывает список и видит записи из разных модулей (НСИ + заявки).
- [x] Фильтры меняют результат предсказуемо; пагинация не ломается при смене фильтра.
- [x] Документация: **`02`** (при изменении прав/индексов), **`TODO.md`**, этот файл — чекбоксы А закрыты.

---

### Тема B. Централизованная обёртка `withAuditedServerAction`

**Цель:** единый контракт для мутаций: право, аудит, санитизация, исход **success/error**.

**Базис:** `src/lib/audit-action-wrapper.ts` уже реализует обёртку; заявки и **все** write-пути НСИ в `src/app/references/**/actions.ts` её используют (**`getAuditTargetAfterSuccess`** для **CREATE**).

#### B.1 Стандарт и документация

- [x] Короткий внутренний регламент (в начале `audit-action-wrapper.ts` или `docs/` фрагмент в **`04`**, не дублируя простыню): когда использовать **`withAuditedServerAction`**, когда допустим **`logActivity`** (редкие низкоуровневые случаи), обязательные поля **`actionKey`**, **`getAuditTarget`**, **`summarizeArgs`**.
- [x] Таблица соответствия **`AuditAction`** ↔ типы операций (CREATE/UPDATE/DELETE и существующие **ATTACH_WAGON**, **WAGON_EVENT**); при нехватке enum — миграция Prisma + **`02`**. *Зафиксировано в **`02-data-model.md`** (§2.1, блок «Соответствие `AuditAction`»); новые значения enum — по мере появления в `schema.prisma`.*

#### B.2 Инвентаризация и миграция Server Actions (НСИ)

- [x] Составить список всех мутаций в `src/app/references/**/actions.ts`, которые ранее звали **`logActivity`** вручную *(инвентаризация 30.04.2026): **CREATE** в **bill-to-parties**, **clients**, **currencies**, **legal-entities**, **payment-terms**, **services**, **site-accounting-objects**, **tax-settings**, **units**, **vat-rates**, **wagon-stays**, **wagon-types**, **warehouses**, **applications** (после MVP §5.2.0); **волна 1** — **counterparties** / **sites** (**update**/**delete**), затем **create** контрагента/площадки, **wagons** (**create**/**update**/**delete**), **tariffs** (**create**)*.
- [x] По приоритету (высокий риск / частота изменений): перевести на **`withAuditedServerAction`** **или** оставить явный **`logActivity`** с **ссылкой на причину** в комментарии (например, пакетная операция). *На 30.04.2026 все перечисленные write-пути НСИ используют обёртку (**`getAuditTargetAfterSuccess`** для создания записей).*
- [x] Для каждой переведённой цели: **`entityName`/`entityId`** согласованы с глобальным журналом (строковые имена сущностей стабильны).

#### B.3 Критерии приёмки (Тема B)

- [x] Заявки: без регрессий (существующие тесты вручную / smoke по сценарию смены статуса и этапа вагона). *Регрессии по заявкам с `withAuditedServerAction` не выявлены при контрольном **`npm run build`**, smoke сценариев — по процессу команды.*
- [x] Хотя бы **N** критичных НСИ-экранов пишут аудит через обёртку. *Закрыто: все мутации НСИ в `references/**/actions` на обёртке; **тарифы** — **create**; **update**/**delete** тарифов в коде отсутствуют.*
- [x] В **`AuditLog.details`** нет утечек паролей/токенов (регрессия **`sanitizeForAudit`**).

---

### Тема C. Единая layout-оболочка (навигация, роли, хедер/футер)

**Цель:** предсказуемый каркас приложения для всех основных разделов.

#### C.1 Навигация

- [x] Добавить в **`AppHeaderNav`** недостающие **публичные** или **защищённые** пункты по политике продукта, например:
  - **План / Roadmap** → `/roadmap` (для всех или только авторизованных — **решить**);
  - **Журнал аудита** → `/audit-log` после Темы A (видимость по праву).
- [x] Единые правила: что видит гость (только «Войти» + Главная?) vs залогиненный.

#### C.2 Контекст пользователя и роли

- [x] В шапке (или выпадающем блоке) отображать **роль**: `User.role` и/или подпись **`SystemRole`** из **`getAuthContext`** — без дублирования секретов.
- [x] При отсутствии **`SystemRole`** показывать только базовую роль.

#### C.3 Футер

- [x] Общий **`AppFooter`** в `RootLayout`: версия/год, опционально ссылка на документацию, **без** утечки внутренних путей.
- [x] Адаптив: не перекрывает контент на малых высотах.

#### C.4 Критерии приёмки (Тема C)

- [x] Все ключевые страницы (`/`, `/orders`, `/references`, новые `/audit-log`, `/roadmap`) визуально согласованы: одна шапка, общий футер, отступы не «пляшут».
- [x] Закрыт открытый пункт **`TODO.md`**: «Базовый UI/UX и навигация (разделы вне НСИ, оболочка по ролям, нижний колонтитул)» — либо явно уточнить остаток в **`TODO.md`**.

---

## Рекомендуемый порядок выполнения (Спринт 1)

1. **B.1** — регламент (чтобы не переделывать аудит дважды).
2. **A.1–A.2** — запросы и права на список аудита.
3. **A.3** — UI глобального журнала.
4. **C.1 + C.3** — навигация и футер (подключить ссылку на журнал).
5. **C.2** — роли в шапке.
6. **B.2** — поэтапная миграция НСИ на обёртку (можно часть перенести на Спринт 1b в **`TODO.md`**, если не укладываетесь по времени).

Зависимость: **Тема A** логически связана с **C.1** (пункт меню «Журнал»).

---

## Definition of Done — Спринт 1 (весь спринт)

- [x] Все чекбоксы **Тем A, B, C** на верхнем уровне отмечены выполненными здесь и в **`TODO.md`**.
- [x] **`npm run build`** проходит; миграции Prisma (если были) задокументированы в **`02`** при изменении схемы.
- [x] **`04-development-plan-and-backlog.md`** содержит актуальную отсылку к этому плану и версию/дату при необходимости.

---

## Спринт 2: Операционное ядро и связи

**Цель спринта:** согласовать **MVP заявок** (`Order`, `OrderWagon`, `WagonEvent`) с **учётом размещений** (`WagonStay`) и заложить **расширенный расчётный контур** по направлению к каноническим **`charge_lines`** §5.3 **`02-data-model.md`**, без попытки закрыть весь Этап 2 **`04`** (~170 ч) целиком.

**Опора на артефакты:** **`TODO.md`** (Этап 2, Backlog Sites), **`04-development-plan-and-backlog.md`** §2 (Этап 2), Epic 2–3; целевая модель **§5.2 / §5.3** в **`02`**.

### Тема D. Мэппинг контрагент / клиент и выравнивание площадки

| ID | Задача | Детали и критерии |
|----|--------|-------------------|
| **D.1** | **Мэппинг `Counterparty` ↔ `Client`** | Зафиксировать в **`02`** и в коде способ связи: отдельная таблица связей, опциональный FK на **`Client`** у **`Counterparty`**, или правила сопоставления по ИНН/ручной привязке. **DoD:** миграция Prisma при необходимости; обновление **`02`** §2.1/§5.1; сценарии «один контрагент — несколько клиентов» / «не сопоставлен» описаны; точка в UI или админ-процесс (минимум — отображение связи в карточке контрагента или в списке). |
| **D.2** | **`Site` и целевая модель** | Закрыть открытые пункты **`TODO.md`** → Backlog Sites: при необходимости **`UNIQUE(name)`**, поля вместимости/ограничений/комментария по §5.1; согласование **`isActive`** vs целевого **`status`**. **DoD:** миграция(и) + обновление форм/валидации; запись в **`02`**. |
| **D.3** | **Привязка `Site` к клиенту / цепочке расчёта** | После D.1: опциональный **`Site.clientId`** → **`Client`** (**`onDelete: SetNull`**), согласование с **`Counterparty.clientId`** в прикладном слое; UI **`/references/sites`**. **Срез 30.04.2026:** миграция **`20260503120000_site_optional_client`**, **`02`** v **2.27**. |

### Тема E. Связь заявки и размещения (`Order` ↔ `WagonStay`)

| ID | Задача | Детали и критерии |
|----|--------|-------------------|
| **E.1** | **Проектирование связи** | Выбрать минимально достаточную модель: FK **`orderId`** (или `applicationId` в перспективе) на **`WagonStay`**, опционально **`source_in_application_id` / `source_out_application_id`** из §5.2, или связующая таблица. Зафиксировать в **`02`** §5.2.1 и в **`04`**. |
| **E.2** | **Миграция и инварианты** | Реализовать схему: создание размещения из контекста заявки (или привязка существующего **`WagonStay`** к **`Order`**) без нарушения **`siteId`** ↔ **`SiteAccountingObject`**. Правила снятия привязки при отмене заявки. |
| **E.3** | **UI / Server Actions** | Минимальный пользовательский поток: с карточки **`/orders/[id]`** видеть связанные размещения или создавать черновик размещения с предзаполнением площадки/объекта учёта/вагона. Аудит через **`withAuditedServerAction`**, где это мутации. |

### Тема F. События у размещения и расширение `charge_lines`

| ID | Задача | Детали и критерии |
|----|--------|-------------------|
| **F.1** | **Целевые события у `WagonStay`** | Ввести отдельную сущность в Prisma (например, **`WagonStayEvent`**) по мотивам §5.2 **не путать** с **`WagonEvent`** на **`OrderWagon`**. Типы этапов, FK на **`wagon_stay_id`**, **`occurredAt`**, аудит. **DoD:** миграция, **`02`**, read API для будущих расчётов. |
| **F.2** | **Расширение `ChargeLine` к §5.3** | Поля: период / **`wagon_stay_id`** (или явная ссылка на источник), тип услуги, incoming/outgoing в соответствии с тарифом. Поэтапно: не ломать текущий MVP по **`Order`** + **`cargo_operation`**; стратегия dual-write или второй тип строки — зафиксировать в ADR/фрагменте **`02`**. **Срез 30.04.2026:** **`periodId`**, денормализация §5.3, миграция **`20260530180000_calculation_period_charge_line_canonical`** (**`04`** v **3.33**); таблица §2.1 и комментарии Prisma согласованы (**`02`** v **2.35**). |
| **F.3** | **Отстой (dwell): генерация строк** | По интервалу **`WagonStay`** (и тарифам «отстой» incoming/outgoing) — генерация **`charge_lines`** с правилом **«вагон-сутки включительно»** (как в **`04`** §2). Минимальный движок в сервисном слое (вызов из job/admin action или по событию закрытия периода). |
| **F.4** | **НДС (базово)** | Если объём позволяет: применение **`TaxSetting`** / **`VatMode`** (accrual / extraction) к новым строкам; иначе — вынести подзадачей в начало Спринта 3 с явной отметкой в **`TODO`**. |

### Тема G. НСИ тарифы и операционная отчётность

| ID | Задача | Детали и критерии |
|----|--------|-------------------|
| **G.1** | **CRUD тарифов: update/delete** | Реализовать правку и удаление с guards (зависимости **`ChargeLine`**, др.) и **`withAuditedServerAction`**. **DoD:** UI **`/references/tariffs`** (+ **`?edit=`** по паттерну других НСИ при необходимости). |
| **G.2** | **Отчёт «Вагоны на площадках на дату»** | Как в **`04`** §2 deliverable: фильтр по дате, площадке/объекту; использование **`ReportFrame`**, экспорт CSV при необходимости. |
| **G.3** | **Отчёт «Начисления за расчётный период»** | **`/reports/charges-by-period`**: **`ChargeLine`** по **`CalculationPeriod`**, фильтры площадка/объект учёта, итоги б/НДС / НДС / с НДС, CSV (**`ReportFrame`**). **DoD:** **`04`** v **3.35**, **`02`** v **2.36**. |

### Тема H. Качество, документация, инфраструктура

| ID | Задача | Детали и критерии |
|----|--------|-------------------|
| **H.1** | **Документация** | Обновлять **`02`**, **`04`** (версия), **`TODO.md`**, **`project-handoff.md`** по мере закрытия **E**–**H.3**, MVP **`Application`** и срезов Epic 3 (**`04`** v **3.32**–**3.43**, **`02`** v **2.33**–**2.44** помимо **3.31**/**2.32**); краткий smoke-чеклист: заявка → открыта → вагон → этапы; размещение связано; строки отстоя incoming/outgoing (**`chargeSide`**, **`OP_FINISHED`**) и НДС (**F.4**); отчёт начислений по периоду (**G.3**); **свод по периоду** (**`/reports/charges-rollup`**, **v3.38**); **главный отчёт за период** (**`/reports/calculation-for-period`**, **`period-calculation-report.ts`**, **v3.39**; **витрина **`CalculationReportLine`**, **`reportSource`**, **`calculation-report-line-build.ts`**, чтение UI/CSV — **v3.54**–**3.56**/ **`02`** **2.53**–**2.55**; строки переноса **`CarryForwardBalance`** — **v3.47**/ **`carry-forward-report-lines.ts`**; контрольная сверка §2.1 — **v3.40**/ **2.41**; док. backlog автосвода (**Epic 3** п. **1**, **v3.41**/ **2.42**); контрольная сверка индексов **`ChargeLine`** и комментария Analytics в **`schema.prisma`** — **v3.42**/ **2.43**; повторная **H.1** — §2.1 **`WagonStayEvent`**/**`ApplicationWagon`**, отчётные модули — **v3.43**/ **2.44**; **MVP перенос свода** — **`CarryForwardBalance`**, миграция **`20260530220000_carry_forward_balances`**, **`carryForwardRollupBalances`** (**`AuditAction.CREATE`**, цель **`CalculationPeriod`**) — **v3.47**/ **2.46**; док. **H.1** по переносам / аудиту — **v3.48**/ **2.47**; **поток A / мини-H.1** — автосвод при **`linkWagonStayToOrder`** / **`unlinkWagonStayFromOrder`**, **`updateOrderStatus` → `CANCELLED`**, allowlist **`chargeLine`** (**v3.49**/ **2.48**); **контрольная сверка §2.1** (**v3.50**/ **2.49**); **поток B**, DDL **`CalculationReportLine`** (**v3.53**/ **2.51–2.52**): миграция **`20260530230000_add_calculation_report_lines`**, **`calculation-report-line-key.ts`**, **`groupKey`**, правки SQL **`20260530210000_*`** / **`20260530220000_*`** под **MySQL**; **после **B.1.2** — **H.1** **v3.61**/ **`02`** **v2.59** (схема **`partner_*`**, **`Application`**); разовые подача/уборка (**`wagon_placement`** / **`wagon_release`**, **`per_wagon_event`** через **`ChargeLine.chargeBasis`**, v **3.36**; сверка без новой миграции — **v3.37**/ **2.38**); расчётный период (**`CalculationPeriod`**) и канон. **`ChargeLine`** (**v3.33**); привязка **`Order`** к **`Application`** (**P1**, v **3.35**); заявка ввод/вывод в НСИ и ссылка из размещения (**v3.30**); **Epic 6 / Этап 4:** **3.73**/**2.68** — **`import-spec`**, проект **4.4**; **3.74**/**2.69** — снимок до **MVP 4.2**; **3.75**/**2.70** — **`/references/nsi-import`**, **`nsi-site-chain-v0`**; **3.76**/**2.71** — **`import-charge-lines-v0.md`**, **`parity-export-diff`**; **3.77**/**2.72** — **`charge-lines-control-v0`**. |
| **H.2** | **CI/CD (минимум)** | **Закрыто (**`04`** v **3.27**; **B.3.2** **3.65** — расширенный allowlist; **3.67** — **`npm run test`**):** GitHub Actions **`.github/workflows/ci.yml`** (push/PR **`main`/`master`**) — **`npm run lint`**, **`npx prisma validate`**, **`node scripts/check-charge-line-mutations.mjs`** (**`ChargeLine`**, **`CalculationReportLine`**, **`CalculationRollupLine`**, **`CarryForwardBalance`**), **`npm run test`**, **`npm run build`**; скрипт **`npm run ci`** (lint + validate + allowlist + test + build). |
| **H.3** | **Техдолг** — **закрыто** | Регламент в **`audit-action-wrapper.ts`** (в т.ч. **H.3**); известные мутации НСИ и заявок (включая **`generateChargesFromEvents`** — грузовая операция и с **v3.36** подача/уборка, **`generateDwellChargesForOrder`**) проходят через **`withAuditedServerAction`** или явно задокументированы (**`createOrder`**, **`reportOrderAuditEvent`**); подписи в **`describeAuditLogDetails`**. |

### Порядок работ (рекомендация)

1. **D.1 → D.2** (модель данных и миграции в начале спринта).
2. **E.1–E.2** (связь `Order`–`WagonStay` до больших изменений в **`ChargeLine`**).
3. **F.1 → F.2 → F.3** (события размещения → расширение строк → отстой).
4. **G.1 → G.2** параллельно по ресурсу, если команда >1.
5. **F.4 / H.*** в конце или перенос обрезка в следующий спринт при нехватке времени.

### Ближайший спринт (текущий срез)

*Таблица приоритетов ниже — **исторический снимок** начала Спринта 2; по состоянию на **`04`** v **3.46** закрыты **D.2**–**D.3**, **E**, **F.1**–**F.4**, **G.1**–**G.3**, **H.2**, **H.3**, MVP **§5.2.0** (**`Application`**, ссылки **`WagonStay`**); **P1 MVP** (**`Order.applicationId`**); **MVP подача/уборка** (**`wagon_placement`** / **`wagon_release`**, **`per_wagon_event`** на **`ChargeLine.chargeBasis`**, без отдельной миграции — задокументировано **3.37**/ **`02`** **2.38**); MVP свод **`CalculationRollupLine`** (**`/reports/charges-rollup`**) — **3.38**/ **2.39**; **MVP главный отчёт «Расчёт за период»** (первая итерация — runtime из **`ChargeLine`**) — **3.39**/ **2.40**; **cutover на **`CalculationReportLine`** + пересборка витрины** — **3.54**–**3.56**/ **2.53**–**2.55**; контрольная **H.1**-сверка **`schema.prisma`**, **`02`** §2.1 и **`project-handoff`** — **3.40**/ **2.41**; док. wave Epic 3 п. **1** — **3.41**/ **2.42**; уточнение индексов **`ChargeLine`** (**`serviceId`**, **`wagonStayId`**) и комментария Analytics в **`schema.prisma`** — **3.42**/ **2.43**; **H.1** повторно — §2.1 **`WagonStayEvent`**/**`ApplicationWagon`**, отчётные модули — **3.43**/ **2.44**; сверка этапов и Этап 4 — **3.44**–**3.45**; **план закрытия этапов 1–3 (полное ТЗ)** §**1.1** + **реализация автосвода** Epic 3 п. **1** — **3.46**/ **2.45**. **Доп.:** **MVP перенос остатков свода** (**`CarryForwardBalance`**, **`20260530220000_carry_forward_balances`**) — **3.47**/ **2.46**; док. **H.1** (аудит **`carryForwardRollupBalances`**, синхронизация **`TODO`**) — **3.48**/ **2.47**; **поток A** (хвост автосвода + allowlist **`chargeLine`**) — **3.49**/ **2.48**; **контрольная сверка §2.1 с Prisma** (**`OrderWagon`**, **`CalculationPeriod`**, **`Application`**) — **3.50**/ **2.49**. **Поток B:** **`04`** v **3.51** — декомпозиция, **`TODO`** «Поток B», §**3.0б**; **`04`** v **3.52** — **B.0.1–B.0.3** (док.: **`02`** v **2.50** §**6** / §**5.4**, **`03`** v **1.3**); **`04`** v **3.53** — **B.1.1a**: **`CalculationReportLine`**, **`20260530230000_add_calculation_report_lines`**, **`calculation-report-line-key.ts`**, выравнивание **`groupKey`**, правки SQL **MySQL** в **`20260530210000_*`** / **`20260530220000_*`**. Epic 3: отстой и канонический **`ChargeLine`** §5.3 (**`04`** v **3.32–3.34**) + отчёт **`/reports/charges-by-period`**. **Доп. поток B:** **3.57**/ **2.56** — **B.2.2**; **3.59**/ **2.57** — **B.2.3**, **B.4.2**, **B.0.4**; **3.60**/ **2.58** — **B.4.3**, **B.4.4**, **B.1.2**; **H.1** — **3.61**/ **2.59**; **3.62**–**3.68** / **2.60**–**2.63** — **`PartnerAccrual`** в витрине, **B.3.1**–**B.3.2**, **B.5** в бэклоге, **B.6.1**, повторная **H.1** (**см. `04` v **3.68**). **Актуальный фокус (после **`04` **3.77**, **`02` **2.72**):** **Этап 4** — продуктовый импорт **`ChargeLine`** по **`import-charge-lines-v0.md`**, **подписанный 4.4**, интеграция CSV diff в приёмку; паритет мартовской таблицы и **Epic 4–5**. **Закрыто:** **4.1**/**MVP 4.2** НСИ (**3.75**), черновик **4.3** + **`parity-export-diff`** (**3.76**), пре-валидация **`charge-lines-control-v0`** (**3.77**). Параллельно — **`Application`**, **`wagon_events`** у **`WagonStay`** (**`project-handoff`**).

Цель итерации ниже — **закрыть хвосты Спринта 2 по порядку D → E**, взять **быстрый результат по G.1** и не расползаться на F до фиксации связи заявки с размещением. *(Выполнено; строки таблицы сохранены как архив.)*

| Приоритет | ID | Задача | Примечание |
|-----------|-----|--------|------------|
| *(архив)* | **D.2** | **`Site`** → целевая модель | Закрыто (**`02`** v **2.26**). |
| *(архив)* | **D.3** | Площадка в цепочке расчёта | Закрыто: **`Site.clientId`**, см. **`02`** v **2.27**. |
| *(архив)* | **E.1–E.3** | **`Order` ↔ `WagonStay`** | Закрыто: **`orderId`**, UI **`/orders/[id]`**. |
| *(архив)* | **G.1** | **Тарифы: update/delete** | Закрыто. |
| *(архив)* | **G.2** / **F.1** | Отчёт или события **`WagonStay`** | Закрыто: **`/reports/wagons-on-sites`**, **`WagonStayEvent`**. |
| **P0** | **Backlog `04`** | **`calculation_lines`** (полный контур, маржа кол. 23–24), паритет мартовского отчёта | Канон. **`ChargeLine`** §5.3 и периоды — **`04`** v **3.33**; **MVP свод** — **`CalculationRollupLine`**, **`04`** v **3.38**; **MVP перенос свода** — **`CarryForwardBalance`**, **`04`** v **3.47**, миграция **`20260530220000_carry_forward_balances`**; **витрина «Расчёт за период»** — **`CalculationReportLine`**, **`04`** v **3.53**–**3.56**, миграции **`20260530230000_add_calculation_report_lines`**, **`20260530240000_calculation_report_line_source`** (**наполнение — **`rebuildCalculationReportLinesForPeriod`**, **B.2.1**); **MVP таблица «Расчёт за период»** (исторически runtime из **`ChargeLine`**, **3.39**; **чтение из витрины — **3.55**–**3.56**) — **`period-calculation-report.ts`**, синтетические строки переноса — **3.47**; док. сверка со схемой — **3.40**/ **2.41**; **автосинхронизация свода** с типовыми мутациями **`ChargeLine`** — **3.46**/ **2.45**; индексы **`ChargeLine.serviceId`**, **`wagonStayId`** — в **`02`** (**2.43** / **`04`** **3.42**); **H.1** док. **3.43**/ **2.44** — §2.1 **`WagonStayEvent`**/**`ApplicationWagon`**; **H.1** **3.48**/ **2.47** — переносы и аудит; **3.49**/ **2.48** — поток **A** (автосвод + allowlist **`chargeLine`**); **3.50**/ **2.49** — сверка **`OrderWagon`** / **`CalculationPeriod`** / **`Application`** в §2.1; **полные `calculation_lines` с маржой и партнёрами** — **Epic 4–5**, *продуктовый срез не завершён* (п. **2** Epic 3); эталон **03** целиком — Epic 4–5 **`04`**. |
| **P1** | **ТЗ §5.2** (MVP) | **`Order.applicationId`** ↔ **`Application`** | **`20260530200000_order_application_link`**, **`src/lib/order-application-link.ts`**, **`order-application-link-form`**, **`updateOrderApplicationLink`**, сброс при смене НСИ — **`04`** v **3.35**, **`02`** v **2.36**. *Backlog:* полный цикл §5.2, утверждения, история. |

### Definition of Done — Спринт 2 (реалистичный минимум)

- [x] D.1 зафиксирован и реализован в схеме + документации.
- [x] D.2: целевые поля **`Site`** + **`UNIQUE(name)`** в Prisma и **`02`** v **2.26** (остаток **`status`** vs **`isActive`** — backlog).
- [x] D.3: опциональный **`Site.clientId`**, UI **`/references/sites`**, согласование с **`Counterparty.clientId`** (**`02`** v **2.27**, миграция **`20260503120000_site_optional_client`**).
- [x] Есть осмысленная связь **`Order`** ↔ **`WagonStay`** (E.1–E.2) и минимальный UI или API-поток (E.3).
- [x] Заведена сущность событий у **`WagonStay`** (F.1); расширение **`ChargeLine`** (F.2) реализовано (**`periodId`**, денормализация §5.3 — **`04`** v **3.33**; описание в **`02`** v **2.34–2.35**).
- [x] Работает сценарий **отстоя** (F.3): **`ChargeLine`** с **`wagon_days_inclusive_incoming`** / **`wagon_days_inclusive_outgoing`**, **`chargeSide`**, календарные UTC-сутки включительно, граница по **`OP_FINISHED`** (**`04`** v **3.32**; легаси **`wagon_days_inclusive`** снимается пересчётом).
- [x] Работает базовый НДС на строках (**F.4**): приоритет ставки тариф → **`TaxSetting`**, снимок **`vatMode`**, пересчёт из событий/отстоя.
- [x] **G.1** и **G.2** закрыты (тарифы update/delete с guard; отчёт **`/reports/wagons-on-sites`**).
- [x] **G.3** закрыт: отчёт **`/reports/charges-by-period`** по **`CalculationPeriod`**, фильтры, CSV, итоги (**`04`** v **3.35**, **`02`** v **2.36**).
- [x] **P1** (MVP): одна заявка на одну целевую **`Application`** (**`Order.applicationId`**, миграция **`20260530200000_order_application_link`**, UI + аудит + сброс при смене НСИ в **`updateOrderRouting`**).
- [x] **MVP подача/уборка** (**`04`** v **3.36**; док. **3.37**/ **`02`** **2.38**): **`wagon_placement`** / **`wagon_release`** (seed), **`per_wagon_event`** (**`ChargeLine.chargeBasis`**, отдельной миграции нет), **`src/lib/wagon-event-billing.ts`**, синхронизация с этапами вагона и **`generateChargesFromEvents`** (**`src/app/orders/actions.ts`**).
- [x] **H.1** контрольная синхронизация документации со схемой и кодом: подтверждено отсутствие миграции под **`per_wagon_event`**, согласованы **`02`** v **2.38** и **`04`** v **3.37**; **доп.:** **`CalculationRollupLine`** — **`02`** v **2.39**, **`04`** v **3.38**.
- [x] **MVP свод начислений за период** (**`04`** v **3.38**, **`02`** v **2.39**): **`CalculationRollupLine`**, миграция **`20260530210000_calculation_rollup_lines`**, **`src/lib/charge-period-rollup.ts`**, **`/reports/charges-rollup`**, пересборка с **`references_write`**.
- [x] **MVP главный отчёт «Расчёт за период»** (**`04`** v **3.39**, **`02`** v **2.40**; **cutover витрины **3.55**–**3.56**/ **2.54**–**2.55**): **`src/lib/period-calculation-report.ts`**, **`/reports/calculation-for-period`**, первая итерация — колонки из runtime-агрегации **`ChargeLine`**; **текущий UI/CSV** — строки **`CalculationReportLine`** после **`rebuildCalculationRollupsForPeriod`**; синтетические строки переноса — **v3.47**/ **`carry-forward-report-lines.ts`**; маржа кол. **20/23–24** в витрине — **B.2.2** (**`04`** **3.57**), unit-тесты — **3.67**; полный паритет эталона — **4.4** / backlog.
- [x] **H.1 контрольная сверка (документация):** **`04`** v **3.40**, **`02`** v **2.41** — **`schema.prisma`** на дату **3.40** без новых миграций после **`20260530210000_calculation_rollup_lines`** (позже — **`20260530220000_carry_forward_balances`**); §2.1 (**`ChargeLine[orderId]`**, отчётные маршруты), **`project-handoff`**.
- [x] **H.1 документация Epic 3 п. 1 (автосвод):** **`04`** v **3.41**, **`02`** v **2.42** — без DDL; до **3.46** зафиксирован ориентир только на ручную пересборку.
- [x] **Epic 3 п. 1 (автосинхронизация свода):** **`04`** v **3.46**, **`02`** v **2.45** — **`charge-period-rollup.ts`**, вызовы из **`orders/actions.ts`**; сохраняется кнопка **«Пересчитать свод»**.
- [x] **H.1 контрольная сверка индексов `ChargeLine` и Analytics в `schema.prisma`:** **`04`** v **3.42**, **`02`** v **2.43** — **`@@index([serviceId])`**, **`@@index([wagonStayId])`**; комментарий в начале **`schema.prisma`** без новых моделей; на срезе **3.42** последняя миграция — **`20260530210000_calculation_rollup_lines`** (далее **`20260530220000_carry_forward_balances`** — **3.47**).
- [x] **H.1 повторная контрольная синхронизация:** **`04`** v **3.43**, **`02`** v **2.44** — отчётные **`src/lib/period-calculation-report.ts`**, **`charge-period-rollup.ts`**, **`src/app/reports/*`**; §2.1 **`WagonStayEvent`** (**`createdAt`/`updatedAt`**, **`@@index([wagonStayId])`**), **`ApplicationWagon`** (**`@@index([wagonId])`**); новых миграций на ту дату нет.
- [x] **MVP перенос остатков свода (поток A, Epic 3):** **`04`** v **3.47**, **`02`** v **2.46** — **`CarryForwardBalance`**, миграция **`20260530220000_carry_forward_balances`**, **`src/lib/carry-forward-balance.ts`**, **`carry-forward-report-lines.ts`**, слияние в **`charge-period-rollup.ts`**, **`carryForwardRollupBalances`** / **`submitCarryForwardRollupBalances`** — **`references/calculation-periods/actions.ts`**, права **`references_write`**.
- [x] **H.1 док. сверка переносов и подписи аудита:** **`04`** v **3.48**, **`02`** v **2.47** — **`carryForwardRollupBalances`** в **`audit-log-display.ts`**; **`AuditAction.CREATE`**, цель **`CalculationPeriod`** (**`toPeriodId`**); синхронизация **`TODO`**, **`project-handoff`**.
- [x] **H.1 мини / поток A (`04` v **3.49**, `02` v **2.48`):** автосвод при **`linkWagonStayToOrder`** / **`unlinkWagonStayFromOrder`**, **`updateOrderStatus` → `CANCELLED`**; **`scripts/check-charge-line-mutations.mjs`** в **`npm run ci`** и **`.github/workflows/ci.yml`**.
- [x] **H.1 контрольная сверка `schema.prisma` и §2.1 (`04` v **3.50**, `02` v **2.49`):** на дату записи без миграций после **`20260530220000_carry_forward_balances`**; в **`02`** — индексы **`OrderWagon`**, **`CalculationPeriod`**, **`Application`**.
- [x] **Поток B — B.2.1 / B.4.1 / B.1.1b (`04` v **3.54**–**3.56**, `02` v **2.53**–**2.55`):** **`rebuildCalculationReportLinesForPeriod`** (**`calculation-report-line-build.ts`**), миграция **`20260530240000_calculation_report_line_source`**, **`getPeriodCalculationReport`** → **`CalculationReportLine`**.
- [x] **Поток B — B.1.1a (`04` v **3.53**, `02` v **2.51–2.52`):** **`CalculationReportLine`**, миграция **`20260530230000_add_calculation_report_lines`**, **`src/lib/calculation-report-line-key.ts`**, **`groupKey`** в **`period-calculation-report.ts`**; правки SQL **`20260530210000_calculation_rollup_lines`**, **`20260530220000_carry_forward_balances`**; **`applications/actions.ts`** (связь **`Order?`**).
- [x] **Поток B — B.2.2 (`04` v **3.57**, `02` v **2.56`):** маржа кол. **23–24** в **`aggregatePeriodCalculationReportLines`** (**`wagon_placement`** incoming/outgoing, **`totalMarginWithVat`**).
- [x] **Поток B — B.2.3 / B.4.2 / B.0.4 (`04` v **3.59**, `02` v **2.57`):** **`assertPeriodOpenForReportVitrine`**; **`rebuildCalculationReportLinesForPeriod`** / **`rebuildCalculationRollupsForPeriod`** и закрытые периоды (**`allowClosedPeriodRollup`**, **`carry-forward-balance.ts`**); подписи кол. **23–24** в UI/CSV; связь с потоком **C** — **`04`** **B.0.4**.
- [x] **Поток B — B.4.3 / B.4.4 / B.1.2 (`04` v **3.60**, `02` v **2.58`):** процедура эталонной сверки (**`04`** §**2**); срез **`02`** §**9**; DDL **`PartnerRule`**, **`PartnerRuleItem`**, **`PartnerAccrual`**, миграция **`20260530250000_partner_rules_accruals`** (*на **3.60** в доке фиксировался только DDL; учёт **`PartnerAccrual`** в витрине — **`04`** **3.62** / **`partner-accrual-report-lines.ts`**.)*
- [x] **H.1 (`04` v **3.61**, `02` v **2.59`):** синхронизация §**1**/§**3** **`04`** и §**2.1**/§**6.1** **`02`** со **`schema.prisma`**, **`partner_*`**, индекс **`Application[siteAccountingObjectId]`**, статусы **Epic 3–5** без противоречий с **3.60**.
- [x] **H.2** минимальный CI: **`.github/workflows/ci.yml`**, **`npm run ci`** (**`04`** v **3.27**; контрольная запись документации — v **3.28**; шаг allowlist — **3.49**; шаг **`npm run test`** — **3.67**).
- [x] **H.3** аудит мутаций: **`audit-action-wrapper.ts`**, **`generateChargesFromEvents`** / **`generateDwellChargesForOrder`** на **`withAuditedServerAction`**, **`describeAuditLogDetails`** (**`04`** v **3.29**, **`02`** v **2.30**); пост-**MVP** **`Application`** и согласование **`02`**/**`04`** без противоречий — **`04`** v **3.31**, **`02`** v **2.32**.
- [x] MVP **§5.2.0** в коде: **`Application`** / **`ApplicationWagon`**, **`WagonStay.sourceInApplicationId`** / **`sourceOutApplicationId`**, **`/references/applications`**, миграция **`20260530120000_application_wagon_stay_source_links`** — задокументировано в **`02`**, **`04`** Epic 2 (**`04`** v **3.30**–**3.31**).
- [x] Миграции отражены в **`02`** при изменении схемы (**v2.26** и далее, в т.ч. **v2.31**–**v2.39**; **v2.39** — таблица **`CalculationRollupLine`**). **v2.40** — срез MVP главного отчёта «Расчёт за период» (без новых таблиц Prisma). **v2.41** — контрольная сверка §2.1 с **`schema.prisma`** (индекс **`ChargeLine[orderId]`**, отчётные маршруты). **v2.42** — инвариант ручной пересборки **`CalculationRollupLine`** и backlog п. **1** Epic 3 (**`04`** **3.41**). **v2.43** — индексы **`ChargeLine[serviceId]`**, **`[wagonStayId]`** и ориентир Analytics в **`schema.prisma`** (**`04`** **3.42**). **v2.44** — **H.1** повторно: **`WagonStayEvent`**, **`ApplicationWagon`** в §2.1 как в Prisma, сверка отчётных модулей (**`04`** **3.43**). **v2.45** — автопересборка свода при типовых мутациях **`ChargeLine`** (**`04`** **3.46**). **v2.46** — **`CarryForwardBalance`**, миграция **`20260530220000_carry_forward_balances`**, перенос свода / отчёт (**`04`** **3.47**). **v2.47** — док. аудита **`carryForwardRollupBalances`** (**`04`** **3.48**). **v2.48** — поток **A**: автосвод при **`link`/`unlink` размещения**, **`Order` → `CANCELLED`**, allowlist **`check-charge-line-mutations.mjs`** (**`04`** **3.49**). **v2.49** — сверка §2.1 с Prisma (**`OrderWagon`**, **`CalculationPeriod`**, **`Application`**) — **`04`** **3.50**. **v2.51** — **`CalculationReportLine`**, миграция **`20260530230000_add_calculation_report_lines`**, **`billToPartyKey`**, правки SQL **MySQL** в **`20260530210000_*`** / **`20260530220000_*`**. **v2.52** — уточнение §2.1 (**`User.chargeLines`**, **`Application.orders`**, коллекции **`calculationReportLines`**, список заявок). **v2.53** — JSON **`reportSource`** (**`20260530240000_calculation_report_line_source`**). **v2.54**–**v2.55** — витрина: **`rebuildCalculationReportLinesForPeriod`**, **`getPeriodCalculationReport`** из **`CalculationReportLine`**. **v2.56** — **B.2.2** (маржа **23–24**). **v2.57** — **B.2.3**, **B.4.2**, **B.0.4**. **v2.58** — **B.4.3**, **B.4.4**, **B.1.2** (**`partner_*`**, **`20260530250000_partner_rules_accruals`**). **v2.59** — **H.1** после **3.60** (детализация **`partner_*`**, **`Application[siteAccountingObjectId]`** в §**2.1**). **v2.60** — **B.5** в бэклоге (**`04`** **3.64**; *закрыто продуктово — **3.71***). **v2.61** — **H.1** (**`04`** **3.66**). **v2.62** — **B.6.1** / §**6.1** (**`04`** **3.67**). **v2.63** — **H.1** повторная сверка доков (**`04`** **3.68**). **v2.64** — **B.2.4**: идемпотентность пересборки витрины (**`04`** **3.69**). **v2.65** — **B.1.3**: **`CarryForwardBalance`** отдельно от витрины (**`04`** **3.70**). **v2.66** — **B.5**, **`vitrine-dashboard`**, Excel/PDF (**`04`** **3.71**). **v2.67** — **H.1** (**`04`** **3.72**); **v2.68** — **H.1** / **Epic 6** (**`04`** **3.73**); **v2.69** — **H.1** (**`04`** **3.74**, *снимок до загрузчика **4.2***); **v2.70** — **MVP 4.2** (**`04` 3.75**); **v2.71** — **4.3** черновик + **`parity-export-diff`** (**`04` 3.76**). **v2.72** — **`charge-lines-control-v0`** (**`04` 3.77**). **v2.73** — **H.1** полная сверка задач и доков (**`04` 3.78**). **v2.74** — **H.1** + продукт **4.3** (**`charge-lines-import-v0`**, **`/references/charge-lines-import`**) + **`Application.createdByUserId`** (**`04` 3.79**, **`20260430260000_application_created_by_user`**, *см. дубликат **`20260430260000_*`** в **`02` 2.74*). Контрольный **`npm run build`** / **`npm run ci`** — **30.04.2026** (успешно).

- [x] **H.1 (`04` v **3.79**, `02` v **2.74`):** **`charge-lines-import-v0.ts`**, **`/references/charge-lines-import`**, **`importChargeLinesControlV0`**; миграция **`20260430260000_application_created_by_user`**; **`wagon-stay-interval-overlap.ts`**; **`TODO`** / **`04`** / **`02`** / этот файл / **`project-handoff`** / **`development-plan-and-backlog`** без противоречий с фактами; **`npm run ci`**.
- [x] **H.1 (`04` v **3.78**, `02` v **2.73`):** **`TODO`** / **`04`** / **`02`** / **`development-plan.md`** (этот файл) / **`development-plan-and-backlog`** / **`project-handoff`**; **`prisma/migrations`** (на срезе **3.78** последняя по партнёру — **`20260530250000_partner_rules_accruals`**), **`src/lib/import/*`**; **`npm run ci`**.
- [x] **H.1 (`04` v **3.77**, `02` v **2.72`):** **`charge-lines-control-v0.ts`**, **`charge-lines-control-v0.test.ts`**, **`import-charge-lines-v0.md`** §6; **`TODO`** / **`04`** / **`02`** / **`project-handoff`**; DDL без изменений (**`20260530250000_partner_rules_accruals`** — последняя).
- [x] **H.1 (`04` v **3.76**, `02` v **2.71`):** док. **`import-charge-lines-v0.md`**, **`parity-export-diff`**, **`week-3-4-plan-4-3-4-5.md`**; **`TODO`** / **`04`** / **`02`** / **`project-handoff`**; DDL без изменений (**`20260530250000_partner_rules_accruals`** — последняя).
- [x] **H.1 (`04` v **3.75**, `02` v **2.70`):** **MVP 4.2** — **`/references/nsi-import`**, **`nsi-site-chain-v0`**; **`TODO`** / **`04`** / **`02`** синхронизированы.
- [x] **H.1 (`04` v **3.74**, `02` v **2.69`):** *исторический снимок до **3.75**:* **`prisma`** без **`import_write`**; **`src/lib/import/*`** и **`/references/nsi-import`** в **`src/`** ещё не были реализованы (см. **`04` 3.75**).
- [x] **H.1 (`04` v **3.73**, `02` v **2.68**):** док. Этапа **4.1** (**`import-spec.md`**, **`fixtures/import/nsi_site_chain_pilot.csv`**) и пакет **4.4** (**`parity-4-4-meeting-pack.md`**, проект **`protocol-parity-4-4.md`**); Prisma без изменений.
- [x] **H.1 (`04` v **3.72**, `02` v **2.67`):** синхронизация **`02`**/**`04`**/**`TODO`**/**`development-plan`**/**`project-handoff`** со схемой и кодом (без новых миграций); §**2** Этап 3, **Epic 3–5**, «Ближайший спринт» согласованы с **B.5**, **`vitrine-dashboard`**, Excel/PDF (**3.71**).
- [x] **B.2.4 (`04` v **3.69**, `02` v **2.64`):** полная замена **`CalculationReportLine`** за период + детерминированный **`aggregatePeriodCalculationReportLines`**; JSDoc **`calculation-report-line-build.ts`**, **`period-calculation-report.ts`**; **`02`** §**5.4**; тест **`period-calculation-report-margins.test.ts`**.
- [x] **B.1.3 (`04` v **3.70**, `02` v **2.65`):** **`CarryForwardBalance`** — отдельный слой **`carry_forward_balances`**; отчёт — **`carry-forward-report-lines.ts`**, **`reportSource`**; свод — **`charge-period-rollup.ts`**; унификация без отдельной таблицы — **backlog**; **`02`** §**5.4**, §**2.1**; JSDoc **`carry-forward-report-lines.ts`**.

---

## Спринт 3 и далее (эскиз)

После приёмки Спринта 2 детализацию Спринта 3 и дорожную карту уточняем по **`04`** §2–3 (агрегаты **`calculation_lines`**, событийные услуги, отчёт «Расчёт за период»). **WagonStay**-события, расширение **`ChargeLine`** и правило **вагон-суток включительно** закрываются в **Спринте 2** (темы F–G); **дополнение:** **`chargeSide`** и раздельные базы отстоя по **`OP_FINISHED`** — **`04`** v **3.32**; канонические **`periodId`** и **`CalculationPeriod`** — **`04`** v **3.33–3.34**. Здесь — следующий слой (отчётность, партнёры, импорт).

**Крупные блоки (без детального чеклиста до фиксации объёма Спринта 2):**

- **Поток B (рабочий чеклист):** **`TODO.md`** «Поток B (Epic 4–5)» — фазы **B.0**–**B.6** (целевые **`calculation_lines`**, **`02`** §5.4, маржа **03** кол. **23–24**, партнёры, паритет «Новая таблица (5).xlsx»); сводка — **`04`** §**3.0б** (**v3.51**).
- Полный отчётный и партнёрский контур (**`04`** Epic 4–5), импорт и дашборды (**`04`** §4 и roadmap).