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

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

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

namespace Ban.Sdaid.Icd.Arch.Tech.Angular
{
    /// <summary>
    /// ADR-UI-001: Технологический стек фронтенда ICD. Фиксирует фреймворк, подход к
    /// компонентам (собственный набор вместо готового UI-kit), вспомогательные пакеты и
    /// явный список того, что сознательно не используется.
    /// </summary>
    public class ADR_UI_001_Stack : IAdrDocument, IFolder<ArchAngularFolder>
    {
        public string Name => "ADR-UI-001. Технологический стек фронтенда";

        public string Description =>
            @"Запускается фронтенд ICD (`src-ui`). Нужно зафиксировать **базовый стек** UI: фреймворк,
подход к компонентной базе, вспомогательные пакеты — и явно обозначить, что используется, а что
сознательно **не** включается. Ключевая особенность: компонентную базу строим **свою**, а не берём
готовый UI-kit, с прицелом на переиспользование набора в других проектах.";

        public string Version => "1.0";
        public string Status => "accepted";
        public string[] Comments => new[]
        {
            "2026-08-11. Принято при разворачивании каркаса фронтенда ICD.",
        };

        public Type? Supersedes => null;

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

            Фронтенд ICD — тонкий клиент (браузерное веб-приложение), запускается с нуля, наследия нет.
            Нужно зафиксировать базовый стек, чтобы дальнейшие решения принимались осознанно, а не по
            инерции.

            Дополнительное требование, определяющее выбор: компонентную базу (от элементарных кнопок и
            полей до крупных таблиц с сортировкой и редактированием ячеек) хотим сделать **своей** и
            переиспользуемой в других проектах. Это прямой довод против готового UI-kit как фундамента —
            иначе каждый проект-потребитель тянул бы за собой стороннюю библиотеку и её визуальный язык.
            """;

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

            1. **Актуальность** — новый проект стартует на самой свежей стабильной версии Angular.
            2. **Переносимость своего UI-набора** — компоненты должны безболезненно выноситься в другой
               проект (целиком или по одному), без завязки на доменный код и без чужой темы.
            3. **Контроль над визуалом и API** — свой дизайн-язык и свой контракт компонентов, а не
               адаптация под чужую тему.
            4. **Минимум зависимостей** — каждая внешняя библиотека несёт цену поддержки; подключаем
               только то, что дорого и рискованно писать самим.
            5. **Покрытие официальной документацией** — стек опирается на Angular и его CDK, без редких
               пакетов.
            """;

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

            - **A. Готовый UI-kit** (ng-zorro / Angular Material / PrimeNG). Быстрый старт, но навязывает
              сторонний визуальный язык и делает будущую библиотеку компонентов обёрткой над чужой
              зависимостью — против цели переносимости.
            - **B. Собственный набор компонентов на headless-фундаменте `@angular/cdk`.** Свой визуал и
              API; CDK закрывает дорогую механику (overlay, a11y, sticky-таблица, virtual-scroll,
              drag-drop) без навязывания внешнего вида.
            - **C. Собственный набор полностью без зависимостей** (даже без CDK). Максимальная
              независимость, но overlay-позиционирование, focus-trap и a11y легко реализовать
              некорректно — высокий риск при небольшой выгоде.
            """;

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

            Выбран **Вариант B**: Angular (последний стабильный) + собственный набор компонентов на
            `@angular/cdk`, без готового UI-kit.

            ### Базовые зависимости

            | Пакет | Версия | Назначение |
            |---|---|---|
            | `@angular/*` | `22.x` | Фреймворк. |
            | `@angular/cdk` | `22.x` | Headless-примитивы (overlay, a11y/focus-trap, sticky-таблица, virtual-scroll, drag-drop) — фундамент собственных компонентов, без навязанного визуала. |
            | `rxjs` | `7.x` | Реактивные потоки: HTTP, мост в сигналы (`toSignal`). |
            | `date-fns` | `4.x` | Работа с датами, локаль `ru` (при работе с таймзонами добавляется `date-fns-tz`). |
            | `sass` (SCSS) | — | Препроцессор стилей. Дизайн-токены — на CSS custom properties (тема задаётся переменными снаружи, что и делает набор переносимым). |

            ### Формы

            Формы — на **Signal Forms** (`@angular/forms/signals`), а не на Reactive Forms. Фронт строится
            signals-first: значения и валидность формы — сигналы, без моста к реактивным потокам. В
            актуальной версии Angular это **стабильный публичный API**, так что выбор не противоречит
            драйверу стабильности.

            ### Собственный набор компонентов — принципы переносимости

            Компоненты живут в `src-ui/src/app/ui/` (пока **не** отдельная npm-библиотека), но
            проектируются так, чтобы выноситься в другой проект без переписывания:

            1. Зависимости только «вниз»: Angular, `@angular/cdk`, свои ui-примитивы, дизайн-токены. Ни
               одного импорта из доменного/прикладного кода проекта.
            2. Ноль доменных знаний: данные — через `input()`/generics, поведение — через
               `output()`/колбэки.
            3. Стили на дизайн-токенах (CSS custom properties), без хардкода цветов; тема — снаружи.
            4. Гранулярность и слабая связность: компонент — своя папка со своим barrel; один компонент не
               тянет весь набор.
            5. Единый alias и barrel-экспорты (`@ui/*`) — набор перемещается одним движением.
            6. Минимум внешних зависимостей, standalone-компоненты.

            ### Что не используем

            - **Готовый UI-kit** (ng-zorro / Angular Material / PrimeNG) как компонентную базу — по
              причинам выше.
            - **Глобальный store** (NgRx / `@ngneat/elf`). Состояние компонента — через сигналы;
              разделяемое — через `@Injectable({providedIn:'root'})`-сервисы с сигналами. Store вводим
              только при кейсе, который сервисом не решается.
            - **`@ngneat/until-destroy`** — эквивалент нативного `takeUntilDestroyed()` + `DestroyRef`,
              внешняя зависимость избыточна.
            - **Глобальный event bus** — взаимодействие через сервисы и роутер. Понадобится широковещание
              — заведём отдельный ADR.
            - **Провайдер анимаций** (`@angular/animations` / `provideAnimations`). Анимации — нативными
              CSS-механизмами (`animate.enter` / `animate.leave`) по мере надобности; deprecated-провайдер
              в фундамент не тянем.
            """;

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

            - Полный контроль над визуалом и API компонентов; набор переносим между проектами.
            - Сигналы и `takeUntilDestroyed` — нативно, без сторонних пакетов; меньше зависимостей —
              дешевле апгрейд Angular.
            - CDK снимает самое дорогое и рискованное (overlay, a11y), не навязывая внешний вид.
            """;

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

            - Свой набор компонентов — долгосрочное обязательство: поддержка, a11y, кросс-браузерность,
              документация. Окупается при переиспользовании в нескольких проектах; на одном — дороже
              готового kit.
            - Крупные компоненты (таблица с сортировкой/редактированием, date-picker) пишем сами поверх
              CDK — заметный объём разовой работы.
            - Без глобального store сложные shared-кейсы (если появятся) пишутся руками через сигналы в
              сервисе.
            """;

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

            - Каркас `src-ui` собирается и запускается на Angular 22 (standalone, страница-приветствие),
              без обращения к глобальному store и без готового UI-kit.
            - Первый крупный компонент (таблица) собирается на `@angular/cdk` с сортировкой и режимом
              редактирования ячеек, оставаясь независимым от доменного кода.
            """;

        public static string S8_OpenQuestions = """
            ## Открытые вопросы / отложено

            - **Тестирование** — фреймворк и пакеты не зафиксированы; вероятно `vitest` (идёт с `ng new`).
              Решение отдельным пунктом позже.
            - **Zoneless** — режим change detection Angular 22; свериться с текущим каркасом и
              зафиксировать явно.
            - **Вынос набора в отдельную библиотеку** (npm-пакет / registry) — возможная будущая веха;
              сейчас набор живёт в `ui/`, но проектируется переносимым.
            - **Событийная шина** — вернёмся, если рост числа фич потребует широковещания.
            """;

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

            - {nameof(Ban.Sdaid.Icd.Vision.IcdVision)} — Видение (тонкий клиент, браузерное веб-приложение).
            """;
    }
}