docs: establish workspace engineering conventions
Workspace security / security (push) Successful in 7s
Workspace verify / verify (push) Successful in 20s
Workspace security / security (pull_request) Successful in 6s
Workspace verify / verify (pull_request) Successful in 20s
Conventional commits / commits (pull_request) Successful in 10s
Workspace security / security (push) Successful in 7s
Workspace verify / verify (push) Successful in 20s
Workspace security / security (pull_request) Successful in 6s
Workspace verify / verify (pull_request) Successful in 20s
Conventional commits / commits (pull_request) Successful in 10s
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# Code health и границы изменения
|
||||
|
||||
## Search → reuse → converge
|
||||
|
||||
Перед utility, hook, wrapper, dependency или новым technical pattern:
|
||||
|
||||
1. Проследи поведение, инварианты и callers у ответственного owner.
|
||||
2. Ищи аналоги по имени **и реализации** (`rg` по imports, API, выражению).
|
||||
3. Расширь подходящий owner/helper/pattern; выбирай минимальное решение,
|
||||
полностью закрывающее текущую задачу. Новый файл сам по себе не улучшение.
|
||||
|
||||
Уменьшай количество способов решать одну техническую задачу. Во frontend
|
||||
сравни query keys, formatters, class composition; в backend — pagination,
|
||||
error mapping, repositories и обращения к одному provider. Сходный синтаксис
|
||||
без общей ответственности не требует DRY. Критерий dependency — в
|
||||
[dependencies](dependencies.md).
|
||||
|
||||
## Change scope
|
||||
|
||||
Consistency с подходящим project pattern предпочтительнее универсальности.
|
||||
Новые layers, wrappers, generic helpers, factories, schemas, validators, scripts
|
||||
и дополнительные проверки требуют текущей ответственности или риска.
|
||||
Сначала используй native API/установленный stack; не строй на гипотетических
|
||||
consumers и будущих requirements.
|
||||
|
||||
Backend: CQRS, Event Sourcing, Domain Events, Unit of Work, Command Bus,
|
||||
generic repositories, abstract factories, custom DI и elaborate domain layers
|
||||
не вводятся только ради «best practice». Frontend: wrapper над Mantine, global
|
||||
store и дополнительная OpenAPI hash/schema система не создаются автоматически.
|
||||
Trust-boundary validation, authorization, atomicity, accessibility и необходимая
|
||||
regression proof остаются частью полного решения.
|
||||
|
||||
## Boy Scout review
|
||||
|
||||
После изменения проверь affected area: новое дублирование, пропущенный helper,
|
||||
competing patterns, небольшие связанные legacy issues и conventions.
|
||||
Исправляй в рамках задачи только непосредственно связанные, небольшие,
|
||||
low-risk, behavior-preserving проблемы, которые легко проверить.
|
||||
Более широкие находки сохраняй для отдельной migration; массовый cleanup
|
||||
не является условием завершения текущей задачи.
|
||||
|
||||
## Persist decisions и ratchet
|
||||
|
||||
Устойчивый pattern должен находиться через код и manifest. Добавляй convention,
|
||||
только если следующей сессии всё ещё нужно явное project decision rule.
|
||||
У каждого правила один owner; AGENTS содержит trigger и ссылку.
|
||||
Mental model живёт в `.ai/architecture.md`, intent — в specs, системные знания —
|
||||
в docs. Audit/backlog не помещай в conventions.
|
||||
|
||||
Legacy фиксируется отдельно; новый diff не добавляет нарушений. При migration
|
||||
закрывай подтверждённые baseline findings с evidence, сохраняя область проверки.
|
||||
Зелёный lint не доказывает отсутствие semantic debt. Работа с baseline начинается
|
||||
с [migration plan](../migrations/conventions-v1/plan.md), только когда задача
|
||||
затрагивает migration или найденный там owner.
|
||||
|
||||
## Domain values
|
||||
|
||||
Finite business vocabulary (status, error code, operation kind, role) принадлежит
|
||||
domain/module/entity owner. Перед определением найди существующие types/values;
|
||||
в comparisons используй символ владельца, без конкурирующих словарей.
|
||||
Для нового project-owned vocabulary без аналога: `as const` + derived union.
|
||||
Сохраняй wire values; generated/external enums не переписывай.
|
||||
|
||||
Numeric policy называй по смыслу и единицам (`TIMEOUT_MS`, `PAGE_SIZE`).
|
||||
Индексы, `index + 1`, `Math.max(value, 0)` и обычные labels/log messages
|
||||
не выноси в constants без semantic benefit. Локальный lint/i18n profile всё равно
|
||||
применим. Не создавай tests существования констант или custom magic-string analyzer.
|
||||
Различия TS/генератора принадлежат local conventions frontend/backend.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Dependencies
|
||||
|
||||
## Перед добавлением
|
||||
|
||||
1. Найди аналог по назначению и реализации в affected repo.
|
||||
2. Проверь его direct dependencies, текущий stack и native/stdlib API.
|
||||
3. Определи масштаб: один простой случай или повторяющаяся техническая задача.
|
||||
4. Используй существующее решение, если оно полностью покрывает поведение.
|
||||
Новый пакет оправдан меньшей общей сложностью, а не сокращением одной строки.
|
||||
|
||||
Повтор non-business задачи в примерно 3+ независимых местах — сигнал пересмотреть
|
||||
pattern, а не требование немедленно извлечь abstraction. Сравни общий helper,
|
||||
native API и зрелую небольшую dependency: parsing, serialization, dates,
|
||||
debounce, class composition. Три `Array.map` не требуют utility library.
|
||||
Не продолжай копировать boilerplate, если один принятый способ дешевле сопровождать.
|
||||
|
||||
`clsx` сейчас не принят как direct dependency. Разные способы соединить классы
|
||||
сначала требуют подтверждённого повторения; устанавливать его заранее не нужно.
|
||||
|
||||
## При выборе пакета
|
||||
|
||||
- Укажи конкретную потребность, альтернативу из текущего stack и существенную
|
||||
цену: совместимость, browser bundle/server runtime, maintenance/security.
|
||||
- Импортируемый пакет объявляй напрямую в repo владельца; наличие в соседнем
|
||||
repo или транзитивном дереве не является dependency contract.
|
||||
- Сохраняй exact versions и lockfile. Перед Node-командами активируй `.nvmrc`
|
||||
через `nvm use --silent`; воспроизводимая установка — `npm ci` в нужном repo.
|
||||
- Peer-конфликты решай совместимыми версиями, без `--force`/`--legacy-peer-deps`.
|
||||
Известная frontend граница TypeScript/openapi-typescript — в
|
||||
[README](../../frontend/README.md#проверка); версии принадлежат manifest/lockfile.
|
||||
- После изменения запускай relevant install/type/build/behavior checks и
|
||||
existing security workflow. Не добавляй второй analyzer, когда задача решается
|
||||
настройкой существующего; [карта проверок](guardrails.md).
|
||||
@@ -0,0 +1,22 @@
|
||||
# Git в workspace
|
||||
|
||||
- Выполняй Git-команды из репозитория владельца: root, frontend, backend,
|
||||
docs и specs имеют независимые history, index и branches.
|
||||
- Новая работа: ветка `codex/<task>` от актуального `develop`, затем PR в `develop`.
|
||||
Сохраняй чужие staged/unstaged/untracked изменения; не переноси их в свой commit.
|
||||
- Commit содержит одну связанную задачу и её необходимые проверки/документацию.
|
||||
Межрепозиторное изменение оформляй отдельными commits/PR с взаимными ссылками.
|
||||
- Commits и заголовки PR — Conventional Commits; допустим `spec:`.
|
||||
Во frontend номер связанной issue добавляй в конец заголовка (`fix: … #12`);
|
||||
без связанной issue номер не нужен. Формат проверяет local commitlint.
|
||||
- Перед commit проверь `git diff --cached --name-status` и сам staged diff
|
||||
в каждом affected repo. Root tracking ограничен [.gitignore](../../.gitignore):
|
||||
новый общий файл получает точечный allowlist и проверку
|
||||
[tracking](../../test-workspace-tracking.py). `git add -f` не используется.
|
||||
- Не выполняй `git clean -fdx`, reset чужих изменений, force-push, удаление или
|
||||
перенос опубликованных тегов как обычную очистку. Для опасной операции нужны
|
||||
явная необходимость, сохранение данных и соответствующая авторизация.
|
||||
- Обычный PR допускает squash. Release/hotfix, синхронизация main/develop,
|
||||
release-конфигурация и CI refs требуют чтения
|
||||
[процесса релиза](../../README.md#релизы-и-ветки): он владеет merge policy,
|
||||
версиями и тегами. Прямой push в `main` запрещён; версии вручную не повышай.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Conventions → deterministic guardrails
|
||||
|
||||
Читай при выборе проверки или изменении tooling. Команды выполняются из repo
|
||||
владельца после `nvm use --silent`. Config/manifest задаёт фактический scope;
|
||||
таблица не заменяет semantic review и не утверждает, что все checks уже запущены.
|
||||
|
||||
| Convention | Существующий check | Достаточность / следующий шаг |
|
||||
| --- | --- | --- |
|
||||
| Git multi-repo tracking | root `python3 test-workspace-tracking.py`, `.gitignore` | Проверяет exact allowlist и сохранность fictional data/nested Git; обновлять вместе с allowlist |
|
||||
| Conventional Commits | local commitlint + commits workflow | Syntax покрыт; атомарность и scope — review |
|
||||
| Dependencies | exact manifest/lockfile, `npm ci`, security workflows (audit/Gitleaks) | Reuse, peer compatibility, ценность dependency — review; новый analyzer не нужен |
|
||||
| Frontend types/style/literals | TypeScript strict, `erasableSyntaxOnly`; Biome `npm run lint` | Props profile, i18n и symbolic strings требуют review; literals exclusions — в Biome |
|
||||
| Frontend FSD | dependency-cruiser `npm run deps` | Upward imports, cycles, public entry points покрыты; same-layer запрет неполный, semantic ownership не проверяется |
|
||||
| Unused frontend code/deps | `npm run knip`, TS unused locals/params | Existing tool достаточно; не добавлять второй unused analyzer |
|
||||
| API generation | frontend `openapi:check`; backend `test:openapi-contract` | Первый сравнивает generated types со snapshot; второй — Nest schema со snapshot. Ни один не доказывает runtime validation errors |
|
||||
| Query/auth/error/finance behavior | Vitest + RTL/MSW; backend Jest/SQLite/HTTP | Test Intent выбирает риск и уровень, без автоматического теста для каждого файла |
|
||||
| Storybook | `typecheck`, `deps:storybook`, `build:catalog` | Imports/types/build покрыты; `play`, visual/keyboard/browser behavior проверять отдельно |
|
||||
| Backend types/style | ESLint/Prettier, app/test TypeScript | Zero-warning gate; `no-explicit-any` отключён, часть unsafe rules включена. Не обещать полного запрета `any` |
|
||||
| Backend modules/domain | TypeScript и semantic review | Отдельного architecture analyzer нет. При повторных нарушениях сначала рассмотреть existing ESLint `no-restricted-imports`, без нового custom analyzer |
|
||||
| DB ownership/atomicity | Prisma schema/constraints, `test:sqlite`, `test:e2e`, `test:durability` | Mock Prisma недостаточно. Relevant suites на disposable DB, без reset пользовательской базы |
|
||||
| Logging/security | Logging/auth/access tests, configured HTTP tests, Gitleaks | Allowlist/redaction имеют границы. Встроенный ESLint `no-console` можно включить отдельно; semantic security review обязателен |
|
||||
| Markdown/routing | docs markdownlint-cli2 + relative-links, `git diff --check` | Existing docs gate охватывает docs, а не соседние `.ai`; для них запустить тот же установленный CLI с явным списком путей и docs config |
|
||||
|
||||
## Ratchet без новой инфраструктуры
|
||||
|
||||
- Existing error gates остаются обязательными; не ослабляй их ради legacy.
|
||||
- До расширения FSD rule получи candidate violations существующим depcruise.
|
||||
Его `--ignore-known` допускает native baseline; сначала проверь формат через
|
||||
`--help`. Не игнорируй целые directories. Обновление baseline принимается
|
||||
только с evidence закрытия/явным обоснованием нового исключения.
|
||||
- Semantic findings учитываются stable IDs в
|
||||
[inventory](../migrations/conventions-v1/audit.md) и закрываются vertical slices
|
||||
по [plan](../migrations/conventions-v1/plan.md). Это reviewed inventory,
|
||||
не автоматический полный счётчик нарушений.
|
||||
- Новый analyzer/custom baseline CI не создаётся. Если существующей проверки
|
||||
недостаточно, сначала сформулируй повторяющийся regression и стоимость
|
||||
поддержки предлагаемого rule.
|
||||
|
||||
## Выбор финального gate
|
||||
|
||||
Markdown/routing-only: проверить все новые/изменённые Markdown, ссылки/якоря,
|
||||
достижимость тем, смысл и `git diff --check`. Root allowlist change дополнительно
|
||||
требует tracking-тест. Не запускать application builds/coverage только ради текста.
|
||||
|
||||
Code/dependency changes: full `npm run verify` affected repo после lockfile install;
|
||||
targeted tests ускоряют итерацию, но не подменяют required gate. Wire changes
|
||||
дополнительно требуют backend contract check, HTTP/DB changes — relevant isolated
|
||||
suites по local Testing. Форматирующие `lint:fix`/`format` — mutations, не proof.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Test Intent
|
||||
|
||||
Перед нетривиальным тестом сформулируй наблюдаемый результат и риск регрессии
|
||||
в описании задачи/PR, рядом с тестом либо в рабочем отчёте. Отдельный artifact
|
||||
не обязателен. Для trivial low-risk изменения отдельный Test Intent не нужен.
|
||||
|
||||
Краткая форма, только применимые пункты:
|
||||
|
||||
- **Поведение:** что увидит пользователь/caller и какую ошибку должен поймать тест.
|
||||
- **Варианты и границы:** значимые альтернативы, edge/error states, concurrency.
|
||||
- **Исключено:** какие детали реализации не являются контрактом.
|
||||
- **Уровень:** самая дешёвая boundary, которая надёжно различает правильный
|
||||
и сломанный исход; критерии — в local testing convention.
|
||||
|
||||
Пример: «Два refresh с одним token: один успешный ответ, второй 401;
|
||||
новая session остаётся рабочей. Проверить на реальной изолированной SQLite.
|
||||
Не проверять порядок private calls». Mock race не доказывает DB atomicity.
|
||||
|
||||
Для каждого теста ответь: «Какой regression он обнаружит?» Не создавай
|
||||
`Foo.test.tsx` из-за появления `Foo.tsx`. По умолчанию не тестируй obvious JSX,
|
||||
CSS classes, каждый wrapper/aria attribute, decorators, trivial CRUD wiring,
|
||||
framework и сторонние библиотеки. Проверяй доступность через пользовательское
|
||||
действие/смысл, когда это риск; декларативный атрибут сам по себе не test intent.
|
||||
|
||||
Bug fix сначала воспроизводит исход на responsible boundary. После подходящих
|
||||
проверок остановись: количество тестов и coverage ради coverage не являются целью.
|
||||
Новые harness/framework/fixtures не нужны, когда существующий setup покрывает риск.
|
||||
Reference in New Issue
Block a user