## 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/.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 уже реализованы, независимые версии остаются отложенными.