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

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

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

namespace Ban.Sdaid.Icd.Arch.Tech.Angular
{
    /// <summary>
    /// ADR-UI-003: Физическая структура проекта src-ui — тематические папки верхнего уровня,
    /// плоские фичи, самодостаточный переносимый набор ui/ с дизайн-токенами, TS-алиасы.
    /// </summary>
    public class ADR_UI_003_ProjectStructure : IAdrDocument, IFolder<ArchAngularFolder>
    {
        public string Name => "ADR-UI-003. Структура проекта src-ui";

        public string Description =>
            @"Каркас `src-ui`, созданный `ng new`, минимален. По мере роста (страницы, сервисы, компоненты,
модели, гарды) нужен предсказуемый **физический** layout: чтобы человек и ИИ одинаково находили место
для нового кода, а генераторы опирались на стабильные пути. Учитываем переносимость набора `ui/` и
отсутствие внешнего UI-kit.";

        public string Version => "1.0";
        public string Status => "accepted";
        public string[] Comments => new[]
        {
            "2026-08-11. Принято следом за ADR-UI-002.",
        };

        public Type? Supersedes => null;

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

            Нужен предсказуемый физический layout `src-ui`, чтобы:

            - человек и ИИ-ассистент одинаково находили место для нового кода;
            - генераторы/skills опирались на стабильные пути;
            - структура не разъезжалась при добавлении фич.

            Две особенности ICD, отличающие раскладку от типовой: собственный **переносимый** набор
            компонентов `ui/` (должен быть самодостаточным, включая дизайн-токены) и **отсутствие**
            внешнего UI-kit (нет `antd-overrides` и подобного).
            """;

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

            1. **Единственная ответственность папок** — каждая папка верхнего уровня имеет понятное
               назначение, новый код легко классифицировать.
            2. **Плоские модули** — никакой группировки `modules/<group>/<feature>/`; навигационная
               группировка живёт в меню, не в файловой системе.
            3. **Lazy loading** — каждая фича `modules/<feature>/` подключается ленивыми маршрутами.
            4. **Стабильные пути** — для автоматизации и предсказуемого ревью.
            5. **Самодостаточность `ui/`** — набор с токенами переносится в другой проект целиком, без
               внешних стилевых зависимостей.
            """;

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

            - **A. Тематические папки верхнего уровня + плоские фичи** — `app/{consts, directives, guards,
              models, modules, pipes, services, ui, utils}`, фичи рядом в `modules/`.
            - **B. Двухуровневые модули** — `modules/<group>/<feature>/`; навигационная группировка
              дублируется в файловой системе.
            - **C. Feature-first** — каждая фича со своими `services/components/models` обособленно, без
              общих тематических папок.
            """;

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

            Выбран **Вариант A**. Папки создаются **по мере надобности** (не заводим пустые заранее);
            назначение каждой зафиксировано ниже. Именование файлов — по стилю Angular 22 без суффиксов
            (см. ADR-UI-002).

            ### Дерево верхнего уровня (целевое)

            ```
            src-ui/
            └── src/
                ├── app/
                │   ├── consts/         # Глобальные константы
                │   ├── directives/     # Атрибутивные/структурные директивы
                │   ├── guards/         # CanActivate-гарды
                │   ├── models/         # Общие модели (Option, Pagination, Sorting, …)
                │   ├── modules/        # Фичи (плоско, см. ниже)
                │   ├── pipes/          # Глобальные pipe-ы
                │   ├── services/       # Singleton-сервисы (root)
                │   │   ├── api-clients/  # Клиенты к backend (генерируемые; см. ADR про API)
                │   │   └── router/       # Реестры маршрутов
                │   ├── ui/             # Собственный переносимый набор компонентов (см. ниже)
                │   ├── utils/          # Чистые функции
                │   ├── app.ts
                │   ├── app.config.ts
                │   ├── app.routes.ts
                │   └── app.const.ts
                ├── styles/
                │   └── theme/          # Переопределения токенов набора под проект (тема)
                ├── styles.scss         # Точка входа стилей (подключает токены ui/ и styles/theme/)
                ├── index.html
                └── main.ts
            ```

            ### Набор `ui/` — самодостаточный и переносимый

            ```
            app/ui/
            ├── tokens/            # Дизайн-токены (CSS custom properties): палитра, отступы, типографика.
            │                      #   Едут ВМЕСТЕ с набором — часть его контракта.
            ├── <component>/       # Папка на компонент (button/, table/, …): <name>.ts|html|scss + index.ts
            └── index.ts           # Общий barrel набора
            ```

            Набор зависит только «вниз» (Angular, `@angular/cdk`, свои токены) и не импортирует доменный
            код (см. ADR-UI-002, принципы переносимости).

            ### Структура папки фичи (`modules/<feature>/`)

            ```
            modules/<feature>/
            ├── components/         # Под-компоненты страниц
            ├── models/             # Доменные UI-модели фичи
            ├── pages/
            │   └── <page>/
            │       ├── <page>.ts
            │       ├── <page>.html
            │       └── <page>.scss
            ├── services/           # Per-page сервисы (регистрируются в providers страницы)
            └── <feature>.routes.ts # Ленивые маршруты фичи
            ```

            ### Принципы организации

            1. **Модули — плоско.** Никакого `modules/<group>/<feature>/`; группировка — только в меню.
            2. **`ui/` — переиспользуемые виджеты**, не привязанные к фиче; самодостаточны (с токенами).
            3. **`services/` (app) — только глобальные** singleton + `api-clients/` и `router/`. Per-page
               сервисы — в `modules/<feature>/services/`.
            4. **`models/` (app) — только общие**; доменные — в фиче.
            5. **Без `store/`** — глобального store нет (ADR-UI-001).

            ### Стили и кастомизация набора

            - Стили — SCSS; дизайн-токены — CSS custom properties в `app/ui/tokens/` (переносятся с набором).
            - **Кастомизация под проект — переопределением значений токенов** в `src/styles/theme/`: меняет
              тему глобально, компоненты не трогаются (чистая замена подхода «antd-overrides»).
            - **Точечная кастомизация** — через component-scoped переменные, которые компонент осознанно
              экспонирует (`--icd-<component>-<prop>`). Инкапсулированные стили компонентов снаружи не
              «ломаем» (ViewEncapsulation) — только предусмотренные переменные.

            ### TS-алиасы (`tsconfig.json`)

            ```jsonc
            {
              "compilerOptions": {
                "paths": {
                  "@app/*": ["src/app/*"],
                  "@api/*": ["src/app/services/api-clients/*"],
                  "@ui/*":  ["src/app/ui/*"]
                }
              }
            }
            ```

            Алиасы обязательны для всего, что вне текущей папки фичи — импорты устойчивы к рефакторингу
            путей. Для набора `ui/` алиас `@ui/*` дополнительно облегчает будущий вынос в библиотеку.

            ### API-клиенты

            Место — `app/services/api-clients/<context>/`. Список контекстов и способ генерации клиента из
            backend-контракта уточняются отдельным ADR при появлении API; сейчас фиксируется только место.
            """;

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

            - Плоские `modules/` исключают споры «куда положить фичу»; тематические папки дают однозначное
              место каждой роли кода.
            - Набор `ui/` самодостаточен (компоненты + токены) — переносится и кастомизируется без правки
              компонентов.
            - Алиасы делают импорты независимыми от глубины фичи и устойчивыми к рефакторингу.
            """;

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

            - При росте числа фич `modules/` содержит много одноуровневых каталогов — решается навигацией
              IDE, не структурой.
            - Доменные модели рассыпаны по `modules/*/models/` — цена изоляции фич.
            - Кастомизация только через токены и предусмотренные переменные требует, чтобы компоненты
              заранее экспонировали нужные «хуки» — дисциплина при дизайне API компонента.
            """;

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

            - Новая фича добавляется как `modules/<feature>/{components, models, pages, services,
              <feature>.routes.ts}` без правки верхнего уровня.
            - Любой виджет из `ui/` используется из любой фичи без циклических зависимостей и без импорта
              доменного кода.
            - Смена палитры/отступов выполняется правкой `src/styles/theme/`, без изменения компонентов.
            """;

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

            - **API-контексты** и способ генерации клиентов из backend-контракта — отдельным ADR при
              появлении эндпоинтов.
            - **`validators/`** — пока не заводим; появится с первыми формами (на Signal Forms).
            """;

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

            - {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_001_Stack)} — Технологический стек фронтенда.
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_002_NamingAndConventions)} — Именование и конвенции.
            """;
    }
}