43 KiB
Context
Локальная архитектура реализована; независимая публикация отложена. Baseline исследования — frontend 3c99deb, версия 0.3.0,
2026-09-20. Требования — в
proposal и delta.
В приложении уже работают 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.
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, не конечная цель |
Направление стрелки — «потребляет»; циклов нет:
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 уже есть
переносимые значения и описания. Не менять формат 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 защищают
именно преобразования и ссылки, не каждое значение 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.
| Назначение | Текущий источник | Целевой источник | Правило применения | Этап |
|---|---|---|---|---|
| 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.
Во время перехода 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 |
Решения для подтверждения перед зависимыми действиями
- Публичные имена
@wealthledger/tokens,@wealthledger/icons,@wealthledger/ui, scope ownership и видимость. Рекомендуется приватная поставка WealthLedger; другое решение меняет доступ и release setup, не текущие данные. - Nexus npm endpoint, владелец publish/read credentials, политика неизменности и хранения прошлых версий. Эти решения нужны только при отдельном запросе внешней публикации.
- Расхождение F12 между сохранённой spec и текущими quality-командами: рекомендуемый default — сохранять требование до отдельного решения владельца, не ослаблять его и не объявлять выполненным. Автоматизация либо корректировка требования оформляются отдельным ограниченным scope после уточнения причины.
Остальное — аргументированные defaults данного предложения, а не список неразрешённых вопросов. Перед реализацией нужен отдельный запрос пользователя; workspaces внутри frontend уже реализованы, независимые версии остаются отложенными.