⟨/⟩ 40_Arch/Tech/Angular/ADR_UI_013_FeaturePagePattern.cs

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

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

namespace Ban.Sdaid.Icd.Arch.Tech.Angular
{
    /// <summary>
    /// ADR-UI-013: Паттерн страницы фичи. Ядро — per-page service + тонкий компонент; типовые
    /// форматы (grid/card/form) фиксируются концептуально, детали дополняются по мере появления
    /// base-компонентов (Table, Modal, Drawer, Toast).
    /// </summary>
    public class ADR_UI_013_FeaturePagePattern : IAdrDocument, IFolder<ArchAngularFolder>
    {
        public string Name => "ADR-UI-013. Паттерн страницы фичи";

        public string Description =>
            @"Страницы распадаются на повторяющиеся форматы (грид, карточка, форма) плюс специфичные экраны.
Фиксируем ядро паттерна — per-page service и тонкий компонент; детали типовых форматов дописываются в
этот ADR по мере появления соответствующих base-компонентов.";

        public string Version => "0.1";
        public string Status => "accepted";
        public string[] Comments => new[]
        {
            "2026-08-11. Принято ядро (per-page service). Детали форматов дополняются при появлении base-компонентов.",
        };

        public Type? Supersedes => null;

        public static string S1_Context = """
            ## Контекст и постановка задачи

            Если каждый собирает страницу по-своему — нет единообразия загрузки, состояния, ошибок.
            Нужен единый **каркас страницы фичи**: связка «страница ↔ её сервис», формат состояния,
            индикаторы загрузки, показ уведомлений.

            На текущем этапе base-компоненты (таблица, модалка, дровер, тост) ещё не готовы, поэтому
            фиксируем **ядро** паттерна; детали типовых форматов дописываются сюда по мере их появления.
            """;

        public static string S2_DecisionDrivers = """
            ## Драйверы решения

            1. **Единообразие** — одинаковые страницы ведут себя одинаково.
            2. **Локальность** — состояние и логика страницы живут рядом со страницей.
            3. **Тестируемость** — per-page service изолируется как обычный класс.
            4. **Готовность к codegen** — стабильные правила для будущих генераторов страниц.
            """;

        public static string S3_ConsideredOptions = """
            ## Рассмотренные варианты

            - **A. Логика прямо в компоненте** — мало файлов, но компонент разрастается, тесты тяжёлые.
            - **B. Per-page service в `providers` страницы + типовой каркас** — состояние/API/эффекты в
              сервисе; компонент тонкий.
            - **C. Отдельный store на страницу** — требует библиотеки store, которой по ADR-UI-001 нет.
            """;

        public static string S4_DecisionOutcome = """
            ## Решение

            Выбран **Вариант B**.

            ### Ядро (принято сейчас)

            **Per-page service — обязателен** для нетривиальной страницы; регистрируется в `providers`
            страницы:

            - **Жизненный цикл** = жизнь страницы (создаётся при входе, уничтожается при выходе).
            - **Хранит** всё, что нужно нескольким частям страницы, — через сигналы (ADR-UI-008).
            - **Делает** вызовы API + маппинг + побочные эффекты (уведомления и т. п.).
            - **Не делает**: не лезет в глобальное состояние без нужды; не публикует `Subject`-ы другим
              страницам (между страницами — через роутер и общие сервисы).
            - **Имя** — `<Name>PageService`.
            - **Компонент страницы — тонкий**: разметка + делегирование в сервис.

            Тривиальная страница может обойтись без per-page service.

            **Индикаторы загрузки** — сигналы (`loading`, `submitting`) в per-page service; шаблон
            реагирует через `@if`.

            **Уведомления (тосты)** — только через сервис-обёртку `NotifyToast` (единый стиль и место
            конфигурации); прямые вызовы запрещены. Реализация сервиса — при появлении base-тоста.

            ### Типовые форматы (концепция; детали — по мере появления base-компонентов)

            - **Grid (список)** — каркас `icd-page` + таблица + пагинатор (загрузка/сортировка/фильтр).
              *Детали — при появлении base `Table` и утилиты пагинатора.*
            - **Card (чтение)** — `<Name>PageService` грузит сущность в сигнал по `id` из маршрута.
            - **Create/Edit (форма)** — форма на Signal Forms (ADR-UI-009); сервис делает `create`/`update`;
              на submit — валидация → вызов → уведомление + редирект. *Детали дровер-форм и удаления — при
              появлении base `Modal`/`Drawer`.*
            - **Специфичные экраны** (мастер и т. п., напр. «Ввод данных») — вне типовых форматов, но с тем
              же per-page service для состояния.

            ### Чего не делаем

            - Не публикуем `Subject` per-page service наружу другим страницам.
            - Не вызываем уведомления/модалки напрямую — только через обёртки.
            - Не делаем shared-фильтры между страницами — фильтр живёт в per-page service одной страницы.
            """;

        public static string S5_PositiveConsequences = """
            ## Положительные следствия

            - Любая страница собирается из понятных кубиков: page → page-service → формат.
            - Тесты per-page service просты (чистый класс с инжектами).
            - Задел под генераторы страниц.
            """;

        public static string S6_NegativeConsequences = """
            ## Отрицательные следствия и компромиссы

            - На простую страницу ложится оверхед (per-page service, каркас) — для тривиальных допускаем отказ.
            - Часть паттерна (grid/модалки/тосты) пока не детализирована — дополняется по мере появления
              base-компонентов, до тех пор эти форматы собираются вручную.
            """;

        public static string S7_Validation = """
            ## Проверка

            - Per-page services регистрируются в `providers` страницы, не в `root`.
            - Компонент страницы — тонкий; состояние и вызовы API — в сервисе.
            - Тосты — только через `NotifyToast`; индикаторы загрузки — через сигналы сервиса.
            """;

        public static string S8_OpenQuestions = """
            ## Открытые вопросы / отложено (дополнить при появлении base-компонентов)

            - **Grid-формат** — детали таблицы и пагинатора (загрузка/сортировка/фильтр, empty-state) —
              при появлении base `Table`.
            - **Модалки/дроверы** — формат create/edit в дровере и удаление через confirm-модалку — при
              появлении base `Modal`/`Drawer`.
            - **Тосты** — реализация сервиса `NotifyToast` — при появлении base-тоста (overlay).
            - **API/маппинг** — связка per-page service ↔ API — отдельным ADR при появлении контракта API.
            - **Права** — видимость действий (меню строки, кнопки) — при появлении auth/claims.
            """;

        public static string S99_Related = $"""
            ## Связанные артефакты

            - {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_003_ProjectStructure)} — размещение фичи и сервиса.
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_005_Layout)} — каркас страницы (page/header/body).
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_008_State)} — состояние в per-page service.
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_009_Forms)} — формы create/edit.
            """;
    }
}