Specs security / security (push) Successful in 8s
Specs verify / verify (push) Successful in 11s
Conventional commits / commits (pull_request) Successful in 12s
Specs security / security (pull_request) Successful in 7s
Specs verify / verify (pull_request) Successful in 11s
441 lines
43 KiB
Markdown
441 lines
43 KiB
Markdown
## Context
|
||
|
||
Локальная архитектура реализована; независимая публикация отложена. Baseline исследования — frontend `3c99deb`, версия `0.3.0`,
|
||
2026-09-20. Требования — в
|
||
[proposal](proposal.md) и [delta](specs/frontend-design-system/spec.md).
|
||
|
||
В приложении уже работают React, TypeScript, Vite, Mantine, TanStack Query,
|
||
RHF/Zod, JSON-токены, общий адаптер темы, Storybook, Vitest/RTL/MSW,
|
||
dependency-cruiser и Knip. Они сохраняются. Другие production-потребители
|
||
общего UI или клиентского SDK в исследованном workspace не обнаружены.
|
||
|
||
На 2026-09-22 workspace-пакеты `@wealthledger/tokens`, `@wealthledger/ui` и
|
||
`@wealthledger/icons` используются локально как private packages. Это принятая
|
||
часть перехода. Описанные далее независимый release и Nexus остаются
|
||
предложением, отложенным до оценки пилота. Фактическое выполнение и ограничения
|
||
сохраняются в [tasks](tasks.md).
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:** три небольшие границы поставки общего фундамента; единый каталог
|
||
источников; сохранение внешнего вида и предметных инвариантов; потребление
|
||
собранного пакета; ограниченные задачи, исполнимые по одной сессии.
|
||
|
||
**Non-Goals:** другой UI framework, второй transport/store/form stack,
|
||
универсальные CRUD/table/form engines, монорепозиторий всего WealthLedger,
|
||
mobile adapter, тёмная тема, массовый rewrite CSS и тестирование внутренностей
|
||
Mantine. Календарь платежей требует отдельного продуктового запроса.
|
||
|
||
## Decisions
|
||
|
||
### 1. Репозиторий и направления зависимостей
|
||
|
||
Рекомендация: **npm workspaces внутри существующего frontend**. Корневое
|
||
приложение сохраняет `src`, Vite entry, собственные providers и `private: true`.
|
||
Новые пакеты располагаются в `packages/tokens`, `packages/icons`, `packages/ui`.
|
||
Имена `@wealthledger/*` приняты для локальных packages; регистрация scope
|
||
и внешняя registry-поставка не подтверждены.
|
||
|
||
| Вариант | Польза | Цена в этом проекте | Решение |
|
||
| --- | --- | --- | --- |
|
||
| Три workspace-пакета в frontend | Один lockfile, toolchain, Storybook и атомарный review источников с потребителем | Нужно явно расширить scopes проверок; локальный link может скрыть дефект поставки | Выбран; обязательна проверка packed consumer |
|
||
| Один отдельный design-system repo с тремя пакетами | Отдельный owner, release cadence, независимые потребители | Новый CI/catalog/install, синхронизация PR и доступа к registry при одном приложении | Отложить до второго независимого production consumer либо отдельного владельца/release cadence |
|
||
| Три отдельных Git repo | Полностью независимые права/жизненные циклы | Три workflow и совместимость без подтверждённой выгоды | Не выбирать |
|
||
| Только существующий shared | Уже работает, нет стоимости публикации | Не даёт запрошенной границы версионируемой поставки | Сохраняется до готовности package foundations, не конечная цель |
|
||
|
||
Направление стрелки — «потребляет»; циклов нет:
|
||
|
||
```text
|
||
frontend app / единственный Storybook
|
||
├─ @wealthledger/ui ── @wealthledger/tokens
|
||
│ └─ Mantine + React (peers у ui)
|
||
├─ @wealthledger/icons ── React (peer)
|
||
└─ entities/features/pages → shared/api, domain models, i18n
|
||
|
||
tokens → нет runtime dependencies
|
||
ui → нет icons dependency до появления реального общего consumer
|
||
icons → нет ui/tokens/Mantine/router/API dependencies
|
||
```
|
||
|
||
Общие компоненты принимают уже подготовленные строки и slots. `EntryCard`
|
||
принимает `ReactNode` и не знает, какой пакет рисует icon/action. Domain выбирает
|
||
цвет по смыслу и форматирует деньги; UI только отображает переданное значение.
|
||
|
||
### 2. Публичная поверхность и сборка
|
||
|
||
Имена ниже в колонке «Цель» — принятые публичные exports локальных пакетов.
|
||
Внутренние `src`, `dist/*` и application alias `@/` не являются package API.
|
||
|
||
| Пакет | Цель / entrypoints | Состав поставки | Зависимости |
|
||
| --- | --- | --- | --- |
|
||
| tokens | `@wealthledger/tokens/tokens.json` | Доверенный JSON v1; JS, CSS, React-адаптер и `.d.ts` на старте не нужны | Нет runtime dependencies |
|
||
| icons | Именованные `AddIcon`, `EditIcon`, `DeleteIcon` из `@wealthledger/icons` | ESM JS + declarations; CSS только если переносится собственная анимация | React peer + external; React DOM не используется |
|
||
| ui | `@wealthledger/ui`: `StateView`, `LoadingSkeleton`, `EntryCard` и их необходимые props types; `@wealthledger/ui/theme`: `theme`, `colorRoles`, `cssVariablesResolver`; `@wealthledger/ui/styles.css` | ESM JS + declarations + собранный CSS, включая CSS Modules | React/React DOM и используемые Mantine core/hooks — peers/external; tokens — точная dependency |
|
||
|
||
`designTokens` нужен foundations story: адаптер может сохранить существующий
|
||
одноимённый export из `ui/theme`, который ссылается на JSON, а не копирует его.
|
||
JSON остаётся отдельно доступным без Mantine. Не добавлять JS-обёртку в tokens
|
||
только ради импорта JSON. Не выдавать non-web adapter за готовый.
|
||
|
||
Использовать установленный Vite для library build ui/icons и TypeScript для
|
||
declarations. Один `tsc` недостаточен для CSS Modules `EntryCard`. Формат — ESM;
|
||
CJS/SSR build не нужен текущему Vite SPA. Настройки library build ещё предстоит
|
||
проверить на зафиксированной Vite 8.3.0; готовых конфигураций здесь нет.
|
||
Публикуемые `files`/`exports` ограничивают поверхность. CSS явно включается в
|
||
side effects; JS импорт сам не устанавливает provider и не читает приложение.
|
||
Library build использует отдельную конфигурацию нужных plugins, не наследует
|
||
app Vite config целиком: PWA/manifest/service worker и dev API proxy не должны
|
||
попасть в поставку библиотеки.
|
||
|
||
Exports указывают на собранные artifacts, поэтому обычные local/CI entrypoints
|
||
сначала собирают packages, затем выполняют consumer typecheck/tests/build.
|
||
Сейчас `verify` начинает проверки до app build; этот порядок потребуется
|
||
дополнить при 2.2. Acceptance начинается на чистом checkout после `npm ci`,
|
||
без старого package dist/cache. Достаточно последовательности npm scripts,
|
||
без собственного build orchestrator.
|
||
|
||
Docker — отдельный потребитель workspace: нынешний `Dockerfile` копирует только
|
||
root manifests перед `npm ci`, а `.dockerignore` не допускает packages.
|
||
В 2.1–2.2 нужны точечные manifests/source/build-config allowlists, установка
|
||
с workspace manifests и package build перед consumer. Host node_modules,
|
||
готовый локальный dist и реальные `.env` в контекст не попадают. Development
|
||
и production targets проверяются отдельно. В текущем Compose монтируются
|
||
только app src/public: изменения packages сначала требуют rebuild dev image.
|
||
Отдельный package bind-mount/watch в Compose отложен до фактической потребности;
|
||
host development может использовать package watch без изменения root repo.
|
||
|
||
Сначала peer ranges узкие, по проверенной комбинации React 19.3.0 и Mantine
|
||
9.6.1; расширять их только после проверки потребителя. React/React DOM
|
||
devDependencies для разработки не должны попадать в bundle. Проверять
|
||
`npm ls react react-dom @mantine/core` и содержимое bundle/packed consumer;
|
||
`dedupe` не заменяет корректную упаковку. Две несовместимые версии Mantine
|
||
также нельзя скрыть локальным symlink.
|
||
|
||
### 3. Токены: использовать уже существующий JSON
|
||
|
||
В [tokens.json](../../../../frontend/packages/tokens/tokens.json) уже есть
|
||
переносимые значения и описания. **Не менять формат v1 ради упаковки.**
|
||
`primitive → semantic → component` — модель владения и ссылок, а не повод
|
||
немедленно переименовать все ключи в новый стандарт.
|
||
|
||
| Уровень | Текущая основа и целевое правило |
|
||
| --- | --- |
|
||
| Primitive | `color.base`, `color.palettes`, `typography`, `spacing.values`, `radius.values`, `shadows.values`, `breakpoints.values`; исходные эффективные значения сохраняются |
|
||
| Semantic | Существующие `color.roles.*` с `color` + `shade` ссылаются на primitive; `primary` с `shade: null` сохраняет разрешение через primaryShade |
|
||
| Component | Пока новые не нужны. Добавлять только именованный совместно управляемый контракт реального общего компонента, если semantic role недостаточно; ссылаться на semantic, затем primitive при отсутствии смысловой роли |
|
||
|
||
Имена описывают роль (`surface`, `border`, `positive`), а не экран или случайный
|
||
цвет. Ссылки однонаправленные и разрешимые; обратных ссылок из primitive на
|
||
semantic/component нет. Новый color role включает назначение и ограничение
|
||
применения. Семантический положительный цвет не вычисляет знак финансовой суммы.
|
||
|
||
Сохранить единицы: размеры/тени в px адаптируются существующими `rem`/`rgba`,
|
||
breakpoints в em не масштабируются, line-height без единицы. Имеющиеся
|
||
[theme tests](../../../../frontend/packages/ui/src/theme.test.ts) защищают
|
||
именно преобразования и ссылки, не каждое значение JSON.
|
||
|
||
Общие CSS-роли `--wl-color-*` производит прежний `CSSVariablesResolver`.
|
||
Spacing/radius/type scales продолжают поступать в Mantine theme и его CSS
|
||
variables. Статическая генерация второго `tokens.css` не нужна: появился бы
|
||
ещё один адаптер и риск расхождения scale. JSON экспортируется без сборочного
|
||
token engine; Style Dictionary, DTCG-converter и runtime schema отложены до
|
||
конкретного внешнего потребителя/формата. Источник остаётся доверенным файлом,
|
||
не внешним пользовательским документом.
|
||
|
||
Светлая схема сохраняется. `primaryShade.dark` не означает готовую dark theme.
|
||
Бизнес-коды, суммы/валюты, московские даты, pagination limits, brand gradients
|
||
`BankCardFace` и случайная геометрия SVG не превращаются в глобальные токены.
|
||
Первое применение semantic roles — точные эквиваленты gray-3/gray-0/green-6/
|
||
red-6 в `EntryCard`; перенос и эта правка идут отдельно.
|
||
|
||
### 4. Mantine, тема и providers
|
||
|
||
`Stack`, `Group`, `Button`, `Paper`, `ActionIcon`, поля, Modal, Dates/Charts
|
||
остаются прямыми импортами Mantine. Изменение defaults решается темой.
|
||
Wrapper нужен только собственному контракту: busy region у `LoadingSkeleton`,
|
||
empty/error composition у `StateView`, layout/image fallback/actions у `EntryCard`.
|
||
|
||
App владеет MantineProvider, DatesProvider, QueryClientProvider, AuthProvider,
|
||
Router и i18n. Storybook имеет свой Mantine/Dates/i18n runtime с той же темой.
|
||
UI не создаёт `WealthLedgerProvider`, не импортирует локализацию продукта и
|
||
не включает app providers. `ui/styles.css` содержит существующую визуальную
|
||
основу и стили общих компонентов; app/preview подключают его явно после
|
||
Mantine CSS. Продуктовые route transitions и bank-card styles остаются в app.
|
||
|
||
Theme Modal transition и глобальная CSS animation сейчас сосуществуют.
|
||
Их визуальный конфликт не доказан. После выделения выбрать один механизм
|
||
открытия по browser comparison, предпочтительно уже настроенный Mantine
|
||
transition; нельзя удалить второй механизм на основании одного сходства кода.
|
||
|
||
### 5. Иконки и движение
|
||
|
||
Начальный набор — реально повторяющиеся plus/pencil/trash из Card/Cards views.
|
||
Имена `AddIcon`, `EditIcon`, `DeleteIcon` — предлагаемая поверхность, не найденные
|
||
exports. Размер задаёт `size` (default 24), геометрия сохраняет `viewBox`, цвет
|
||
получается через `currentColor`. Существующие размеры и strokeWidth 1.5/2
|
||
сохраняются у callers; выравнивание рисунка не совмещается с переносом.
|
||
|
||
Канонический исходник SVG для небольшого набора — **SVG-разметка в именованных
|
||
React-компонентах** `packages/icons/src/svg/<Name>.tsx`. Это один редактируемый
|
||
источник, без параллельных ручных `.svg` и `.tsx`. Отдельные raw SVG-файлы в
|
||
первой поставке не публикуются: non-React consumer пока отсутствует. Если
|
||
потребуются исходные `.svg` как самостоятельный продуктовый артефакт, перенести
|
||
канон в `src/svg/*.svg` и сравнить штатный SVGR CLI с ручным поддержанием;
|
||
не писать собственный генератор. Сейчас ни dependency, ни pipeline для этого
|
||
не нужны. JS/types несут SVG-компоненты, это явно отражено в составе поставки.
|
||
|
||
По умолчанию рисунок декоративный (`aria-hidden`, без фокуса). У standalone
|
||
meaningful icon потребитель задаёт доступное имя и image semantics. У
|
||
`ActionIcon` имя остаётся на действии; SVG не дублирует его. Общий пакет не
|
||
выбирает подпись «редактировать операцию» и не получает DTO.
|
||
|
||
`BankOperationIcon` и `operation-appearance.ts` остаются в entity: mapping
|
||
category/kind → рисунок/цвет/анимация — бизнес-логика. Собственная геометрия и
|
||
движение рисунка могут перейти в icons позже при реальном reuse. Hover/focus
|
||
trigger по сценарию, route transitions, bank/card state остаются приложению.
|
||
Существующий `bind-icon-animation` переиспользуется, если переносится тот же
|
||
animation contract; он не копируется в пакет ради трёх статичных иконок.
|
||
Все переносимые движения обязаны сохранять reduced-motion поведение.
|
||
|
||
### 6. Каталог источников компонентов
|
||
|
||
Порядок поиска: **существующие компоненты приложения → собственная библиотека
|
||
→ Mantine → уже разрешённые dependencies → обоснованное новое решение**.
|
||
Новый компонент появляется у владельца реальной ответственности, а не потому,
|
||
что текущий компонент отсутствует в Storybook. Таблица — компактный маршрут,
|
||
не каталог каждого JSX-узла. Номера обозначают этапы в [tasks](tasks.md).
|
||
|
||
| Назначение | Текущий источник | Целевой источник | Правило применения | Этап |
|
||
| --- | --- | --- | --- | --- |
|
||
| Layout, buttons, inputs, dialogs | `@mantine/core`, `@mantine/dates` | Те же пакеты | Прямые imports; variant/default через theme, не WL-копия каждого primitive | 1, 2 |
|
||
| Цветовые роли, шкалы | `shared/theme/tokens.json` | `tokens/tokens.json` + адаптер `ui/theme` | JSON — значения, адаптер — Mantine, бизнес-смысл — consumer | 2 |
|
||
| Тема/общие стили | `shared/theme` | `ui/theme`, `ui/styles.css` | Одна тема App/Storybook; providers у runtimes | 2 |
|
||
| Busy skeleton region | `shared/ui/LoadingSkeleton` | `ui` | Label и region общие, skeleton shapes принадлежат странице | 3.1 |
|
||
| Empty/error | `shared/ui/StateView` | `ui` | Строки/action props; query/error classification вне UI | 3.1 |
|
||
| Строка с изображением и значением | `shared/ui/EntryCard` | `ui` | Готовые strings/slots, fallback и responsive actions; без money parsing | 3.2–3.3 |
|
||
| Plus/edit/delete | Inline SVG Card/Cards views | `icons` | Named imports; label и disabled у ActionIcon | 4 |
|
||
| Навигация и active route | `shared/ui/AppShell` | `app/ui` | Product shell; не публичный компонент ui-пакета | 1.1 |
|
||
| Карта и её операции | `entities/bank-card` | Там же | `BankCardFace`, `BankOperationIcon`, `BankSummaryView`, `BankCardFields`, `BankFeedback` — domain | Без переноса |
|
||
| Период банковских данных | `entities/bank-card/BankPeriodPicker`, model/period | Там же | Draft/URL/query semantics сохраняются; не универсальный date service | 5, без extraction |
|
||
| Период дохода | `pages/account-income/.../IncomePeriodForm.view` | Та же page; pure helpers в её model | Изолировать story от VM, сохранить validation/submit | 5.3 |
|
||
| Позиции/структура портфеля | `pages/account/ui/components/PositionCard.view`, `PortfolioStructure.view` | Там же | Page-local композиция допустима; не переделывать под EntryCard | Без переноса |
|
||
| Недавние события | `entities/brokerage-event` + Account page | Там же; общий EntryCard из ui | Первый продуктовый пилот, финансовое представление у entity | 3.2 |
|
||
| Общие instrument details | `features/instrument-details` | Там же | Реальный reuse stocks/bonds; typed presentation contract отдельно от общего UI | Без переноса |
|
||
|
||
Последние непакетные источники выбираются через существующие `index.ts`.
|
||
В таблице обозначения `shared/ui/...` описывают файлы до миграции; это не разрешение
|
||
на deep import. Текущие владельцы указаны в колонке цели.
|
||
|
||
### 7. Предметный UI, API и конечные словари
|
||
|
||
Рекомендация: оставить domain UI в `entities/features/pages`. Второй
|
||
производственный consumer, которому нужен тот же стабильный domain contract,
|
||
и отдельный release owner — проверяемое условие рассмотрения business package.
|
||
Storybook не считается таким потребителем. Повторная карточка может потребовать
|
||
переноса page → entity внутри приложения, но не нового npm-пакета.
|
||
|
||
`shared/api` сохраняет snapshot, generated types, typed transport и auth-aware
|
||
boundary. Генерируются **типы**, а не весь handwritten client. Query keys,
|
||
normalization, freshness и invalidation остаются в entity/feature owner;
|
||
не входят ни в generated artifact, ни в ui. Отдельный `api-client` сейчас
|
||
потребовал бы отделить Vite environment, auth/retry lifecycle и query policy без
|
||
второго потребителя. Вернуться к вопросу при втором независимом приложении.
|
||
|
||
Backend остаётся единственным editable HTTP source. Frontend получает
|
||
предоставленный snapshot, локально генерирует и сравнивает declarations;
|
||
соседний backend checkout не становится входом CI. DTO aliases из generated
|
||
`paths` сохраняются. UI form models допустимы, когда отличаются от transport.
|
||
|
||
Для frontend собственных конечных словарей — принятый `as const` + union:
|
||
`enum` несовместим с текущим `erasableSyntaxOnly`. Набор operation kinds можно
|
||
свести у bank entity и проверить через generated `BankOperation['kind']`;
|
||
не объявлять вторую DTO enum. Wire literals сохраняются. `ProblemDetailsDto.code`
|
||
остаётся `string`, unknown code получает fallback; нельзя объявлять закрытый
|
||
список ошибок. Общий `apiErrorCode` извлекает code, одинаковое recovery
|
||
классифицируется ближайшим допустимым owner без обратных FSD imports.
|
||
|
||
### 8. Политика библиотек
|
||
|
||
Версии закреплены в frontend package manifests и lockfile. Решения ниже
|
||
не означают новой установки или обновления.
|
||
|
||
| Область | Сейчас | Решение и причина | Этап |
|
||
| --- | --- | --- | --- |
|
||
| Build/React/Router | Vite, TS, React Compiler, React Router | Сохранить; расширить имеющийся build для library artifacts | 2 |
|
||
| Server/local state | TanStack Query / React state / URL | Сохранить owners; Redux из transitive deps не делает его app store | Все |
|
||
| Forms/validation | RHF, resolvers, Zod | Сохранить; vocabulary у entity, controller/view банковской формы отдельно | 5.2, 5.4 |
|
||
| UI/charts | Mantine; Recharts/react-is обеспечивают peer graph charts | Сохранить, не удалять peer deps из-за отсутствия direct imports | Все |
|
||
| Styles/условные классы | CSS Modules, template/ternary, data-* | Сохранить один этот подход; clsx/classnames не вводить без сложности, которой здесь нет | 3–5 |
|
||
| Icons | Inline SVG | Унифицировать повторяющиеся общие рисунки в малом собственном наборе | 4 |
|
||
| Motion | motion для routes, CSS/native для рисунков | Сохранить по разным владельцам; проверить дублирование Modal отдельно | 5.1 |
|
||
| Dates | Day.js + Mantine Dates + native Date/Intl | Сохранить роль каждого; Moscow/ISO policy остаётся domain/page | 5.3 |
|
||
| Money | String + BigInt cents, display formatters | Сохранить точность и unknown≠zero; decimal library не добавлять | Все |
|
||
| API/errors | openapi-fetch/react-query/typescript | Сохранить; не добавлять axios, второй generator или schema registry | Все |
|
||
| Tests | Vitest/RTL/MSW | Сохранить; `fireEvent` принят, user-event только transitively | 2–5 |
|
||
| Catalog | Storybook 10.6.0 | Один runtime, расширить glob и границы на packages | 2–4 |
|
||
| Quality | Biome, Knip, dependency-cruiser | Дополнить действующие scopes, не ставить Steiger/ещё один analyzer | 1–2 |
|
||
| Browser/visual CI | Принятого E2E runner/visual diff нет | Ручной browser proof пилота; Playwright — при повторяемой browser-only регрессии и владельце CI | Отложено |
|
||
| Release | release-it + native npm + Gitea | Использовать текущий подход, адаптировать workspace releases; Changesets/Lerna не нужны для трёх пакетов | 6 |
|
||
|
||
### 9. Предлагаемое уточнение conventions
|
||
|
||
Это предложения для будущих задач; действующие инструкции сейчас не меняются.
|
||
AGENTS остаётся коротким router, постоянный каталог переносится в подходящий
|
||
раздел existing UI convention/README после подтверждённого перехода.
|
||
|
||
| Владелец правила | Конкретное уточнение | Когда |
|
||
| --- | --- | --- |
|
||
| `.ai/architecture.md` | Package graph вне FSD; src public APIs; app shell; никакого package → app или same-layer обхода | 1–2 |
|
||
| `.ai/conventions/ui.md` | Каталог источников и search order; тема против wrapper; props-only общие компоненты | 2–3 |
|
||
| UI + Storybook | JSON/semantic roles, explicit CSS import, светлая схема, иконки/currentColor/reduced-motion | 2–4 |
|
||
| `.ai/conventions/data.md`, TypeScript/React | Generated vocabulary vs local const unions; errors открыты; package не владеет query state | 5.2 |
|
||
| Engineering/dependencies | Workspace direct deps, peers, exact lock, packed consumer, ограничения exports | 2, 6 |
|
||
| Storybook | Один runtime, colocated package/product stories, новые reachability scopes | 2–3 |
|
||
| Testing | Поведение → риск → минимальная boundary; package artifact contract; browser proof не равен build | 2–3, 6 |
|
||
|
||
### 10. Storybook и проверки
|
||
|
||
Один существующий frontend Storybook показывает `Design System` и `Product`.
|
||
Общие stories переезжают вместе с ui/icons; foundations читают опубликованный
|
||
JSON/адаптер. Product stories остаются рядом с entities/pages. Обновляются
|
||
только globs/aliases/check scopes, не создаётся отдельное приложение каталога.
|
||
Mantine/theme/Dates/i18n уже есть в preview; Query/Auth/API providers не нужны.
|
||
Synthetic props и callbacks сохраняются; MSW остаётся в Vitest, не в worker.
|
||
|
||
| Наблюдаемый контракт | Минимальный способ доказать |
|
||
| --- | --- |
|
||
| JSON → размеры/тени/semantic CSS, unscaled breakpoints | Перенести существующие theme unit tests; не проверять каждый literal |
|
||
| JS/types/CSS/JSON доступны вне workspace | Pack + чистый consumer с type/build/render и без source aliases |
|
||
| EntryCard image fallback, actions при focus/touch | Один небольшой RTL case на собственный fallback/действие, synthetic story и browser review |
|
||
| Деньги/version/idempotency/invalid input | Существующие targeted RTL/MSW tests формы; новые cases только если меняется соответствующая boundary |
|
||
| Query/auth/recovery | Имеющиеся MSW tests; no real backend; не тестировать это через stories |
|
||
| Keyboard/name/reduced motion/narrow layout | Выбранные собственные interactions в browser; примитивные гарантии Mantine не переписывать |
|
||
|
||
`build:catalog` не исполняет `play`; существующий `storybook.test.tsx` проверяет
|
||
лишь выбранные группы. Не обещать screenshot regression по факту сборки.
|
||
Snapshot всех компонентов и полный новый E2E stack не планируются.
|
||
|
||
Новые workspace-папки не охвачены автоматически: нынешние TS/Knip/deps/story
|
||
настройки главным образом ориентированы на `src`. Package type/build/lint,
|
||
dependencies и запрет app imports вводятся вместе с соответствующим пакетом.
|
||
Нельзя временно исключить packages целиком и назвать gate полным. Same-layer
|
||
rule сначала проверяется на текущем graph, затем включается для чистого scope;
|
||
legacy exception имеет имя, причину и задачу удаления. Existing coverage floors
|
||
не понижаются; перенос tests/coverage ownership не должен скрыть потерю сценария.
|
||
|
||
### 11. Локальная работа и потребление
|
||
|
||
Приняты приватные npm workspaces внутри frontend: один install/lockfile,
|
||
сборка пакетов и потребление через exports. Проверки охватывают приложение,
|
||
пакеты и Storybook. Собранные tarballs проверены вне workspace без source aliases;
|
||
эта проверка выявляет отсутствующие exports, типы, CSS и несовместимые peers.
|
||
|
||
Публикация, независимый SemVer, package release automation и настройка Nexus
|
||
не входят в текущий переход. Вернуться к ним можно при подтверждённой пользе
|
||
для независимого потребителя; тогда отдельно определить registry, права,
|
||
неизменность версий, совместимость и откат. Текущий app release не меняется.
|
||
|
||
## UI/UX Applicability and Package
|
||
|
||
**Applicability: N/A для нового визуального дизайна.** Цель — сохранение уже
|
||
существующего приложения, без новых экранов и рисунков. Новый макет/visuals и
|
||
hash registry не создаются. Для проверки переноса выбран следующий scope.
|
||
|
||
Пилот: `AccountPage → useAccountPageViewModel → useBrokerageEvents →
|
||
BrokerageEventsPreview → BrokerageEventCard → EntryCard`. Это read-only
|
||
preview выплат; `PositionCard` не использует EntryCard и не подходит для
|
||
переноса без изменения представления. Generic icons в пилоте отсутствуют и
|
||
мигрируют отдельно в Card/Cards.
|
||
|
||
Сохраняются loaded/loading/error/empty, missing amount как unknown, а не ноль,
|
||
registry-date/account metadata, валюта, logo fallback, длинные строки,
|
||
preview limit и ссылка полного списка. Сверяются desktop и viewport 375px,
|
||
доступный focus и отсутствие горизонтального overflow. У generic EntryCard
|
||
actions дополнительно проверяются fine/coarse pointer и reduced motion на
|
||
synthetic story. Текущий RecentEvents error-priority не меняется молча.
|
||
|
||
## Delivery Map
|
||
|
||
| Area | Status | Architectural outcome or N/A reason |
|
||
| --- | --- | --- |
|
||
| frontend | affected | Workspaces tokens/icons/ui, ограниченная миграция, checks и package release integration |
|
||
| backend | N/A | Пакеты не меняют HTTP/auth/storage; замечание об errors вынесено в отложенный scope |
|
||
| specs | affected | Этот change и новые требования к поставке/иконкам; main specs обновятся только после принятой реализации |
|
||
| docs | affected | После поставки уточняются design overview и описание frontend container/release boundary |
|
||
|
||
## Solution Assessment
|
||
|
||
| Решение | Fit / зрелость / ограничения / стоимость | Выбор |
|
||
| --- | --- | --- |
|
||
| Существующие npm workspaces + Vite/TS | Стандартная упаковка; не требует нового Git repo; CSS/peers и published surface нуждаются в проверке | Да |
|
||
| Отдельный design-system repo | Ясная независимость ownership, но удваивает окружение каталога/CI при одном app | Позже по явному consumer/owner trigger |
|
||
| Style Dictionary или собственный token compiler | Полезны нескольким форматам/платформам; сейчас JSON + Mantine adapter уже решают задачу | Нет; runtime trust boundary не меняется |
|
||
| Ручные React SVG / SVGR pipeline | Несколько рисунков дешевле поддерживать в одном TSX source; SVGR нужен каноническим raw SVG exports | Ручные SVG-компоненты сейчас, без генератора |
|
||
| release-it/native npm / Changesets | Первый стек уже принят; второй полезен большому потоку независимых release contributions | Сохранить существующий app release; независимый package release отложен |
|
||
|
||
Новые внешние runtime dependencies не требуются. Риск supply chain сохраняется
|
||
под существующим security gate; peer/version checks и registry ACL нельзя
|
||
заменить предположением о готовом Nexus.
|
||
|
||
## Risks / Trade-offs
|
||
|
||
- Workspace links скрывают отсутствующие exports/assets и конфликт React:
|
||
независимый packed consumer обязателен.
|
||
- Package graph расширяет проверяемую область: старый зелёный `deps src` не
|
||
подтверждает новые packages. Scopes расширяются при появлении владельца.
|
||
- CSS order/global reset влияют на всё приложение. Сначала перенос без
|
||
изменения значений, затем отдельно semantic roles и Modal consolidation.
|
||
- Общие исходники в frontend — осознанный выбор для одного потребителя;
|
||
публикация не означает уже существующий независимый каталог/команду.
|
||
- Изменение view/controller рядом с денежной формой рискованнее UI extraction:
|
||
это отдельная поздняя задача с сохранением tests version/idempotency.
|
||
|
||
## Migration Plan
|
||
|
||
Границы owners → package foundations → общие компоненты и read-only пилот →
|
||
иконки и точечное выравнивание → packed consumer → удаление совместимости.
|
||
Единственный подробный backlog и зависимости находятся в [tasks](tasks.md).
|
||
|
||
Во время перехода `shared/theme` и три старых UI entrypoints могут быть тонкими
|
||
re-exports package API. Они не содержат второй JSON, CSS или реализации.
|
||
Новые consumers используют package paths; добавлять exports/логику в facade
|
||
запрещено. Удаление — когда поиск оставшихся runtime/test/story imports даёт
|
||
ноль и app/catalog/packed consumer прошли gates. Старые inline icons живут до
|
||
своего consumer batch, но новые копии извлечённых рисунков не добавляются.
|
||
|
||
### Rollback Contract
|
||
|
||
| Field | Decision |
|
||
| --- | --- |
|
||
| Status | required: меняются локальные imports, сборка и владельцы компонентов |
|
||
| Trigger | Нет exports/CSS/types, peer conflict, несовместимое представление либо failed pilot/recovery |
|
||
| Actions | Вернуть согласованный diff приложения, packages, imports и lockfile; при выпуске приложения использовать прежний app image |
|
||
| Data safety | API/storage/money wire format не меняются; не откатывать чужие продуктовые изменения и не сбрасывать пользовательские данные |
|
||
| Verification | Повторить соответствующий consumer gate и пилот на прежней версии; проверить восстановление согласованного состояния приложения и packages |
|
||
|
||
### Осознанно отложенное
|
||
|
||
| Находка/возможность | Причина и условие возврата |
|
||
| --- | --- |
|
||
| F8: RecentEvents error приоритетнее cached data | Реальное отличие от общего recovery convention. Не менять при extraction; отдельная product recovery задача после согласования expected stale/error UX, с refetch-error regression test |
|
||
| F9: ProblemDetails errors schema/example и validation mapping | Отдельная backend contract задача: metadata + HTTP behavior test, затем предоставленный snapshot; не основание вручную исправлять frontend DTO |
|
||
| F12: Основная frontend-quality-guardrails spec требует initial 500 kB и baseline lazy chunks, а действующий verify не содержит такого gate | Отдельно согласовать актуальность сохранённого требования и способ enforcement. Не считать Vite warning блокирующим budget gate; package migration сравнивает фактический размер сборки, не заявляя выполнения отсутствующей проверки |
|
||
| Единый recovery classifier всех investment errors | Одинаковые codes ещё не доказывают одинаковый UX; объединять только подтверждённый общий recovery без нарушения FSD |
|
||
| Business/API packages, dark/mobile, raw SVG pipeline, Playwright/visual service | Нет принятого второго consumer или значимого browser-only regression scope |
|
||
|
||
## Решения для подтверждения перед зависимыми действиями
|
||
|
||
1. Публичные имена `@wealthledger/tokens`, `@wealthledger/icons`, `@wealthledger/ui`,
|
||
scope ownership и видимость. Рекомендуется приватная поставка WealthLedger;
|
||
другое решение меняет доступ и release setup, не текущие данные.
|
||
2. Nexus npm endpoint, владелец publish/read credentials, политика неизменности
|
||
и хранения прошлых версий. Эти решения нужны только при отдельном запросе внешней публикации.
|
||
3. Расхождение F12 между сохранённой spec и текущими quality-командами:
|
||
рекомендуемый default — сохранять требование до отдельного решения владельца,
|
||
не ослаблять его и не объявлять выполненным. Автоматизация либо корректировка
|
||
требования оформляются отдельным ограниченным scope после уточнения причины.
|
||
|
||
Остальное — аргументированные defaults данного предложения, а не список
|
||
неразрешённых вопросов. Перед реализацией нужен отдельный запрос пользователя;
|
||
workspaces внутри frontend уже реализованы, независимые версии остаются отложенными.
|