docs: make project documentation self-contained

This commit is contained in:
2026-09-12 13:09:37 +03:00
parent aa9afc15e4
commit 3a99af1a6e
36 changed files with 1006 additions and 703 deletions
+20 -11
View File
@@ -1,13 +1,22 @@
# Разработка
# Сопровождение системы
Работа начинается с задачи пользователя; обязательного OpenSpec/SDD lifecycle нет.
Проектные факты выбирайте через [AI_INDEX](../AI_INDEX.md).
Здесь описаны локальное окружение, согласованность компонентов, проверка
качества и поддержание проектных знаний. Материалы самостоятельны и не
требуют открытия внутренних файлов приложений.
- [Engineering governance](engineering-governance.md) — выбор решения/dependency, risk-based tests, local gates, UI и опасные изменения.
- [Context discipline](agent-token-efficiency.md) — semantic/path routing, sources, recovery и проверка эффективности.
- [Routing eval cases](agent-context-evals.md) — реальные decision cases и counterexamples для conventions.
- [Frontend workflow](frontend-workflow.md) / [backend workflow](backend-workflow.md) — запуск и существующие checks.
- [HTTP contract workflow](runtime-openapi-verification.md) — Nest OpenAPI → snapshot → generated types и контрактная проверка.
- [Дизайн-система](design-system.md) / [UI-каталог](ui-catalog.md) — theme/tokens, реальные components/stories и ограничения.
- [Remediation registry](audit-remediation.md) — найденная запись Audit ID и historical evidence.
- [OpenSpec](openspec-authority-and-lifecycle.md) — optional legacy workflow, только по явному запросу.
- [Локальное окружение](local-workspace.md) — предпосылки работы, первый пользовательский сценарий и диагностика.
- [Frontend](frontend-workflow.md) / [backend](backend-workflow.md) — ответственность приложений и границы проверки.
- [HTTP contract](runtime-openapi-verification.md) — направление генерации OpenAPI и проверка совместимости.
- [Дизайн-система](design-system.md) / [UI-каталог](ui-catalog.md) — визуальные роли, реальные состояния и ограничения примеров.
- [Принципы изменений](engineering-governance.md) — связность системы, риск и доказательства результата.
- [Ведение документации](documentation.md) — самостоятельные объяснения и их обновление вместе с системой.
- [Контекст знаний](agent-token-efficiency.md) / [проверочные вопросы](agent-context-evals.md) — поиск ответа и обнаружение пробелов документации.
- [OpenSpec](openspec-authority-and-lifecycle.md) — роль сохранённых требований и статус прежнего процесса.
## Исторические свидетельства
[Remediation registry](audit-remediation.md) и [Completion Evidence](completion-evidence.md)
сохраняют статусы, исходные адреса и результаты прежних проверок.
[Аудиты](../audits/README.md) — неизменяемые снимки своего времени. Эти материалы
не входят в самостоятельное описание текущей системы; их внутренние ссылки
могут требовать архивного окружения и не являются условием чтения документации.
+25 -39
View File
@@ -1,50 +1,36 @@
# Проверка agent context
# Проверка полноты проектных знаний
Это небольшой corpus решений для настройки routing. Выполняйте cases по текущим
AGENTS/router/conventions: сначала определите решение и необходимые источники,
затем сравните с ожиданием. Это не unit tests, повторяющие Markdown, и не новый
verification framework. Для проверки изменения правила нужны activating case,
допустимое исключение и unrelated counterexample.
Эти вопросы помогают оценить, объясняет ли документация систему без доступа
к исходникам. Для каждого вопроса важны правильный ответ, существенное
ограничение и отсутствие ошибочного вывода из похожего сценария.
## Cases
| Задача | Необходимый контекст / ожидаемое решение | Что не должно активироваться без новой границы |
| Вопрос | Объяснение | Существенная граница |
| --- | --- | --- |
| Изменить props и layout existing finance view | Frontend UI; props остаются presentation, derived collection values — у VM | API, Prisma, architecture, tests без risk/test change |
| Исправить только продуктовую строку/Zod message | UI section «Строки и валидация»; locale/validationMessage, mandatory review | Остальные UI sections, HTTP/structure/testing |
| Добавить page-local фильтр без сети | Frontend architecture + UI; оставить у page, если нет independent capability | Новый shared abstraction/feature ради click; API |
| Добавить business summary component | Architecture + UI; business meaning и existing owner определяют placement | shared только из-за reuse; widgets layer |
| Изменить query refetch/error recovery | Frontend data + testing; cached snapshot/current generation и exact feature source | Backend data при неизменном server behavior |
| Добавить новый HTTP response field | Backend HTTP + общий contract workflow + применимые tests; Nest → snapshot → generated TS, affected client data rules | Второй editable OpenAPI в specs; ручной generated TS |
| Добавить account endpoint с новым RPC | Backend HTTP, architecture при новом use case, security/access, integrations, testing; TbankAccessService/TbankClient | Прямой gRPC из controller; доверие accountId без ownership |
| Исправить только Prisma query без HTTP/auth boundary | Backend data, testing при data-risk; existing PrismaService | Весь HTTP/security guide автоматически |
| Атомарно обновить связанные записи | Data + testing; transaction/constraint у инварианта, isolated DB proof | Generic repository; mock как доказательство реальной atomicity |
| Изменить конкурентный refresh | Security + data + testing; ADR 009; один winner, superseded не отзывает его session | Replay-history/grace window без задачи; новый coordinator |
| Изменить DTO validation error | HTTP + testing + exact error source; configured HTTP case проверяет pipe/filter pair | Success по одному direct controller call/Swagger snapshot |
| Изменить gRPC retry/deadline | Integrations + testing; bounded existing client path, controlled upstream failure | Вложенный retry loop; реальная сеть/secret |
| Добавить безопасное scalar log field | Architecture/logging; проверить allowlist и event | Весь auth guide без sensitive boundary; считать message автоматически redacted |
| Изменить только тест | Testing соответствующего repo; source guides только по проверяемой границе | Все production conventions из-за расширения `.ts` |
| Добавить dependency/adapter для одной задачи | Общий выбор/dependencies; existing owner/platform/library прежде нового кода | Новый interface только для hypothetical reuse |
| Исправить опечатку в общей документации | Docs AGENTS и затронутый source | Любые frontend/backend conventions |
| После UI начала появились mutation/schema/new files | Routing повторяется по staged/unstaged/new, новые границы читаются до решения | Продолжать по первоначальному UI-only scope |
| Отсутствует обязательный security source / источники конфликтуют | Остановить зависимое решение, восстановить факт/уточнить задачу | Догадка из соседнего code или жёсткий лимит на число документов |
| Кто подтверждает доступ к брокерскому счёту? | [Обзор](../architecture/system-overview.md#предметная-модель) | Сессия подтверждает пользователя, но идентификатор счёта не доказывает доступ |
| Как меняются финансовые данные при замене token? | [Подключение](../features/tbank-connection.md#граница-финансового-кэша) | Данные прежнего поколения не становятся сохранённым снимком нового подключения |
| Что происходит при конкурентном refresh? | [Authentication](../features/authentication.md), [ADR 009](../adr/009-concurrent-refresh-rotation-policy.md) | Один победитель; заменённый token не отзывает его сессию сам по себе |
| Как восстанавливается интерфейс после ошибки обновления? | [UI resilience](../features/frontend-ui-resilience.md) | Фоновая ошибка отличается от первой загрузки и смены пользователя |
| Чем будущая выплата отличается от дохода? | [События](../features/brokerage-account-upcoming-events.md), [доходы](../features/brokerage-account-income-analytics.md) | Прогноз не подтверждает личное зачисление |
| Можно ли складывать разные валюты или заменить неизвестное нулём? | [Money](../architecture/domain-glossary.md#money) | Точность, валюта и отсутствие значения сохраняются отдельно |
| Откуда рейтинг и доходность облигации? | [Bond detail](../features/bond-detail.md) | Рейтинг эмитента не заменяет рейтинг выпуска; рыночная доходность не равна личному результату |
| Доказывает ли OpenAPI правильность ошибки запроса? | [HTTP API](../architecture/http-api.md#error-contract) | Равенство схем не доказывает полный HTTP-поток |
| Что гарантирует проверка хранения данных? | [Backend](backend-workflow.md#локальная-проверка) | Проверка с подставными ответами не доказывает атомарность реальной базы |
| Как ограничиваются обращения к внешнему сервису? | [T-Bank](../features/tbank-connection.md#конфигурация-и-ограничения) | Повторы, очередь и лимит ограничены; TLS остаётся включённым |
| Защищает ли фильтрация логов любое сообщение? | [ADR 008](../adr/008-pino-backend-logging.md) | Секрет в свободном тексте требует отдельной проверки |
| Есть ли восстановление пароля по письму? | [Ограничения auth](../features/authentication.md#limitations) | Пример будущего сценария не является поставленной возможностью |
## Что измерять
Для startup/working-set измерения перечислите ровно прочитанные файлы/sections,
инструмент подсчёта и unit (символы или tokenizer). Required source нельзя
исключать только ради хорошего числа. Число доступных файлов на диске не является
стоимостью конкретной задачи.
Для реальной first-pass оценки выполните одинаковые задачи с одинаковой моделью,
version/tools и comparable prompts: прежний context, только новые indexes,
затем полный routing. Считайте принятие без substantive correction, iterations,
ошибки placement/contract/security, лишние abstractions и пропущенные sources.
Routing review и зелёные application tests сами по себе такого улучшения не доказывают.
Полезное объяснение позволяет найти ответ, назвать ограничение и связать его
с другими сценариями. Оцениваются неверные выводы о доступе, деньгах, полноте
данных и источниках, а также число уточнений до правильного понимания.
Время поиска и объём чтения имеют смысл только вместе с точностью ответа.
## Изменение правил
Если нужный source не прочитан — исправьте trigger. Если source прочитан, но
не разрешает выбор — уточните decision/safe path/example. Если дефект
детерминирован — используйте подходящий existing test/linter. Не добавляйте
новый always-on paragraph для каждого отдельного случая.
Если знание есть, но его трудно найти, уточняется навигация. Если документ
найден, но не объясняет различие понятий или ограничение, уточняется объяснение.
При конфликте источников сохраняется отметка о ручном решении; догадка не
подменяет установленный факт.
+28 -48
View File
@@ -1,62 +1,42 @@
# Context discipline
# Контекст знаний о системе
Цель — получить правила, которые меняют текущее решение, и не читать остальные
заранее. Это процедура прямой работы по задаче, без обязательных SDD artifacts,
ролей, approval fingerprints или подсчёта документов как delivery gate.
Цель навигации — дать читателю знания, необходимые для конкретного вопроса,
без предварительного чтения всей документации. Самостоятельное объяснение
связывает понятия, сценарии и ограничения, а не воспроизводит устройство кода.
## Routing context
1. Определи требуемое поведение, тип решения и affected repos до supporting reads.
2. Прочитай root/local AGENTS, затем CONVENTIONS и SOURCES affected code repo.
3. Объедини сработавшие semantic, path и boundary triggers. Путь — сигнал ответственности, а не повод загружать всё по расширению `.tsx`/`.ts`.
4. Прочитай выбранные conventions или явно указанные sections до зависимого решения. При domain/API/security вопросе открой точный source через [docs index](../AI_INDEX.md).
5. Проследи ближайший существующий owner и подходящие код/тесты. Его поведение не заменяет canonical fact.
6. Повтори routing при новой потребности и по финальным staged, unstaged и новым файлам. Содержимое работы важнее первоначального названия задачи.
Первый проход работает без diff. Auth + refresh, например, активирует API,
security и testing вместе. Отображение query state без изменения запросов не
добавляет transport rules. Docs-only опечатка не требует frontend/backend conventions.
Обычно хватает нескольких тем; это наблюдение, не лимит. Обязательный source
нельзя пропускать ради числа файлов или token budget.
Новая граница внутри задачи требует дочитать правила до работы. Расширение
самой задачи сначала сообщи пользователю; уже данное разрешение не запрашивай
повторно. Чужой concurrent diff учитывай при разграничении ownership.
[Тематический индекс](../AI_INDEX.md) направляет к нужному предмету:
аутентификация связана с безопасностью и сессиями, денежный показатель —
с его происхождением и валютой, ошибка интерфейса — с восстановлением данных.
Вопрос о внешнем виде не требует автоматически изучать хранение данных.
При обнаружении новой существенной границы расширяется и нужный контекст.
## Источники и конфликты
Прямое указание пользователя определяет задачу. Текущий executable HTTP contract
генерируется backend; docs описывает проектные факты/решения; conventions задают
выбор реализации; code показывает существующие аналоги. Generic framework advice
используется после проектных источников. Research содержит рекомендации, которые
нужно сверить с actual code/config, а не автоматически превращать в новый контракт.
Публичный HTTP-контракт описывается OpenAPI backend; документация объясняет
систему, ADR сохраняют причины решений, исследования предлагают варианты.
Существующее поведение не отменяет согласованное требование, а рекомендация
из исследования не становится принятым решением автоматически.
Если задача намеренно меняет контракт, обновляй его source и зависимые материалы
согласованно. Missing input, противоречие security/data правил или неоднозначный
контракт блокируют только зависимое решение до установления фактов/уточнения.
История чата, случайный аналог и предполагаемый путь не заменяют источник.
При расхождении возможны устаревшее объяснение, дефект реализации или
незавершённое изменение. Неустановленный смысл, особенно в безопасности,
данных и публичном контракте, явно отмечается для ручного решения.
Карта ответственности за знания — [ведение документации](documentation.md).
## Recovery и handoff
Для продолжения достаточно текущей задачи, сделанных изменений, remaining work,
точных checks/results и blockers. Не создавай параллельную копию требований,
Design, state registry или обязательный handoff-файл.
В новом контексте восстанови необходимые sources; в том же переиспользуй уже
прочитанные неизменившиеся inputs. Supporting reads добавляй по возникшему вопросу.
Git status/diff показывают staged и unstaged; новые файлы учитывай отдельно.
Relevant ignored/workspace-owned inputs (например `.env`, root AGENTS) не
теряются только потому, что Git их не показывает. Секреты в evidence не печатай.
Продолжение работы опирается на ожидаемый результат, выполненные изменения,
оставшиеся вопросы, результаты проверок и ограничения. Дублирование требований
в нескольких независимых пересказах создаёт риск расхождения. Исторические
проверки сохраняют своё значение только для того состояния системы, в котором
они выполнялись; секреты не являются допустимым содержимым свидетельств.
## Проверка эффективности
Используй [набор routing cases](agent-context-evals.md) для настройки новых правил.
Проверяй activating case, safe exception и unrelated counterexample по реальным
инструкциям. Source links и gates дополняют эту проверку, но не доказывают first-pass quality.
Сравнивай startup context и реально выбранные sections, фиксируя способ измерения.
Не объявляй меньшее число файлов или зелёный application test улучшением качества
агента. Для first-pass acceptance нужны одинаковые реальные задачи/модель/tools,
наблюдённые ошибки ownership/contract/security и число исправлений.
Добавляй convention по повторяющейся decision error; уточняй trigger при missed
source; deterministic regression отдавай существующему test/linter, если он подходит.
[Проверочные вопросы](agent-context-evals.md) показывают, можно ли получить
правильную модель системы и отличить близкие понятия. Качество оценивается по
верности ответа, найденным ограничениям и необходимости дополнительных уточнений.
Число документов, их краткость или успешная проверка Markdown сами по себе
не доказывают полезность знания. Сравнение результатов требует одинаковых
вопросов и сопоставимых условий.
+22 -25
View File
@@ -1,34 +1,31 @@
# Рабочий процесс backend
# Backend: ответственность и проверка
## Предварительные условия
Backend требует Node 22. Создайте `backend/.env` на основе
`backend/.env.example` и замените placeholder-значения `JWT_SECRET` и
`TOKEN_ENCRYPTION_KEY`; token T-Bank в этот файл не записывается.
Backend обслуживает публичный HTTP API, локальные сессии, хранение данных
и интеграции с внешними источниками. Локальная поставка использует Node 22
и SQLite. Окружению нужны адрес frontend, адрес базы, секрет подписи сессий
и отдельный ключ шифрования подключения. T-Bank token вводится пользователем
через настройки и не является общим секретом окружения.
```bash
cd backend
cp .env.example .env
npm ci
```
Назначение параметров, согласование адресов и сохранение данных описаны в
[локальном окружении](local-workspace.md).
## Локальная проверка
Canonical gate не изменяет versioned-файлы:
Проверка backend объединяет статический анализ, проверку типов приложения
и тестов, автоматические сценарии и сборку. Она не изменяет исходные материалы;
автоматическое исправление форматирования не считается доказательством проверки.
Диагностика покрытия доступна отдельно, общего числового порога для backend нет.
```bash
npm run verify
```
[Сравнение OpenAPI](runtime-openapi-verification.md) проверяет соответствие
публичного контракта ожиданиям frontend. Валидация запросов, cookie, доступ
и ошибки требуют полного HTTP-потока; целостность и конкурентные изменения
данных — проверки с изолированной реальной базой.
Он последовательно запускает lint, application/test TypeScript, Jest и build. `npm run lint:fix` — явная
записывающая команда, а `npm run test:cov` — отдельная диагностика без общего
числового threshold. Runtime OpenAPI сверяется с frontend snapshot из workspace:
```bash
cd backend
npm run test:openapi-contract
```
`npm run test:e2e` временно не является passing gate: Prisma schema engine
останавливает migration до Jest. Точная диагностика и trigger пересмотра
зафиксированы в [audit remediation registry](audit-remediation.md).
**Известное ограничение:** движок Prisma 7.9.1 при применении миграций к новой
SQLite-базе возвращает `Schema engine error` до запуска сквозных тестов.
Это воспроизведено и при проверке локального окружения 12 сентября 2026 года.
Успех остальных проверок не подтверждает прохождение этой границы. Условие
пересмотра — стабильная версия с тремя последовательными успешными применениями
миграций на новых базах под Node 22.
+53 -104
View File
@@ -1,135 +1,84 @@
# Дизайн-система WealthLedger
Общий фундамент находится в
[`frontend/src/shared/theme`](../../frontend/src/shared/theme/index.ts).
Его public API экспортирует `theme`, `cssVariablesResolver`, `colorRoles`, `designTokens` и
подключает базовые CSS. App владеет MantineProvider; Storybook подключает свой
изолированный provider к тому же API. Тема и значения не копируются в preview.
Оба runtime используют светлую схему; dark theme не заявлена как поддерживаемая.
Приложение и UI-каталог используют одну визуальную основу: цветовые роли,
типографику, интервалы, радиусы, тени и адаптивные размеры. Общая тема основана
на Mantine; её значения не дублируются отдельно в каталоге.
Поддерживается светлая схема, тёмная тема не заявлена.
## Тема и токены
[`tokens.json`](../../frontend/src/shared/theme/tokens.json) — единственный
редактируемый источник опубликованных токенов WealthLedger. Он содержит восемь
палитр по десять оттенков: blue, gray, dark, red, green, yellow, grape и orange;
базовые white/black, оттенки по умолчанию, семантические роли с описаниями,
типографику, интервалы, радиусы, тени и breakpoints. Существующие значения
приняты из темы приложения и Mantine 9.5.1; теперь ими владеет JSON. Default
radius остаётся md, font family заголовков совпадает с общей.
Опубликованная система включает восемь палитр по десять оттенков: blue, gray,
dark, red, green, yellow, grape и orange; базовые white/black, оттенки
по умолчанию и семантические роли. Общая гарнитура применяется и к заголовкам,
стандартный радиус — средний. Настройки являются доверенной локальной частью
приложения; загрузка внешних или пользовательских токенов не предусмотрена.
[`theme.ts`](../../frontend/src/shared/theme/theme.ts) напрямую адаптирует JSON
в Mantine. Файл — доверенная конфигурация репозитория; приложение не загружает
внешние или пользовательские токены и не проверяет JSON runtime-схемой.
Размеры px преобразуются native `rem`, сохраняя `--mantine-scale`, тени собираются
из слоёв с `rgba`, а breakpoints остаются em без масштабирования. Неопубликованные
палитры и настройки поведения компонентов остаются defaults Mantine.
Небольшой [`theme.test.ts`](../../frontend/src/shared/theme/theme.test.ts)
проверяет преобразования адаптера; корректность изменений локального JSON
проверяется при review, сборке и проверке внешнего вида.
Используйте props Mantine (`gap="md"`, `p="xl"`, `radius="md"`, `shadow="xs"`)
или `--mantine-spacing-*`, `--mantine-radius-*` и другие native CSS variables.
[Foundations](http://localhost:6006/?path=/story/design-system-foundations--colors)
читает эффективную тему и описания из JSON, показывает фактические значения
и образцы. Обновление Mantine не заменяет принятые шкалы автоматически и требует
повторной проверки адаптера и внешнего вида приложения.
`colorRoles` связывает смысл и native Mantine reference; resolver создаёт
`--wl-color-<role>`, ссылающийся на Mantine variable, без повторного hex-значения.
| Role | Native reference | Применение |
| Роль | Цветовая основа | Применение |
| --- | --- | --- |
| canvas | gray.2 | Фон приложения |
| surface | white | Paper и формы в светлой схеме |
| surface | white | Поверхности и формы |
| subtle | gray.0 | Приглушённая поверхность |
| text | dark.7 | Основной текст страницы |
| muted | gray.6 | Вторичный текст (dimmed светлой схемы) |
| text | dark.7 | Основной текст |
| muted | gray.6 | Вторичный текст |
| border | gray.3 | Граница поверхности |
| primary | blue filled | Основное действие и активная навигация |
| info | blue.6 | Информация |
| positive | green.6 | Положительный результат с текстом/знаком |
| negative | red.6 | Ошибка или отрицательный результат с текстом/знаком |
| warning | yellow.6 | Предупреждение, не мелкий текст на белом |
| positive | green.6 | Положительный результат с текстом или знаком |
| negative | red.6 | Ошибка или отрицательный результат с текстом или знаком |
| warning | yellow.6 | Предупреждение; не мелкий текст на белом |
Базовые CSS используют canvas/text aliases. Остальные роли доступны для
постепенного использования; существующие локальные Mantine references не
переписаны массово. Цвет не заменяет подпись статуса. Палитра не гарантирует
доступный контраст произвольных сочетаний: для текста и фона проверяйте контекст.
Grape и orange используются Product; предметные значения задают их FSD-владельцы.
Цвет не заменяет подпись или знак. Палитра не гарантирует доступный контраст
произвольного сочетания текста и фона. Дополнительные grape/orange и отдельные
оформления карточек сохраняют предметный смысл соответствующего экрана;
они не образуют универсальную финансовую классификацию всей системы.
Особые card gradients/shadows, размеры страницы и финансовые цвета CSS остаются
у своих FSD-владельцев. Это сохранение существующего UI, а не завершённый редизайн
или миграция всех literals в tokens. Новую общую шкалу стоит вводить только при
реальном повторном использовании, если native Mantine scale не подходит.
Общие шкалы основаны на принятых значениях приложения и Mantine 9.5.1.
Обновление библиотеки не заменяет их автоматически. Масштабируемые размеры,
тени и адаптивные границы требуют сохранения единиц и визуальной проверки.
Отдельные градиенты, тени и размеры экранов остаются локальными визуальными
решениями; переход всех существующих значений в общую шкалу не завершён.
## Переносимый JSON
Файл использует собственный формат WealthLedger `formatVersion: 1`, без runtime
imports, CSS variables или исполняемого кода. Это контракт данных, а не заявление
о совместимости с DTCG или importer конкретной системы.
Опубликованные токены представлены в собственном формате WealthLedger,
версия 1. Это данные без исполняемого кода и зависимостей от runtime приложения.
Совместимость с DTCG или импортом конкретного инструмента не заявлена.
| Данные | Представление |
| --- | --- |
| Цвета | Hex; palette — массив оттенков 0–9; base — именованные white/black. |
| Семантическая роль | `color`, `shade`, `description`; ссылка на palette или base. Для palette `shade: null` означает `primaryShade.light`, для base оттенок не нужен. |
| Типографика | CSS font stacks; размеры и headings в px, веса числовые, line heights без единиц. |
| Интервалы и радиусы | Именованные `values` xs–xl с `unit: "px"`; `radius.default` выбирает имя шкалы. |
| Тени | Упорядоченные слои: offsetX/offsetY/blur/spread в px, ссылка `color` на base и opacity 0–1. |
| Breakpoints | Именованные `values` xs–xl с `unit: "em"`, не зависят от масштаба UI. |
| Цвета | Hex, палитры оттенков 0–9 и именованные базовые цвета |
| Семантические роли | Ссылка на цвет и оттенок, описание; отсутствие оттенка палитры означает основной оттенок светлой схемы |
| Типографика | Наборы шрифтов, размеры в px, числовые веса и безразмерная высота строки |
| Интервалы и радиусы | Именованные шкалы xs–xl в px и выбранный радиус по умолчанию |
| Тени | Упорядоченные слои: смещения, размытие и растяжение в px, базовый цвет и непрозрачность |
| Адаптивные границы | Именованные размеры xs–xl в em, независимые от масштаба интерфейса |
Не используйте для палитр специальные имена Mantine `dimmed` и `bright`;
`white` и `black` принадлежат base colors. Задавайте вес шрифта в диапазоне
CSS 1–1000. Это правила редактирования формата, а не runtime-проверки.
Внешний потребитель читает raw JSON напрямую. Например, из workspace root,
без Node, React или Mantine:
```python
import json
from pathlib import Path
tokens = json.loads(Path("frontend/src/shared/theme/tokens.json").read_text())
assert tokens["formatVersion"] == 1
colors = tokens["color"]
role = colors["roles"]["primary"]
shade = role["shade"]
if shade is None:
shade = colors["primaryShade"]["light"]
primary_hex = colors["palettes"][role["color"]][shade]
```
`shared/theme/index.ts` предназначен для frontend: он подключает CSS и Mantine
runtime. При интеграции с другой системой сопоставьте единицы, font stacks,
слои теней и semantic references с её форматом; парсер JSON сам этого не делает.
Несовместимое изменение требует новой версии контракта. Внешняя интеграция,
Перенос в другую систему требует сопоставления единиц, шрифтов, слоёв теней
и семантических ссылок. Само чтение JSON не обеспечивает такой совместимости.
Несовместимое изменение формата требует новой версии; внешняя интеграция,
генератор артефактов и публикация пакета пока не реализованы.
## Общие компоненты
Public API — [`shared/ui`](../../frontend/src/shared/ui/index.ts). Минимальный
каталог включает две существующие реализации, реально используемые приложением:
| Компонент | Контракт и правила |
| Представление | Поведение и ограничения |
| --- | --- |
| StateView | Empty/error с title, text, необязательным action; error получает role alert. Кнопке нужен доступный текст; не использовать для initial loading. |
| LoadingSkeleton | Общая status/busy-область с доступной label; caller задаёт только декоративные shapes без фокуса. Структура skeleton принадлежит section/page. |
| Пустой результат или ошибка | Заголовок, пояснение и необязательное действие; ошибка объявляется вспомогательным технологиям, кнопка имеет доступное название |
| Загрузка | Доступная область состояния занятости с пояснением и декоративными фигурами без фокуса; структура отражает ожидаемый экран |
| Действия | Основной, вторичный и вспомогательный варианты; состояния выполнения и недоступности |
Они не импортируют API, auth, счета или позиции. Не создаются wrappers над всеми
примитивами: для действий используется Mantine Button с общей темой. В каталоге
показаны filled для основного действия, default для вторичного/retry и subtle
для вспомогательного, а также loading и disabled. Provider не меняет defaults
Button или Paper ради каталога. Loading действия не заменяет loading страницы;
при refetch сохраняются данные и показывается локальное состояние.
Общие представления не получают финансовые данные и не управляют
аутентификацией. Состояние выполнения действия отличается от загрузки всей
страницы. При фоновом обновлении доступные данные сохраняются с локальным
индикатором; правила восстановления описаны в
[UI resilience](../features/frontend-ui-resilience.md).
Route-aware AppShell не входит в заявленный общий набор. Бизнес-компоненты
и композиции остаются у entities/pages и показываются в Product; витрина не
определяет FSD ownership. Подробности запуска, взаимодействий и coverage —
[UI-каталог Storybook](ui-catalog.md).
Каркас с продуктовой навигацией не входит в заявленный общий набор.
Предметные карточки и композиции представлены в [UI-каталоге](ui-catalog.md).
## Границы доказательств
Каталог использует synthetic fixtures, локальные Actions и MemoryRouter, без
application API/auth/storage runtime. Dependency-cruiser проверяет FSD и
транзитивную runtime-изоляцию stories. Browser проверяет виды, размеры, focus и
действия. Эти примеры не доказывают API recovery и прохождение инвестиционного
сценария. Продуктовый пилот остаётся отдельным change и здесь не проводился.
Каталог использует вымышленные данные и локальные действия без входа,
сохранённого пользовательского состояния и application API. Проверки отделяют
его от исполнения продуктовых запросов. Вид, размеры, фокус и взаимодействия
проверяются в браузере; каталог не доказывает восстановление реального API
или прохождение инвестиционного сценария.
+88
View File
@@ -0,0 +1,88 @@
# Ведение документации
Документация объясняет систему независимо от размещения исходного кода.
За актуальность затронутого объяснения отвечает автор изменения предметной
области; проверка сопоставляет изложение с фактическим поведением и принятыми
решениями. Ответственность подсистем описана в [карте возможностей](../features/README.md).
## Владельцы фактов
| Тип знания | Где объясняется | Граница достоверности |
| --- | --- | --- |
| Устройство и взаимодействие системы | [Обзор](../architecture/system-overview.md) | Описывает существующие подсистемы, данные и потоки |
| Наблюдаемое поведение | [Возможности](../features/README.md) | Сценарий, инвариант, ошибка и ограничение объясняются здесь полностью |
| Значение терминов | [Глоссарий](../architecture/domain-glossary.md) | Одно определение, ссылки из связанных сценариев |
| HTTP-контракт | [HTTP API](../architecture/http-api.md), публичный OpenAPI backend | Объяснение семантики не создаёт второй независимо редактируемый wire contract |
| Причины значимого решения | [ADR](../adr/README.md) | Контекст, решение и последствия относятся к указанному статусу решения |
| Окружение и восстановление | [Локальное окружение](local-workspace.md) | Предпосылки и ограничения описаны без знания устройства репозиториев |
| Принципы сопровождения | [Engineering governance](engineering-governance.md) | Объясняют согласованность и доказательства результата |
| Гипотезы и внешние наблюдения | [Исследования](../research/README.md) | Рекомендация не означает реализованную возможность |
| Результаты прежних проверок | [Исторические свидетельства](README.md#исторические-свидетельства) | Действительны для состояния и условий своего времени |
Поведенческие требования и предложения изменений могут отдельно согласовываться
в OpenSpec. Их роль описана [здесь](openspec-authority-and-lifecycle.md);
понимание текущего сценария не требует доступа к хранилищу спецификаций.
При конфликте возможны устаревший текст, нарушение договорённости реализацией
или незавершённое изменение. Текущее поведение не отменяет согласованное
требование автоматически. Неустановленный смысл явно отмечается для ручного
решения; особенно это важно для безопасности, данных и публичного контракта.
## Куда поместить знание
Объяснение принадлежит существующему документу о соответствующей области.
Понятие определяется в глоссарии; сценарий связывает его с поведением и
ограничениями; ADR сохраняет причину выбора; исследование — ещё не принятый
вариант и его источники. Новый документ нужен для самостоятельного вопроса,
которому нет подходящего места. Навигация делает его доступным из индекса.
Один факт имеет одно полное объяснение, на которое ссылаются остальные страницы.
Ссылка внутри документации уточняет контекст, а не скрывает необходимое условие
понимания за внутренним файлом другого репозитория.
## Содержание страницы
Связное объяснение содержит назначение, ответственность компонентов,
предпосылки и инварианты, основной поток, ошибки, восстановление и ограничения.
Диаграмма нужна, когда помогает понять взаимодействие. Это ориентир, а не
обязательный набор пустых разделов.
Вместо имён классов, внутренних вспомогательных функций и настроек разработки
излагается их архитектурный или функциональный смысл. Публичные API, единицы
показателей, внешние системы и принятые технологические решения остаются
частью объяснения, если нужны читателю. Детали разработки и инструкции
инструментам не входят в описание системы.
Статус понятен из вступления или индекса: текущее поведение, объяснение решения,
исследование или история. Дата наблюдения не гарантирует актуальность спустя
время. Для замены принятого решения сохраняются его прежний контекст и ссылка
на последующее решение.
## Обновление вместе с кодом
| Что изменилось в системе | Какое знание затронуто |
| --- | --- |
| Сценарий, инвариант, ошибка или восстановление | Объяснение возможности и её ограничений |
| Ответственность, внешний источник или поток данных | Обзор, схема и причина значимого решения |
| Значение понятия | Глоссарий и связанные сценарии |
| Окружение, диагностика или граница проверки | Материалы сопровождения |
| Новая возможность | Карта возможностей и тематический индекс |
| Только внутреннее устройство без изменения описанных знаний | Изменение документации может не требоваться |
Изменения нескольких компонентов относятся к общей задаче; объяснение
поставленного результата не должно обещать ещё отсутствующую часть.
Смысловая согласованность важнее совпадения названий задач и формальных отметок.
## Проверка
Проверка охватывает Markdown, внутренние ссылки и якоря, доступность страниц
через навигацию и чтение основной документации без соседних репозиториев.
Внешние URL и HTML-ссылки не проверяются правилом относительных ссылок.
Исторические аудиты, журнал устранения замечаний и свидетельства завершения
сохраняют исходные адреса отдельно от основной книги.
Смысловая проверка подтверждает, что читатель понимает ответственность,
инвариант и ограничение; будущая возможность не выдана за существующую;
API и архитектура не изменены редакторским пересказом. Непонятный смысл
внешней ссылки отмечается для ручной проверки, а не восполняется догадкой.
Успешная синтаксическая проверка не доказывает актуальность знания.
+56 -77
View File
@@ -1,103 +1,82 @@
# Engineering governance
# Принципы изменения и проверки системы
Это общий owner решений о scope, dependencies, testing и проверке результата.
Работа начинается с задачи пользователя и выполняется напрямую. OpenSpec/SDD
не обязателен; прежняя [процедура](openspec-authority-and-lifecycle.md) доступна
только по явному запросу. Исторические artifacts не переписываются.
Ожидаемый результат определяется задачей пользователя. Сопровождение сохраняет
ответственность подсистем, безопасность, точность данных и проверяемость результата.
OpenSpec остаётся [необязательным средством согласования](openspec-authority-and-lifecycle.md);
исторические свидетельства не становятся обязательной процедурой новой задачи.
## Выбор реализации
Читай этот раздел при новой abstraction/dependency, refactor, multi-module
изменении или неоднозначном ownership.
Связное поведение принадлежит ответственной подсистеме. Существующая возможность
используется повторно, если сохраняет нужный смысл и инварианты. Новая граница
оправдана самостоятельной ответственностью, общей потребностью нескольких
потребителей либо необходимостью отделить доступ и целостность данных.
1. Требуемое поведение уже существует — используй его.
2. У поведения есть подходящий owner/helper — расширь его, сохранив связность.
3. Задачу решает платформа, стандартная библиотека или принятая dependency — используй её.
4. Иначе добавь небольшую реализацию там, где принадлежит инвариант.
5. Если текущая структура мешает правильному ownership, сделай необходимый связный refactor с проверкой сохранения поведения.
Оптимизируй ясность всей системы. Число файлов/строк само по себе не определяет
качество: coherent refactor лучше дублированного guard в нескольких callers.
**Безопасный путь:** при неопределённом будущем reuse оставь код у ближайшего
подходящего владельца. Выделение оправдано текущей общей ответственностью,
несколькими реальными consumers или необходимой trust/transaction boundary.
Один consumer не запрещает модуль с самостоятельным инвариантом, но не оправдывает
interface/factory/registry только для воображаемой расширяемости.
Примеры: фильтр одного экрана остаётся page-local; чистое денежное преобразование
использует существующий decimal helper; запрос Prisma не требует generic repository.
Security validation, доступность, error handling и защита данных сохраняются
даже в маленькой реализации.
Простота оценивается по ясности всей системы и стоимости сопровождения,
а не по размеру изменения. Предполагаемая будущая возможность сама по себе
не оправдывает новую подсистему. Упрощение сохраняет валидацию, доступность,
обработку ошибок и защиту от потери данных.
## Dependencies
Перед новой dependency проверь installed stack и существующий helper. Если
подходящего решения нет, оцени поддерживаемую библиотеку, совместимость,
maintenance/security cost и точную недостающую возможность. Собственный код
выбирай по совокупной стоимости, а не ради отсутствия dependency любой ценой.
Версии и scripts принадлежат package.json/lockfile. Frontend сохраняет exact
versions; backend использует свою текущую policy. Transitive package не считается
прямо принятой dependency. Не меняй весь lockfile или инструментарий ради
устаревшей рекомендации в Markdown. Новые сервисы, CI и browser mocking требуют
задачи, в которой они действительно нужны.
При выборе внешней зависимости учитываются текущая потребность, совместимость,
поддержка, безопасность и стоимость сопровождения. Использование принятой
платформы может быть проще собственной реализации; зависимость ради одной
воображаемой будущей возможности не является самостоятельной потребностью.
Новый сервис или общая инфраструктура должны решать актуальную задачу.
## Risk-based testing
Автоматический тест обязателен для изменённого security/privacy поведения,
денежных вычислений, data integrity/migration, concurrency, публичного контракта,
критического journey и подтверждённой регрессии.
Изменения безопасности и приватности, денежных расчётов, целостности данных,
миграций, конкурентного доступа, публичного контракта, критического сценария
и подтверждённой регрессии требуют автоматической проверки соответствующего
риска на наблюдаемой потребителем границе.
Выбирай самую дешёвую надёжную границу, наблюдаемую потребителем. Тест нужен
для собственного branching, преобразования или инварианта; не для каждого
DTO, декларативной конфигурации, thin adapter или поведения библиотеки.
Меняющийся тест тоже активирует testing convention, даже без production diff.
Frontend coverage — anti-regression constraint; backend общего threshold не имеет.
Не пиши тесты только ради процента или повторения Markdown.
Статические проверки не доказывают финансовую или функциональную корректность.
Покрытие frontend служит ограничителем регрессий; для backend общего числового
порога нет. Проверки поведения библиотеки или проценты сами по себе не заменяют
проверку собственного инварианта системы.
## Проверка результата
В итерации используй targeted check из применимого convention. Перед завершением
запусти `npm run verify` каждого изменённого code/docs repo под его `.nvmrc`
после lockfile install. Для HTTP contract — дополнительно
[contract checks](runtime-openapi-verification.md). Общего CI сейчас нет.
Результат оценивается по исходной задаче: сохранены ли смысл данных и контракты,
правильно ли разграничен доступ, учтены ли ошибки и доступность интерфейса.
Проверки приложений и документации дополняются
[согласованием HTTP-контракта](runtime-openapi-verification.md), если он меняется.
Общего CI сейчас нет.
Проверь actual staged/unstaged/new scope и результат против задачи: ownership,
сохранение данных/контрактов, ошибки, доступность, отсутствие лишних abstractions.
Неизменившийся успешный gate можно использовать повторно, если известны команда,
его полный relevant input scope и неизменные prerequisites; при сомнении выполни
его снова. Auto-fix не заменяет non-mutating gate.
Успешная проверка применима к тому состоянию системы и тем предпосылкам,
на которых выполнена. При их изменении старое свидетельство не доказывает
новый результат. Автоматическое исправление материалов и проверка без их
изменения — разные действия.
В ответе достаточно: что поставлено, как проверено, какие ограничения остались.
Не создавай role records, fingerprints всех repositories, Completion Evidence
или delivery commits только ради процесса. Существующие рабочие изменения
других задач сохраняются. Нужный review не заменяется количеством checkboxes.
[Влияние на документацию](documentation.md#обновление-вместе-с-кодом) входит
в оценку результата: описанные понятия, сценарии, решения и ограничения
обновляются вместе с системой. Отсутствие влияния может быть обоснованным
результатом. Отчёт о поставке различает выполненное, проверенное и остающиеся
ограничения; количество формальных отметок не заменяет смысловую проверку.
## Guardrails и local gates
- **Автоматический invariant:** существующий deterministic checker блокирует нарушение в фактическом scope с документированными исключениями.
- **Обязательное semantic правило/процедура:** исполнитель и reviewer проверяют решение; отсутствие checker не переводит i18n, validation или authorization в пожелание.
- **Guidance:** необязательное предпочтение, например эстетический выбор между эквивалентными вариантами.
Не обещай enforcement, отсутствующий в config/tests. Новая автоматическая проверка
оправдана реальным риском или повторяющимся дефектом, а не возможностью написать
ещё один checker. Механические правила принадлежат tools; выбор правильного owner
и полезного теста остаётся semantic judgement.
Автоматические проверки гарантируют только свойства, охваченные их областью.
Смысловые требования — например, правильный владелец данных, авторизация,
локализация и полезность выбранных проверок — требуют отдельной оценки.
Предпочтение между равноценными вариантами отличается от обязательного
инварианта. Новая автоматизация оправдана реальным риском или повторяющимся
дефектом; её наличие само по себе не является целью.
## UI-решения
Для изменяемого UI определи ожидаемые экраны, states, interactions и responsive
поведение из задачи. Используй существующий [каталог](ui-catalog.md) и
[дизайн-систему](design-system.md). Сложный или неоднозначный вариант покажи
пользователю в конкретной форме до дорогой реализации; простой согласованный
вариант делай сразу. Визуальные материалы нужны по задаче, не как обязательный
SDD-пакет. Сборка Storybook не доказывает доступность или визуальное соответствие.
Ожидаемые экраны, состояния, взаимодействия и поведение на разных размерах
экрана определяются пользовательским сценарием. [Каталог](ui-catalog.md)
и [дизайн-система](design-system.md) показывают существующую визуальную основу.
Неоднозначный вариант можно оценить по конкретному примеру до реализации.
Успешная сборка каталога не доказывает доступность и визуальное соответствие.
## Изменение опасного контракта
При public/security/data/billing или труднообратимом выборе заранее уточни
существенную неопределённость. Для миграции определи trigger отката, действия,
сохранность уже созданных данных и проверку восстановления. Сначала подготовь
конкретное reviewable решение; обычные обратимые edits не требуют ритуального approval.
Источники и конфликтующие версии разрешай через [context discipline](agent-token-efficiency.md).
Для публичного контракта, безопасности, данных, платежей и труднообратимого
изменения существенная неопределённость разрешается до применения решения.
Для миграции важны условия отката, сохранность уже созданных данных и проверка
восстановления. Порядок разрешения конфликтов знаний описан в
[контексте системы](agent-token-efficiency.md#источники-и-конфликты).
+25 -42
View File
@@ -1,51 +1,34 @@
# Frontend Workflow
# Frontend: ответственность и проверка
Frontend требует Node 22. В `frontend/` чистая установка и полный локальный quality gate выполняются так:
Frontend предоставляет пользовательские экраны, навигацию и представление
финансовых данных. Он получает данные только через публичный API backend;
credentials T-Bank остаются на сервере. Состав приложения и потоки показаны
в [обзоре системы](../architecture/system-overview.md).
```bash
nvm use --silent
npm ci
npm run verify
```
## Совместимость с backend
`verify` проверяет OpenAPI drift, TypeScript, Biome, один coverage-backed запуск Vitest, Knip,
FSD dependency rules, runtime graph stories и отдельные сборки приложения и
Storybook. Он работает без backend. Coverage
остаётся anti-regression constraint; правила выбора тестов зафиксированы в
[engineering governance](engineering-governance.md).
Типизированный клиент frontend производится из опубликованного backend
OpenAPI. Согласованность клиента с сохранённым описанием API и согласованность
этого описания с работающим backend проверяются отдельно.
Изменение публичного контракта требует обновления производного клиента;
подробности — [согласованность OpenAPI](runtime-openapi-verification.md).
Изолированные примеры реальных компонентов и композиций запускаются в Storybook
через `npm run dev:catalog`. `npm run build:catalog` создаёт `storybook-static/`,
а `npm run preview:catalog` обслуживает эту статическую сборку. Структура каталога,
работа с Docs, Controls и Actions, доступность и ограничения описаны в
[UI-каталоге Storybook](ui-catalog.md).
## Проверка интерфейса
Для UI задачи используйте каталог как reference существующего решения.
Ожидаемые экраны, states и interactions определите по [задаче](engineering-governance.md#ui-решения).
Storybook показывает реализацию; визуальное соответствие и доступность
проверяются отдельно от сборки. SDD-пакет для этого не обязателен.
Локальная проверка frontend охватывает корректность типов, статический анализ,
автоматические сценарии, зависимости и сборку приложения и UI-каталога.
Она может выполняться без запущенного backend. Покрытие тестами ограничивает
регрессии; само по себе число покрытых строк не доказывает правильность
финансового расчёта, доступность или прохождение пользовательского сценария.
Backend остаётся источником OpenAPI. После изменения опубликованного
backend-контракта разработчик обновляет в `frontend/` committed snapshot
`src/shared/api/spec/openapi.json` копированием backend OpenAPI document, затем
запускает:
```bash
npm run openapi:generate
```
Команда использует только committed snapshot и регенерирует
`src/shared/api/generated/schema.d.ts` offline. Проверку соответствия backend
runtime contract и frontend snapshot выполняют отдельной backend-командой
`npm run test:openapi-contract`.
[Каталог](ui-catalog.md) показывает существующие визуальные решения.
Соответствие задаче, широкий и узкий экран, клавиатурная навигация и восстановление
после ошибок проверяются в интерфейсе отдельно от успешной сборки.
## Состояние тестового клиента
`frontend/src/test/query.tsx` предоставляет `createTestQueryClient` с отключёнными
test retries и query-only `createQueryWrapper`. Независимый case получает свой
client до React wrapper render; rerender сохраняет тот же экземпляр и seeded
cache. Auth и T-Bank tests используют эту же фабрику. Mantine, Router и
AuthProvider остаются явно выбранными локальными providers.
Общий teardown последовательно выполняет RTL cleanup, сброс auth client и
сброс MSW handlers. Production query defaults этой инфраструктурой не меняются.
Независимые проверки получают изолированное состояние клиента. Обновление
представления внутри одного сценария сохраняет его кэш; следующий сценарий
не наследует сессию и ответы предыдущего. Повторные попытки в тестовой среде
могут быть отключены для предсказуемого результата. Это не меняет
[политику обновления данных приложения](../adr/007-react-query-fetch-policy.md).
+84
View File
@@ -0,0 +1,84 @@
# Локальное окружение и восстановление
WealthLedger поставляется как локальное приложение: frontend работает
в браузере, backend обслуживает API и обращается к SQLite и внешним источникам.
Это описание предпосылок и ограничений работы, без привязки к устройству
исходного кода. Production-развёртывание в текущую поставку не входит.
## Подготовка backend
Локальная серверная среда использует Node 22 и SQLite. Для работы нужны:
| Параметр | Назначение и ограничение |
| --- | --- |
| Адрес локальной базы | Одинаковая база используется при подготовке схемы и работе приложения; относительный адрес зависит от рабочей директории процесса |
| Разрешённый origin frontend | Определяет browser-источник, которому разрешён доступ к API с credentials |
| Порт API | По умолчанию 3000 |
| Секрет подписи сессий | Секрет не короче 32 символов; отличается от ключа шифрования подключения |
| Ключ шифрования подключения | 32 байта в base64; требуется для чтения сохранённого T-Bank token |
| Параметры интеграции | Адрес T-Bank, лимит запросов и при необходимости доверенный CA; [ограничения](../features/tbank-connection.md#конфигурация-и-ограничения) |
T-Bank token вводится пользователем через интерфейс после входа и не является
общим параметром окружения. Существующая база и её ключ шифрования сохраняются
при обновлении. До миграции необходима резервная копия; восстановление проверяется
на отдельной копии. Потеря или замена ключа не является безвредным сбросом:
прежнее подключение нельзя расшифровать новым ключом.
**Известное ограничение:** проверка новой временной SQLite-базы 12 сентября
2026 года под Node 22 воспроизвела `Schema engine error` до создания схемы.
Полный первый запуск на чистой базе пока не подтверждён; пользовательская база
в этой проверке не использовалась. Условия пересмотра —
[проверка backend](backend-workflow.md#локальная-проверка).
В development доступна [локальная Swagger UI](http://localhost:3000/api/docs)
при стандартном порте API. Она показывает контракт, но не доказывает доступность
T-Bank и не используется frontend как источник данных во время работы.
## Подготовка frontend
Стандартные адреса: API `http://localhost:3000`, frontend `http://localhost:5173`.
Адрес API в клиенте должен совпадать с работающим сервером, а разрешённый origin
backend — с origin браузера. Смена порта требует согласованного изменения
адресов. Смесь `localhost` и `127.0.0.1` меняет границу browser cookie и CORS.
Локальный HTTP предполагает development-режим backend: в других режимах
refresh-cookie получает Secure flag и требует защищённого соединения.
Поведение сессии описано в [Authentication](../features/authentication.md).
## Первый сценарий
1. Пользователь регистрируется или входит. Новый профиль получает сессию;
после перезагрузки приложение пытается её восстановить.
2. В настройках пользователь сохраняет собственный T-Bank Invest token.
Успех означает проверенный доступ к брокеру и сохранённое подключение.
3. В разделе «Счета» доступны отдельный и общий портфель. Отсутствие доступных
счетов является допустимым пустым результатом.
4. «Доходы» показывают полученные выплаты, «События» — будущие.
5. При выходе локальная сессия и её клиентский кэш очищаются.
Без T-Bank token доступны регистрация, вход и состояние отсутствующего
подключения. Это не подтверждает работу финансовых сценариев.
## Если запуск или сценарий не работает
| Симптом | Проверка и безопасное восстановление |
| --- | --- |
| Порт занят | Адрес действующего процесса или выбранный свободный порт должен совпадать с настройками клиента и разрешённым origin |
| Ошибка CORS или сессия теряется после reload | Согласованность адресов, hostname и режима cookie проверяется на стороне browser и backend |
| Ошибка подготовки базы | Установленный blocker не устраняется удалением пользовательской базы или обходом миграций; сохраняются версия среды и текст ошибки |
| `TBANK_NOT_CONNECTED` | Подключение создаётся в настройках текущего пользователя |
| `INVALID_TBANK_TOKEN` | После проверки token и прав у брокера подключение заменяется через настройки |
| `TBANK_UNAVAILABLE`, TLS или rate limit | Проверяются сеть, лимиты и доверенный CA; проверка TLS сохраняется |
| НКР/MOEX недоступен при работающих остальных секциях | Состояние источника и повторная попытка относятся к конкретной секции; недоступность не означает отсутствия рейтинга |
| Подключение не читается после смены ключа | Восстанавливается прежний ключ из защищённой копии; если он утрачен, собственный token вводится заново через настройки |
HTTP-запросы связываются с безопасными журналами через `X-Request-ID`.
Пароли, cookies, Authorization и broker token не включаются в диагностический
отчёт. Ограничения журналирования — [ADR 008](../adr/008-pino-backend-logging.md).
## Проверка первого изменения
Успешная сборка, запуск и прохождение сценария — разные доказательства.
Границы проверки описаны для [frontend](frontend-workflow.md),
[backend](backend-workflow.md) и [HTTP-контракта](runtime-openapi-verification.md).
Завершённость результата учитывает фактические проверки и остающиеся ограничения.
+17 -27
View File
@@ -1,35 +1,25 @@
# OpenSpec: optional legacy workflow
# OpenSpec: роль требований и история процесса
Обязательный SDD lifecycle отменён для обычной разработки. Текущие правила —
[engineering governance](engineering-governance.md),
[context discipline](agent-token-efficiency.md) и root/local AGENTS.
Задача пользователя не требует Proposal/Delta/Design/Tasks, отдельных agent roles,
Completion Evidence или archive как условия завершения.
Обязательный SDD lifecycle отменён для обычной разработки согласно
[ADR 012](../adr/012-task-driven-development-with-scoped-context.md).
Задача пользователя определяет ожидаемый результат; дополнительные planning
artifacts и архивирование не являются условием её завершения.
## Существующие материалы
`specs/openspec` сохраняет behavioral specs, active changes, schemas и archives.
Существующий planning artifact описывает только свой прежний scope и не доказывает
готовность нового запроса. Датированные evidence/archives не переписываются.
Нужную behavioral spec выбирай через [specs index](../../specs/AI_INDEX.md).
OpenSpec сохраняет поведенческие требования, предложенные изменения и историю
согласования. Существующее описание изменения относится только к своему объёму
и не доказывает готовность другой возможности. Текущее поведение системы
объясняется в [карте возможностей](../features/README.md).
## Если OpenSpec запрошен явно
Canonical store прежнего workflow — `wealth-ledger-specs`, физически
`specs/openspec`. Перед Node-командами выбери frontend `.nvmrc`, если у specs
нет своей. Для чтения/изменения change всегда задавай store явно:
OpenSpec остаётся необязательным средством согласования требований, дизайна
и задач. Его собственная модель определяет состав и порядок артефактов;
подтверждение человеком и смысловая проверка результата не выводятся из
одного наличия файлов. Обновление требований и архивирование меняют историю,
поэтому относятся к явно выбранной работе с этой историей.
```bash
openspec status --change <change> --json --store wealth-ledger-specs
openspec instructions <artifact> --change <change> --json --store wealth-ledger-specs
```
Native status/instructions определяют фактические artifacts и schema. Получай
разрешение на именно запрошенное изменение, не выводи approval из наличия файлов.
Sync/archive меняют existing specs/history и выполняются только в рамках такой
явной задачи, после проверки ожидаемого semantic diff и сохранности данных.
Structural validation не доказывает соответствие реализации задаче.
Прежнее rationale — [ADR 010](../adr/010-native-openspec-sdd-and-local-orchestration.md)
и [011](../adr/011-native-openspec-lifecycle-with-repository-gates.md);
текущий выбор прямой работы — [ADR 012](../adr/012-task-driven-development-with-scoped-context.md).
Причины прежнего процесса и его упрощения сохранены в
[ADR 010](../adr/010-native-openspec-sdd-and-local-orchestration.md) и
[ADR 011](../adr/011-native-openspec-lifecycle-with-repository-gates.md).
+25 -40
View File
@@ -2,55 +2,40 @@
## Назначение
`npm run test:openapi-contract` в `backend/` строит configured Nest application,
создаёт runtime OpenAPI document и сверяет его с committed snapshot
`frontend/src/shared/api/spec/openapi.json` после детерминированной canonicalization.
Проверка сравнивает OpenAPI, сформированный настроенным backend-приложением,
с описанием API, на котором основан frontend. Backend остаётся единственным
источником исполняемого HTTP-контракта; frontend-клиент является производным.
Причины выбора описаны в [ADR 002](../adr/002-nest-generated-openapi-contract.md).
Это отдельный контрактный gate, а не общий verifier всех репозиториев. Он обязателен перед завершением задачи, меняющей
backend API или frontend transport contract и не заменяет
локальные lint/typecheck команды приложений.
Эта проверка подтверждает согласованность публичного контракта, но не заменяет
проверки каждого приложения и наблюдаемого HTTP-поведения.
## Выбор и направление изменения
1. Определите, меняется wire contract (route, request/response field, status, error shape) или только внутренний код/UI model. Во втором случае snapshot не меняется.
2. Прочитайте [HTTP semantics](../architecture/http-api.md) и нужный feature/domain source. Backend Nest controllers/DTO/Swagger metadata — единственный editable источник OpenAPI; specs repo не является вторым OpenAPI source.
3. Измените этот source и проверьте representative HTTP behavior. При изменении контракта скопируйте generated runtime OpenAPI в committed frontend snapshot, затем в frontend выполните `npm run openapi:generate`.
4. Выполните frontend `npm run openapi:check` и backend `npm run test:openapi-contract`, а также verify affected repos. Эти команды проверяют разное: schema parity не доказывает validation/auth/error behavior.
Изменением контракта считается изменение маршрута, входного или выходного поля,
статуса либо формы ошибки. Внутреннее изменение представления без изменения
API не требует нового описания контракта.
Generated frontend TS и backend Prisma client вручную не редактируются.
Frontend domain/UI type допустим, когда он отличается от transport DTO по смыслу.
Перед compatibility-sensitive изменением оцените существующих consumers и
rollback/data constraints; одного обновления snapshot недостаточно.
## Запуск
Из корня workspace:
```bash
cd backend
nvm use --silent
npm run test:openapi-contract
```
Перед первым запуском в backend выполняют `npm ci` под Node 22.
Направление согласования: публичный API backend → OpenAPI → производное
описание и типизированный клиент frontend. Две независимо редактируемые версии
контракта создавали бы риск расхождения. Перед изменением, влияющим на
совместимость, учитываются существующие потребители и сохранность данных.
Семантика запросов и ошибок описана в [HTTP API](../architecture/http-api.md).
## Границы и результат
Команда:
Сравнение выполняется на границе настроенного приложения, нормализует порядок
ключей JSON-объектов и сохраняет порядок массивов. Оно не обновляет сравниваемые
описания и клиент автоматически и не обращается к T-Bank или другим внешним
источникам. Несовпадение указывает на рассогласование контракта.
- использует configured Nest application на integration boundary;
- рекурсивно сортирует только ключи JSON objects и сохраняет порядок arrays;
- не записывает snapshot или generated frontend types.
Она не записывает committed snapshot или generated frontend types и не
обращается к T-Bank либо другому внешнему сервису. Если контракт действительно
изменён, snapshot обновляют явным копированием backend OpenAPI document в
`frontend/src/shared/api/spec/openapi.json`, затем в `frontend` запускают
`npm run openapi:generate` и снова выполняют эту проверку.
Равенство схем не доказывает фактическую работу валидации, авторизации,
статусов, cookie и обработки ошибок: для этого нужны наблюдения полного
HTTP-потока. Согласованность описаний и функциональная корректность —
разные доказательства.
## Ограничение e2e
Проверка Swagger не запускает backend e2e tests. WL-P2-05 (runnable e2e) и
WL-P2-13 (единый workspace verdict) отложены из-за нестабильного Prisma 7.9.1
migration gate; дата, rationale и trigger пересмотра находятся в
[audit remediation registry](audit-remediation.md).
Сравнение OpenAPI не запускает сквозные проверки с миграциями базы.
Известная ошибка движка миграций и условие пересмотра описаны в
[проверке backend](backend-workflow.md#локальная-проверка).
+50 -98
View File
@@ -1,120 +1,72 @@
# UI-каталог Storybook
Storybook 10.6.0 показывает реальные компоненты и композиции WealthLedger
на общей визуальной основе приложения без входа и подключения backend.
Storybook 10.6.0 показывает реальные представления WealthLedger на общей
визуальной основе приложения без входа и подключения backend.
## Запуск и сборка
Из `frontend/` выберите Node 22 и установите зависимости из lockfile:
```bash
nvm use --silent
npm ci
npm run dev:catalog
```
Storybook запускается на [localhost:6006](http://localhost:6006); браузер
автоматически не открывается. Отдельная статическая сборка и её preview:
```bash
npm run build:catalog
npm run preview:catalog
```
Результат находится в `frontend/storybook-static/`, вход — `index.html`.
Команда preview выводит адрес статической витрины в терминале. Обычный
`npm run build` сохраняет приложение в `frontend/dist/`; stories не входят
в его entrypoint и продуктовые маршруты. Публикация отдельным сервисом не настроена.
Каталог работает как отдельная локальная витрина по адресу
[localhost:6006](http://localhost:6006) либо как самостоятельная статическая
сборка. Его примеры не входят в пользовательские маршруты приложения.
Публикация отдельным сервисом не настроена.
## Компоненты и работа с примерами
В дереве доступны два блока, 9 групп / 30 историй:
Два блока каталога включают 9 групп и 30 примеров:
| Блок / группа | Что показывает |
| Группа | Что показывает |
| --- | --- |
| `Design System/Foundations` | Восемь палитр и семантические роли, типографику, интервалы, радиусы, тени и breakpoints из общей темы, адаптированной из tokens.json. |
| `Design System/Components/StateView` | Четыре empty/error варианта с действием и без. |
| `Design System/Components/LoadingSkeleton` | Общую доступную busy-область с нейтральными structural shapes. |
| `Design System/Components/Button` | Прямой Mantine Button: primary, default, subtle, loading, disabled; локальное действие и keyboard interaction. |
| `Product/BrokerageAccountList` | Сводки счетов в нескольких валютах, недоступную/пустую сводку и длинное название. |
| `Product/PositionCard` | Акцию с положительным результатом, облигацию с отрицательным, прочий инструмент и позицию без оценки. |
| `Product/RecentEvents` | Полученные события, loading/error/empty и неизвестную ожидаемую сумму. |
| `Product/PortfolioRefreshState` с `PortfolioTotals` | Сохранённые суммы при обновлении и ошибке, локальный retry. |
| `Product/AccountPageLoading` | Реальный skeleton заголовка, сводки и строк страницы счёта. |
| Основы дизайн-системы | Палитры, семантические роли, типографику, интервалы, радиусы, тени и адаптивные размеры |
| Пустой результат и ошибки | Четыре варианта с действием и без |
| Загрузка | Доступную область занятости с нейтральными фигурами |
| Кнопки | Основное, вторичное и вспомогательное действие, выполнение и недоступность, работу с клавиатурой |
| Список счетов | Несколько валют, недоступную и пустую сводку, длинное название |
| Карточка позиции | Акцию с положительным результатом, облигацию с отрицательным, прочий инструмент и отсутствие оценки |
| Последние события | Успешный, загружаемый, ошибочный и пустой результат; неизвестную сумму |
| Обновление портфеля | Сохранённые суммы при обновлении и ошибке, локальную повторную попытку |
| Загрузка страницы счёта | Контур ожидаемых заголовка, сводки и строк |
Быстрые входы: [Design System — цвета](http://localhost:6006/?path=/story/design-system-foundations--colors)
и [Product — карточка позиции](http://localhost:6006/?path=/story/product-positioncard--stock-gain).
Все исходные 21 истории сохранены; 9 новых добавляют foundations и общие примеры.
Бизнес-компоненты остаются в entities/pages, а общие StateView и LoadingSkeleton
— в shared/ui. Button показан напрямую: новое имя-wrapper не вводится.
Каталог не перечисляет все элементы библиотеки или приложения. Отсутствие
представления в витрине не означает его отсутствия в продукте. Основы показывают
опубликованные шкалы и смысл ролей; особые размеры и тени конкретных экранов
не объявляются общими токенами. Границы описаны в [дизайн-системе](design-system.md).
Каталог не перечисляет весь Mantine или все компоненты приложения. AppShell
с product navigation не объявлен компонентом общего набора. Отсутствие компонента
в каталоге не запрещает его использование. Foundations показывает опубликованные
шкалы из `shared/theme/tokens.json`, описания ролей и эффективные Mantine значения.
Локальные размеры и особые тени не объявляются глобальными токенами;
неопубликованные defaults остаются у Mantine. [Дизайн-система](design-system.md)
описывает JSON-формат, внешнее чтение, ownership и правила расширения.
Canvas показывает выбранный пример. Docs поясняет назначение и ограничения,
Controls меняет доступные свойства, Actions показывает локальные действия.
Вымышленные исходные данные не редактируются через Controls: другой набор
данных выбирается отдельным примером. Свойства можно сбросить, пример —
смонтировать заново; изменение размера просмотра не сбрасывает выбранные значения.
Выберите историю в дереве, чтобы открыть её состояние в Canvas. Docs описывает
назначение, ограничения и свойства группы, а также её примеры. Controls меняют
разрешённые свойства; синтетические объекты и callbacks недоступны для редактирования.
Например, `kind` у `PositionCard` меняет вариант представления фиксированной позиции,
а разные данные инструмента выбираются отдельной историей. Actions регистрирует
локальные callbacks кнопок и retry.
Для возврата изменённых свойств используйте штатный reset args в Controls;
для повторного монтирования примера — remount в панели Canvas. Размер preview
можно менять без сброса args. Изолированный iframe позволяет отдельно проверить
компонент на узком экране; навигацией самой витрины управляет Storybook.
Preview и приложение используют один public API `shared/theme`: theme,
CSSVariablesResolver и базовые styles вместе с Mantine CSS. Preview использует
русскую i18n и фиксированную светлую схему без чтения сохранённой темы.
Stories находятся рядом с существующими presentation components и импортируют
их реализации. Токены и описания их семантических ролей принадлежат
`shared/theme/tokens.json`; `theme.ts` напрямую адаптирует этот локальный файл
в Mantine, preview не хранит копию токенов. Error StateView сохраняет alert semantics,
skeleton — busy-область с декоративными фигурами без фокуса. Проверяйте доступность
действий и ссылок с клавиатуры вместе с визуальным состоянием.
Витрина и приложение используют одну тему. Примеры показываются по-русски
в светлой схеме. Ошибка сохраняет доступное объявление, загрузка — состояние
занятости; декоративные фигуры не получают фокус.
## Границы и сопровождение
Все счета, позиции, события и суммы вымышлены. Stories не читают application
storage, cookies, секреты или реальные пользовательские данные. Внешние логотипы
не загружаются: примеры используют буквенный fallback существующего компонента.
Storybook manager может сохранять собственные настройки витрины; telemetry отключена.
Все счета, позиции, события и суммы вымышлены. Каталог не читает сессии,
cookies, секреты и реальные пользовательские данные. Вместо внешних логотипов
показываются буквенные заглушки. Сама витрина может сохранять свои настройки;
телеметрия отключена.
Stories не подключают AuthProvider, QueryClient, API clients и исполняемые VM.
Действия не обращаются к application API. Ссылки меняют только локальный маршрут
MemoryRouter: страница назначения не отображается, URL приложения не меняется.
Retry демонстрирует локальный callback и не доказывает восстановление API или
полный пользовательский сценарий. Loading/error относятся к выбранному примеру.
Действия не обращаются к application API. Ссылки меняют только локальное
состояние примера, не открывают продуктовую страницу назначения и не меняют
адрес приложения. Повторная попытка демонстрирует локальное действие и не
доказывает восстановление реального запроса.
Композиция сохранённых сумм показывает представление Client Cached Snapshot;
сам query lifecycle не исполняется. Для запросных экранов действует
[UI Pattern](../../frontend/.ai/conventions/frontend-ui.md#состояния-и-recovery): сохранение данных при refetch,
structural skeleton для initial loading и контекстный индикатор mutation.
Skeleton конкретной страницы остаётся ответственностью страницы.
Сохранённые суммы иллюстрируют Client Cached Snapshot, но его жизненный цикл
здесь не исполняется. В приложении первичная загрузка показывает контур
ожидаемого содержимого, фоновое обновление сохраняет данные, а выполняемое
действие имеет контекстный индикатор. Подробности —
[состояния интерфейса](../features/frontend-ui-resilience.md).
При изменении включённого компонента проверяйте вместе с ним его пример,
описание и ограничения. `npm run verify` включает Storybook в strict TypeScript,
Biome, Vitest, Knip и dependency-cruiser, затем собирает приложение и статическую
витрину. Основная проверка FSD сохраняется; отдельный `deps:storybook` проверяет
runtime graph stories и preview, запрещая достижимость application data.
Type-only ссылки на типы VM и API стираются и не запускают запросы.
Declarative stories не требуют искусственного unit coverage, а продуктовые
coverage floors сохраняются. Клавиатура, реальные размеры и визуальное
соответствие проверяются в браузере; автоматической visual regression нет.
Автоматические проверки frontend охватывают каталог и его изоляцию от
продуктовых запросов. Примеры и их пояснения обновляются вместе с включёнными
представлениями. Клавиатура, реальные размеры и визуальное соответствие
проверяются в браузере; автоматической визуальной регрессии нет.
## Использование в UI задаче
Каталог помогает выбрать existing component, состояние и ограничения. Ожидаемое
поведение определите из задачи: экраны, states, interactions и узкий viewport.
Для сложного варианта покажите конкретный макет/пример до дорогой реализации;
простой согласованный вариант реализуйте сразу по [UI policy](engineering-governance.md#ui-решения).
Story — reference текущей реализации. Сборка не доказывает visual match,
keyboard accessibility или работу настоящего API. Проверяйте соответствие задаче
и применимые states в браузере. Использование установленного каталога не требует
повторного approval установки или OpenSpec Design artifact.
Каталог помогает сравнить существующие состояния с ожидаемым пользовательским
сценарием. Он дополняет [принципы UI-решений](engineering-governance.md#ui-решения)
конкретными примерами, но успешная сборка не доказывает доступность,
визуальное соответствие и работу настоящего API.