docs: make frontend instructions self-contained
Frontend security / security (pull_request) Successful in 8s
Frontend verify / verify (pull_request) Successful in 3m55s
Conventional commits / commits (pull_request) Successful in 20s
Frontend security / security (push) Successful in 8s
Frontend verify / verify (push) Successful in 3m49s

This commit was merged in pull request #15.
This commit is contained in:
2026-09-15 20:45:37 +03:00
parent 9f7e342333
commit d9ada27621
8 changed files with 165 additions and 44 deletions
+2 -3
View File
@@ -62,9 +62,8 @@ public API `shared/theme`. Storybook показывает synthetic presentation
не использует application API. RTL/MSW проверяют поведение приложения отдельно. не использует application API. RTL/MSW проверяют поведение приложения отдельно.
Existing route-aware AppShell расположен в shared/ui; это legacy placement, Existing route-aware AppShell расположен в shared/ui; это legacy placement,
а не образец нового shared primitive. Общий план улучшений читается только а не образец нового shared primitive. При изменении foundation прочитай
при migration через [router](../AGENTS.md). [UI](conventions/ui.md#визуальная-основа) и [Storybook](conventions/storybook.md).
При изменении foundation прочитай [design system](../../docs/design/overview.md).
## Примеры ## Примеры
+13 -8
View File
@@ -28,7 +28,7 @@ client, runtime schema, hash/checksum registry или дополнительны
без отдельной текущей потребности; existing OpenAPI flow уже владеет генерацией. Frontend-команды не читают соседний без отдельной текущей потребности; existing OpenAPI flow уже владеет генерацией. Frontend-команды не читают соседний
backend checkout и не проверяют backend runtime OpenAPI; изменение wire backend checkout и не проверяют backend runtime OpenAPI; изменение wire
shape/status/route сохраняет shape/status/route сохраняет
[границу HTTP-контракта](../../../docs/architecture/http-api.md#источник-контракта). публичный контракт предоставленного snapshot.
Одна UI-модель не требует менять API. `openapi:generate` работает offline от snapshot; Одна UI-модель не требует менять API. `openapi:generate` работает offline от snapshot;
`openapi:check` генерирует во временный каталог и сравнивает, не меняя tracked files. `openapi:check` генерирует во временный каталог и сравнивает, не меняя tracked files.
@@ -40,18 +40,23 @@ Authorization. Auth endpoints исключены из Bearer/retry middleware. R
Не добавляй собственный refresh/retry loop в caller. Не добавляй собственный refresh/retry loop в caller.
Protected queries используют existing session-aware boundary; logout очищает Protected queries используют existing session-aware boundary; logout очищает
session-scoped cache. При auth/token change читай [security](../../../backend/.ai/conventions/security-auth.md) session-scoped cache. Access token хранится только в памяти, refresh передаётся
и [authentication](../../../docs/domains/authentication/overview.md). httpOnly cookie с `credentials: include`. Не сохраняй tokens в localStorage,
URL, логах или fixtures. Logout очищает локальную session/cache и при ошибке
сети; до окончания auth bootstrap показывай neutral state. Перед auth change
прочитай shared client, session owner и их tests.
Успешная connection mutation коммитит подтверждённый status и сбрасывает financial Успешная connection mutation коммитит подтверждённый status и сбрасывает financial
GET subtree; ошибка mutation не меняет generation/cache. Это отдельная граница GET subtree; ошибка mutation не меняет generation/cache. Это отдельная граница
от обычного фонового refetch: [connection policy](../../../docs/integrations/tbank.md#граница-финансового-кэша). от обычного фонового refetch. Даже повторное сохранение того же token начинает
новую generation; поздний ответ прежней generation не попадает в новый кэш.
Mutations используют существующий generated client и query-key owner; Mutations используют существующий generated client и query-key owner;
после успеха обновляй/invalidируй только связанные данные. Optimistic update после успеха обновляй/invalidируй только связанные данные. Optimistic update
нужен конкретному UX и обязан иметь rollback/error behavior. нужен конкретному UX и обязан иметь rollback/error behavior.
Default focus refetch выключен; freshness и retry определяются существующей Default focus refetch выключен; freshness и retry задаются существующими
[query policy](../../../docs/adr/007-react-query-fetch-policy.md) и feature source. query options у entity/feature owner. После `staleTime` повторное открытие
экрана может запустить background refetch; focus сам по себе его не запускает.
При обычном refetch сохраняй Client Cached Snapshot, при session/connection При обычном refetch сохраняй Client Cached Snapshot, при session/connection
смене не показывай данные прежнего владельца. UI presentation — в UI convention. смене не показывай данные прежнего владельца. UI presentation — в UI convention.
@@ -76,5 +81,5 @@ Network/unknown error получает безопасное локальное
Изменяя header/retry/invalidation, проверяй наблюдаемое поведение через MSW и Изменяя header/retry/invalidation, проверяй наблюдаемое поведение через MSW и
[Testing](testing.md); не обращайся к реальному T-Bank. [Testing](testing.md); не обращайся к реальному T-Bank.
`npm run openapi:check`, `npm run typecheck` и targeted tests проверяют разные `npm run openapi:check`, `npm run typecheck` и targeted tests проверяют разные
части решения. Для API semantics нужны exact docs и проверки наблюдаемого части решения. Для поведения API-клиента используй сценарии MSW на публичной
HTTP-поведения на стороне backend. HTTP-границе; реализация сервера не является входом frontend-проверок.
+76
View File
@@ -0,0 +1,76 @@
# Работа в репозитории
## Граница и порядок работы
Репозиторий сам содержит инструкции, исходники, конфигурацию и входы своих
проверок. Сборка, CI и обязательный маршрут чтения работают без соседних
checkout. Внешний API задаётся предоставленным публичным контрактом;
исходники или инструкции его реализации не являются зависимостью разработки.
При нехватке требования сообщи, какое решение не определено, до его реализации.
Начни с результата и affected areas. До edits проследи flow/invariants, найди
owner и 1–3 примера. Код показывает механизм; случайный аналог не меняет контракт.
Работай напрямую; OpenSpec/SDD lifecycle — только по явному запросу.
Перед Node-командами активируй местную `.nvmrc`: `nvm use --silent`.
Сохраняй чужие staged/unstaged/untracked изменения и read-only архивы.
## Change scope
Сначала расширь существующего владельца. Иначе используй standard library,
платформу или установленную dependency; небольшая новая реализация допустима
при собственной ответственности. Не создавай helper/interface/wrapper ради
возможного reuse. Общее имя не означает общую бизнес-ответственность.
Сохраняй validation, authorization, atomicity, accessibility и migration safety.
После diff выполни Boy Scout review: проверь новое дублирование, owner, callers,
небольшие связанные legacy issues и соответствие local conventions. Исправляй
непосредственно связанные low-risk проблемы; широкий cleanup — отдельная задача.
## Domain values
Finite business vocabulary принадлежит одному domain/module/entity owner.
Переиспользуй его symbols; для нового словаря без аналога — `as const` + union.
Сохраняй wire values; generated/external enums не переписывай вручную.
Numeric policy называй по смыслу и единицам. Индексы, `Math.max(value, 0)` и
обычные labels не выноси в constants без semantic benefit.
Локальный TypeScript/lint профиль определяет дополнительные ограничения.
## Dependencies
Проверь аналоги и direct dependencies в местном manifest до добавления пакета.
Новая dependency оправдана текущей потребностью и меньшей общей сложностью;
оцени compatibility, runtime/bundle и maintenance/security. Импортируемый пакет
объявляется напрямую; транзитивная установка не является контрактом.
Сохраняй exact versions и lockfile; воспроизводимая установка — `npm ci`.
Peer-конфликт решай совместимыми версиями без `--force`/`--legacy-peer-deps`.
Используй существующий analyzer; не добавляй второй для той же проверки.
## Test Intent
Перед нетривиальным тестом кратко определи наблюдаемый исход, regression risk,
значимые edge/error/concurrency cases и самую дешёвую надёжную boundary.
Отдельный artifact не нужен. Проверяй результат, а не private call order,
декларации, тривиальные wrappers или поведение framework.
При bug сначала воспроизведи исход. Mock race не доказывает DB atomicity.
Уровни и runnable commands выбирай по местной testing convention.
## Проверки и завершение
Code/dependency change: `npm ci`, полный `npm run verify` и дополнительные
risk checks из местной testing convention. Targeted tests ускоряют итерацию,
но не заменяют финальный gate. `lint:fix`/format — edits, не proof.
Markdown-only: проверь новые/изменённые тексты, локальные ссылки/якоря, маршруты
чтения и `git diff --check`; application build ради текста не нужен.
Повтори routing по staged/unstaged/new files. Запиши краткие команды, результаты
и ограничения. Зелёный lint не заменяет semantic/security review.
## Git и релизы
Работа — в `codex/<task>` от актуального `develop`, затем PR в `develop`.
Сохраняй чужие изменения; перед commit просмотри staged paths и diff.
Commits и PR titles — Conventional Commits; допустим `spec:`. Каждый commit
содержит одну связанную задачу. При связанной issue добавь её номер в конец
заголовка (`fix: … #12`); без issue номер не нужен. Root другого checkout
не управляет этим repo.
Прямой push в `main`, force-push и перенос опубликованных тегов не входят в
обычную работу. Перед release/hotfix прочитай местный README, раздел «Релизы».
+2 -2
View File
@@ -1,7 +1,7 @@
# Frontend testing # Frontend testing
Перед нетривиальными тестами сформулируй Перед нетривиальными тестами сформулируй
[общий Test Intent](../../../.ai/conventions/testing.md); отдельный документ [общий Test Intent](engineering.md#test-intent); отдельный документ
не требуется. Trivial low-risk изменения обходятся без него. не требуется. Trivial low-risk изменения обходятся без него.
## Выбор проверки ## Выбор проверки
@@ -35,7 +35,7 @@ MSW запускается только Vitest setup в `src/test/`, без brow
экземпляр и seeded cache. Providers выбирай явно. Existing teardown выполняет экземпляр и seeded cache. Providers выбирай явно. Existing teardown выполняет
RTL cleanup, auth reset и MSW reset: [test client](../../src/test/query.tsx). RTL cleanup, auth reset и MSW reset: [test client](../../src/test/query.tsx).
Тестовый клиент отключает retries запросов и мутаций для предсказуемого исхода; Тестовый клиент отключает retries запросов и мутаций для предсказуемого исхода;
это не меняет [политику обновления приложения](../../../docs/adr/007-react-query-fetch-policy.md). это не меняет [политику обновления приложения](data.md#auth-и-invalidation).
## Важные случаи ## Важные случаи
+1 -1
View File
@@ -32,7 +32,7 @@ Container/VM/view и state owners — в [UI](ui.md).
## Domain literals and magic values ## Domain literals and magic values
Общее правило ownership и символических значений — Общее правило ownership и символических значений —
[Domain values](../../../.ai/conventions/code-health.md#domain-values). [Domain values](engineering.md#domain-values).
Backend vocabulary бери из generated `paths`, не создавай ручную копию enum. Backend vocabulary бери из generated `paths`, не создавай ручную копию enum.
Текущий `schema.d.ts` содержит только types: typed wire literals допустимы, Текущий `schema.d.ts` содержит только types: typed wire literals допустимы,
когда generator не предоставляет runtime values. когда generator не предоставляет runtime values.
+11 -1
View File
@@ -18,7 +18,7 @@ components живут у feature/entity/page, даже при повторном
Wrapper нужен для проектной ответственности, а не ради нового имени Wrapper нужен для проектной ответственности, а не ради нового имени
для Button. Локальный CSS module принадлежит component; общий token вводи для для Button. Локальный CSS module принадлежит component; общий token вводи для
реально общей роли через [design system](../../../docs/design/overview.md). реально общей роли в [визуальной основе](#визуальная-основа).
| Состояние | Владелец | | Состояние | Владелец |
| --- | --- | | --- | --- |
@@ -104,3 +104,13 @@ Type/style: `npm run typecheck`, `npm run lint`. Для risk behavior/измен
используй [Testing](testing.md). UI: keyboard, narrow viewport, используй [Testing](testing.md). UI: keyboard, narrow viewport,
loading/error/empty/loaded и recovery по применимости. [Storybook](storybook.md) задаёт выбор stories и изоляцию каталога; loading/error/empty/loaded и recovery по применимости. [Storybook](storybook.md) задаёт выбор stories и изоляцию каталога;
сверяй UI с задачей отдельно от build. сверяй UI с задачей отдельно от build.
## Визуальная основа
Общая тема живёт в `src/shared/theme`: `tokens.json` задаёт переносимые значения,
`theme.ts` адаптирует их к Mantine. Используй public API темы и её semantic roles,
без отдельной палитры в page/component. Поддерживается светлая схема.
Цвет дополняет подпись или знак; проверяй контраст конкретной пары text/background.
Warning не используй для мелкого текста на белом. Деньги сохраняют валюту, знак
и различие между нулём и неизвестной суммой. Общие состояния демонстрирует
Storybook; presentation stories используют synthetic data без application API.
+17 -19
View File
@@ -1,8 +1,9 @@
# Frontend router # Frontend router
Общие инструкции — [workspace AGENTS](../AGENTS.md). Объединяй triggers задачи, Репозиторий самостоятельный: обязательные инструкции и проверки используют
путей и обнаруженных boundaries; читай только нужные темы до решения. только его файлы и предоставленные публичные контракты. Перед работой прочитай
Системные факты/spec/ADR выбирай в разделе [Источники](#источники) по вопросу. [порядок работы](.ai/conventions/engineering.md#граница-и-порядок-работы), затем
объединяй triggers задачи и путей; читай активированные темы до решения.
| Решение / сигнал | Читать | | Решение / сигнал | Читать |
| --- | --- | | --- | --- |
@@ -12,28 +13,25 @@
| Только продуктовая строка / Zod message | [Строки](.ai/conventions/ui.md#строки-и-валидация) | | Только продуктовая строка / Zod message | [Строки](.ai/conventions/ui.md#строки-и-валидация) |
| Query/mutation, server cache, shared/api, generated types | [Data](.ai/conventions/data.md) | | Query/mutation, server cache, shared/api, generated types | [Data](.ai/conventions/data.md) |
| API/network/application errors, codes и сообщения | [Errors](.ai/conventions/data.md#errors) | | API/network/application errors, codes и сообщения | [Errors](.ai/conventions/data.md#errors) |
| Login/refresh/logout, token/cookie, session ownership | Data + [Security](../backend/.ai/conventions/security-auth.md) + [Testing](.ai/conventions/testing.md) | | Login/refresh/logout, token/cookie, session ownership | [Data/auth](.ai/conventions/data.md#auth-и-invalidation) + [Testing](.ai/conventions/testing.md) |
| Request/response field, route/status/error shape, OpenAPI | Data + [HTTP contract source](../docs/architecture/http-api.md#источник-контракта) | | Request/response field, route/status/error shape, OpenAPI | [Data/contract](.ai/conventions/data.md#типы-и-contract) |
| Tests или behavior с regression risk | [Testing](.ai/conventions/testing.md) | | Tests или behavior с regression risk | [Testing](.ai/conventions/testing.md) |
| Storybook/stories/play, theme/tokens/shared UI | [Storybook](.ai/conventions/storybook.md), UI; design facts — в разделе Источники | | Storybook/stories/play, theme/tokens/shared UI | [Storybook](.ai/conventions/storybook.md), UI; design facts — в разделе Источники |
| Helper/dependency/новый pattern, refactor/scope | [Code health](../.ai/conventions/code-health.md), для пакета — [Dependencies](../.ai/conventions/dependencies.md) | | Helper/dependency/новый pattern, refactor/scope | [Change scope](.ai/conventions/engineering.md#change-scope), для пакета — [Dependencies](.ai/conventions/engineering.md#dependencies) |
| Выбор gate, tooling, завершение | [Guardrails](../.ai/conventions/guardrails.md) | | Выбор gate, tooling, завершение | [Проверки](.ai/conventions/engineering.md#проверки-и-завершение) |
Показ query state не означает изменение fetching. Изменение тестов активирует Показ query state не означает изменение fetching. Изменение тестов активирует
Testing и без production diff. Повтори routing по итоговому diff, включая новые Testing и без production diff. Перед завершением повтори routing по новым и
файлы. Migration backlog читается только при работе над соответствующим finding изменённым файлам. Для Git/release прочитай
через [plan](../.ai/migrations/conventions-v1/plan.md). [Git и релизы](.ai/conventions/engineering.md#git-и-релизы).
## Источники ## Источники
Открывай только источник по возникшему вопросу; примеры кода не переопределяют | Вопрос | Локальный источник |
контракт. Specs задают behavior, а editable OpenAPI принадлежит backend.
| Вопрос | Источник |
| --- | --- | | --- | --- |
| HTTP contract, validation/error codes | [HTTP API](../docs/architecture/http-api.md) | | HTTP request/response/errors | [OpenAPI snapshot](src/shared/api/spec/openapi.json), generated types и [Data](.ai/conventions/data.md) |
| Auth/session/refresh, подключение брокера | [Authentication](../docs/domains/authentication/overview.md), [T-Bank](../docs/integrations/tbank.md) | | Auth/session/refresh/cache | [Data](.ai/conventions/data.md#auth-и-invalidation), source и colocated tests владельца |
| Money, account/position/income/cache meanings | [Глоссарий](../docs/glossary.md) | | Money, account/position/income | Entity types, API snapshot, formatters и tests соответствующего slice |
| Theme/tokens, UI-каталог | [Дизайн-система](../docs/design/overview.md), [Storybook](README.md#ui-каталог-storybook) | | Theme/tokens, UI-каталог | [UI](.ai/conventions/ui.md), [Storybook](README.md#ui-каталог-storybook) |
| Поведение области / требования | [Области docs](../docs/README.md#предметные-области), [Specs index](../specs/AI_INDEX.md) | | Поведение области | Source и tests её page/entity/feature; неясное ожидание уточни до изменения |
| Versions/scripts/check scope | Manifest/lockfile, Biome/TypeScript/dependency configs | | Versions/scripts/check scope | Manifest/lockfile, Biome/TypeScript/dependency configs |
+43 -10
View File
@@ -55,7 +55,7 @@ document и затем выполните `npm run openapi:generate`.
`npm run build:catalog`. Каталог использует общую тему приложения, вымышленные `npm run build:catalog`. Каталог использует общую тему приложения, вымышленные
данные и локальные действия без application API. Примеры не доказывают данные и локальные действия без application API. Примеры не доказывают
восстановление реального запроса. Визуальные роли описаны в восстановление реального запроса. Визуальные роли описаны в
[дизайн-системе](../docs/design/overview.md). [UI convention](.ai/conventions/ui.md#визуальная-основа).
## Документация ## Документация
@@ -65,16 +65,49 @@ document и затем выполните `npm run openapi:generate`.
- [Data/API/cache](.ai/conventions/data.md) - [Data/API/cache](.ai/conventions/data.md)
- [Testing](.ai/conventions/testing.md) - [Testing](.ai/conventions/testing.md)
- [UI-каталог Storybook](#ui-каталог-storybook) - [UI-каталог Storybook](#ui-каталог-storybook)
- [Обзор поставленной системы](../docs/overview.md)
- [Карта проектных фактов](../docs/README.md)
Runtime OpenAPI backend сверяется с frontend snapshot отдельной read-only Checkout frontend содержит все входы сборки и проверок. Публичная схема API
backend командой `npm run test:openapi-contract`. поступает как отдельный artifact; команды frontend используют только её
Разработка идёт напрямую по задаче пользователя. Каждый affected repo проходит локальную копию и не обращаются к исходникам или CI сервера. Доставка новой
свой verify; при изменении wire contract дополнительно выполняется contract check. схемы — явное обновление snapshot с review и `npm run openapi:generate`.
Обязательного OpenSpec/SDD lifecycle нет. Runtime URL API задаётся окружением, а не расположением другого репозитория.
Разработка идёт напрямую по задаче пользователя; OpenSpec/SDD — по явному запросу.
Версии и ветки: [процесс релиза](../README.md#релизы-и-ветки).
Knip исключает `conventional-changelog-conventionalcommits`: release-it загружает Knip исключает `conventional-changelog-conventionalcommits`: release-it загружает
preset по имени из `.release-it.json`. Версия preset закреплена напрямую. preset по имени из `.release-it.json`. Версия preset закреплена напрямую.
## Релизы
Репозиторий выпускается независимо. `develop` — интеграция, `main` — принятые
релизы. Работа: `codex/<task>` от актуального `develop`, PR в `develop`.
Обычные PR допускают squash; release и обратная синхронизация сохраняют историю.
Commits и PR titles — Conventional Commits, включая `spec:`. Версии вручную не повышай.
1. Получи `main`, `develop` и теги: `git fetch origin --tags`. Убедись, что
`develop` содержит последний релиз. Создай `release/<name>` от проверенного
`develop`; `nvm use --silent`, `npm ci`. Hotfix начинается от `main` в
`release/hotfix-<name>` и проходит тот же процесс.
2. На чистой ветке выполни `npm run release:preview`, просмотри версию/changelog,
затем `npm run release:prepare`. Команда создаёт `chore(release): X.Y.Z`,
обновляет manifest/lockfile/CHANGELOG; тег и push не выполняет. Не обходи
guards ветки, чистого дерева, отсутствующих тегов или уже подготовленной версии.
3. Проверь diff и штатные gates этого репозитория. Отправь только release-ветку,
открой PR в `main` с заголовком `chore(release): X.Y.Z`. После зелёных
`verify`, `security`, `commits` выполни fast-forward-only merge. Если `main`
изменился, согласуй историю и повтори проверки кандидата.
4. Получи удалённый `main`, сравни его HEAD с проверенным release SHA и версией
manifest/lockfile. Создай аннотированный `vX.Y.Z` именно на этом SHA:
`git tag -a vX.Y.Z <release-sha> -m "Release X.Y.Z"`, затем отправь только
`git push origin refs/tags/vX.Y.Z`. Не запускай release-it повторно на `main`.
5. Верни release-коммит через PR `main → develop` без squash/rebase; проверь,
что `develop` содержит тег. Опубликованные теги не перемещай. При сбое после
merge создай отсутствующий тег без нового bump; до merge исправь и проверь
существующий кандидат без повторного повышения версии.
`feat:` повышает minor, `fix:`/`perf:` и прочие разрешённые типы — patch;
`!`/`BREAKING CHANGE:` — major, включая версии до 1.0. `chore(release):`
исключён из рекомендации и changelog. Конфигурация — `.release-it.json`.
В Gitea для `main`/`develop` должны быть запрещены прямой/force push и обход
администратором, обязательны `verify`, `security`, `commits`; теги `v*` защищены.
Workflow сам не включает эти настройки. Отдельное review approval для одного
владельца не требуется. Npm publishing, deploy и Gitea Releases не включены.