⟨/⟩ 80_Subsystems/Backend/BackendCodeMap.cs

101 строк · в начало

using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd;

namespace Ban.Sdaid.Icd.Subsystems.Backend
{
    /// <summary>
    /// Карта кода backend (src-api): проекты, где какой артефакт, стек, соответствие spec→code
    /// и как запускать. Онбординг — чтобы не грепать дерево кода каждую сессию.
    /// Сейчас backend — каркас (bootstrap) с единственной сквозной операцией; карта отражает
    /// текущее состояние и целевую раскладку, куда лягут артефакты по мере реализации.
    /// </summary>
    public class BackendCodeMap : IApplicationDocument, IFolder<SubsystemsFolder>
    {
        public string Name => "Backend (src-api) — карта кода";

        public string Description =>
            @"Навигатор по реализации backend в src-api: какой проект за что отвечает, где физически лежит
каждый тип артефакта, каков стек и как запускать сервис. Backend в ранней стадии: реализован первый
реальный read-срез (справочники ввода) по CQRS-контракту с единой обёрткой ответа; БД/EF, command-ветка
и аутентификация ещё не введены. Прочитать ПЕРЕД реализацией backend — заменяет разведку по коду.";

        public string Version => "0.2";
        public string Status => "draft";
        public string[] Comments => new[]
        {
            "2026-08-11. Заведено после разворачивания каркаса backend (src-api) — сквозной hello через слои.",
            "2026-08-12. Проверочный hello удалён; реализован первый read-срез «справочники ввода» и единая обёртка ответа (ADR-SRV-001).",
        };

        public static string Projects = """
            ## Проекты (src-api)

            | Проект | Роль |
            |---|---|
            | `Ban.Icd.Api` | Веб-хост ASP.NET Core (net10): `Program.cs` (DI, OpenAPI, контроллеры, enum-как-строка, CORS, HttpClient), `Controllers/`, прикладной слой `Application/`. Сейчас `Application/InputPackets/` (сдача `SubmitInputPacketCommand` — произвольный набор кадров без плана/ролей/идентификаторов, ADR-007; чтение очереди `GetInputQueueQuery`, удаление `DeleteInputPacketCommand`/`ForceDeleteInputPacketCommand`, обработка `NormalizePacketCommand`; `InputPacketController` = POST multipart, GET список, GET содержимое кадра (оригинал/обработанное), POST обработка кадра/пакета, DELETE мягкое/жёсткое); русские подписи идентификаторов — `Application/CaptureLabels`; общая обёртка `Application/CommonModels/` (`IcdBaseRequestResult`, `ErrorDetails`, `ErrorCode`). |
            | `Ban.Icd.Cqrs` | Инфраструктура CQRS: `Queries/` и `Commands/` (`IIcdQuery`/`IIcdCommand` + Handler/Result/Processor), процессоры, `IcdCqrsDiExtension` (`Register{Query,Command}Processor`/`Handlers`). Pipeline-шаги ещё не введены. |
            | `Ban.Icd.Domain` | Доменные сущности и типы. Модуль `Capture/`: enum'ы и сущности пакета `InputPacket`/`ImageFrame`/`PacketIdentifier` (по спеке `50_Domain/Capture`; планы съёмки убраны — ADR-007). |
            | `Ban.Icd.Infrastructure` | Инфраструктура: `IClock`, **доступ к данным** (`Persistence/`: `IcdDbContext` + EF-конфигурации + миграции, EF Core/PostgreSQL), **файловое хранилище** (`Storage/IFileStorage` + `FileSystemFileStorage`) и **нормализация изображений** (`ImageProcessing/IImageNormalizer` + `OrthocoverImageNormalizer` — HTTP-клиент orthocover, multipart, ADR-SRV-005); `AddIcdInfrastructure`. |
            """;

        public static string Stack = """
            ## Стек и текущее состояние

            - **net10**, ASP.NET Core: контроллеры + OpenAPI (`Microsoft.AspNetCore.OpenApi`, эндпоинт `/openapi/v1.json`). Enum сериализуются строкой (`JsonStringEnumConverter`, ADR-SRV-002).
            - **Самописный CQRS** (без MediatR): query- и command-ветки, авто-регистрация обработчиков, без pipeline-шагов. Контроллер зависит от процессора (`IIcdQueryProcessor`/`IIcdCommandProcessor`).
            - **Единая обёртка ответа** — `IcdBaseRequestResult { RequestId?, IsSuccess, StatusCode, Message?, Errors[] }`, полезная нагрузка в `Payload` наследника (ADR-SRV-001).
            - **Персистентность** — EF Core + **PostgreSQL** (`IcdDbContext`, миграции в `Infrastructure/Persistence/Migrations`, строка подключения `ConnectionStrings:IcdDb`). Сущности — по ADR-SRV-003 (enum строкой, FK-каскад).
            - **Файловое хранилище** — `IFileStorage` (диск, `Storage:RootPath`); на стенде заменяется S3/MinIO той же абстракцией.
            - **Нормализация изображений** — `IImageNormalizer` (`OrthocoverImageNormalizer` — HTTP-клиент внешнего orthocover: multipart-запрос, разбор multipart/mixed; ADR-SRV-005). Конфиг `Orthocover:Url`/`ApiKey` (секрет — в `appsettings.Local.json`/env, вне git).
            - **Срезы**: сдача `POST /api/InputPacket` (multipart: произвольный набор кадров без плана/ролей/идентификаторов — ADR-007 → номер `П-ГГГГММДД-NNN` от максимального суффикса за день, ключи хранения `<номер>/<NN>.<ext>` по ADR-002, файлы в хранилище, пакет в БД, состояние `Queued`); чтение очереди `GET /api/InputPacket` (список с составом из БД, мягко удалённые исключены); содержимое кадра `GET /api/InputPacket/{id}/frames/{order}/content` (поток из хранилища; `variant=normalized` — обработанное); обработка `POST /api/InputPacket/{id}/frames/{order}/normalize` (нормализация кадра через orthocover, хранит обработанный PNG; есть и пакетный `.../normalize`); удаление `DELETE /api/InputPacket/{id}` (мягкое — флаг `Deleted`) и `.../force` (жёсткое — запись каскадом + файлы кадров). Русские подписи идентификаторов — `Application/CaptureLabels`. Аутентификация, read/write-split, pipeline, автозапуск обработки (очередь), определение вида ИК/ролей и извлечение полей — **ещё не введены**.
            - **Конфигурация по средам** — `appsettings.json` (`IConfiguration`); CORS-origins фронта из `Cors:AllowedOrigins` (пусто = разрешить любой, локально); Swagger UI только в Development. Конфиги сред генерятся `devops/configs-generator` (ADR-SRV-004).
            - **Централизованные версии пакетов** — `src-api/Directory.Packages.props`.
            - **Solution** — `Ban.Icd.slnx` на корне репозитория; ведётся отдельно от спеки (`sdaid/Ban.Sdaid.sln`), у которой свой процесс сборки-рендера.
            """;

        public static string SpecToCode = """
            ## Соответствие spec → code

            Раскладка спеки (sdaid) и кода (src-api) различаются — целевой маппинг:

            | sdaid (спека) | src-api (код) |
            |---|---|
            | `50_Domain/<Module>/<Entity>` | `Ban.Icd.Domain/<Module>/<Entity>.cs` |
            | `45_Api/Endpoints/<Area>/<Name>` (endpoint + Command/Query + Result) | `Ban.Icd.Api/Application/<Area>/...` + `Ban.Icd.Api/Controllers/<Area>Controller.cs` |
            | `55_Backend/Handlers/<Area>/<Name>Handler` (canonical narrative) | `Ban.Icd.Api/Application/<Area>/<Name>Handler.cs` |
            | `55_Backend/Services/<Area>/<Name>` | `Ban.Icd.Infrastructure/...` или прикладной сервис в `Ban.Icd.Api` |
            | CQRS-контракты (`IIcdQuery`/`IIcdQueryHandler`, процессор) | `Ban.Icd.Cqrs` |
            | ADR бэкенда (`40_Arch/Tech/CSharp/ADR_SRV_001..003`) | конвенции CQRS/обёртки/grid/EF, которым следует код |

            Каждый код-файл реализации несёт XML-`<remarks>` со ссылкой на артефакт спеки sdaid (правило в `CLAUDE.md`). Операции ввода/очереди описаны контрактом в спеке: `45_Api/Endpoints/InputPackets/{SubmitInputPacket, GetInputQueue, DeleteInputPacket, GetFrameContent, NormalizePacket}` (endpoint + команда/запрос + результат), парные `55_Backend/Handlers/...` (сценарии; у GetFrameContent handler-а нет — прямая отдача файла из хранилища); базовые типы — `45_Api/Based`. Внешние интеграции — под своим ADR (нормализация изображений — ADR-SRV-005).
            """;

        public static string Run = """
            ## Сборка и запуск

            ```bash
            dotnet build Ban.Icd.slnx
            # БД: PostgreSQL по строке ConnectionStrings:IcdDb; применить миграции:
            dotnet ef database update --project src-api/Ban.Icd.Infrastructure --startup-project src-api/Ban.Icd.Api
            dotnet run --project src-api/Ban.Icd.Api --urls http://localhost:5080
            # сдача:   POST http://localhost:5080/api/InputPacket   (multipart)
            # очередь: GET  http://localhost:5080/api/InputPacket
            # контракт/UI: /openapi/v1.json, /swagger (Development)
            ```

            Особенности окружения (расположение dotnet SDK, `DOTNET_ROOT` для `dotnet ef`, доступ к PostgreSQL) относятся к конкретной машине разработчика и в спеке не фиксируются.
            """;

        public static string RelatedDocuments = $"""
            ## Связанные документы

            - {nameof(Ban.Sdaid.Icd.Subsystems.Frontend.FrontendCodeMap)} — карта кода фронта; фронт потребляет контракт этого backend.
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.CSharp.ADR_SRV_001_Cqrs)} — CQRS и обёртка ответа, которым следует код.
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.CSharp.ADR_SRV_002_GridQueryContract)} — контракт списочных запросов (для будущих гридов).
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.CSharp.ADR_SRV_003_EntityAndEfMapping)} — правила сущностей и EF (для write-ветки с БД).
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.CSharp.ADR_SRV_004_AppConfigAndCors)} — конфигурация по средам и CORS.
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.CSharp.ADR_SRV_005_ImageNormalizationOrthocover)} — нормализация изображений (orthocover).
            """;
    }
}