Sergey Krylov 5b9d7f3a27
All checks were successful
CI / ci (pull_request) Successful in 3m20s
CI / ci (push) Successful in 3m1s
docs: fix historical files to new structure and update
2026-06-18 22:04:09 +03:00

334 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Дизайн стабилизации quality gate, API-контракта и документации
## Статус
Одобрено для спецификации 2026-06-14.
## PRD
### Проблема
В MoexVibe накопился координационный технический долг между тестами, сгенерированными контрактами
и документацией. Приложение всё ещё собирается, но стандартный backend quality gate сейчас нельзя
считать надёжным:
- `npm run lint` падает из-за неиспользуемой переменной в backend-тесте.
- `npm run test:backend` падает, потому что часть backend-тестов обращается к живому MOEX API через
настоящий `MoexClientService`.
- Ошибки live MOEX-запросов проявляются как Vitest `DataCloneError`, потому что `AxiosError`
содержит функции в конфигурации запроса, которые нельзя клонировать между worker'ами.
- backend Swagger JSON по `/api/docs-json` и `apps/frontend/src/api/types.ts` не отражают актуальные эндпоинты
`auth`, `portfolios` и `securities/screener`.
- README, AGENTS и страницы Docusaurus местами описывают старое состояние репозитория.
- `npm run build:docs` успешно генерирует статические файлы, но выводит предупреждения Docusaurus о
broken link на `/`.
Из-за этого следующие задачи делать медленнее: разработчику неочевидно, какой вывод команд важен,
какой API-контракт актуален и почему backend-тесты падают: из-за поведения приложения или из-за
сетевой зависимости.
### Цели
1. Сделать стандартные проверки детерминированными и пригодными для локальной разработки и CI.
2. Сохранить live MOEX-проверки, но вынести их из стандартного unit-test пути.
3. Вернуть понятный источник правды для OpenAPI-контракта.
4. Перегенерировать или синхронизировать frontend OpenAPI-типы с текущими backend routes.
5. Привести README, AGENTS и Docusaurus-документацию к текущему состоянию репозитория.
6. Убрать actionable предупреждения Docusaurus о broken links из `npm run build:docs`.
### Не входит в задачу
- Пользовательские feature-изменения.
- Глубокий рефакторинг `PortfolioService` или `MoexClientService`.
- Переход frontend API-клиента на полностью сгенерированный клиент.
- Redis, изменение схемы БД, redesign auth-модели или portfolio analytics.
- Миграция CI-провайдера.
## Текущие находки
### Проходящие проверки
- `npm run test:frontend` проходит: 22 файла, 95 тестов.
- `npm run format:check` проходит.
- `npm run build:backend` проходит.
- `npm run build:frontend` проходит.
- `npm run build:docs` успешно генерирует статические файлы.
### Падающие или шумные проверки
- `npm run lint` падает в `apps/backend/src/modules/securities/screener.service.spec.ts`, потому
что `moexClient` присваивается, но не используется.
- `npm run test:backend` падает с unhandled Vitest errors. Затронутые specs создают настоящий
`MoexClientService` и ходят в MOEX:
- `apps/backend/src/modules/moex-client/moex-client.service.spec.ts`
- `apps/backend/src/modules/securities/securities.service.spec.ts`
- `apps/backend/src/modules/candles/candles.service.spec.ts`
- похожие service specs для shares и bonds тоже зависят от live MOEX-доступа.
- `npm run build:docs` предупреждает, что многие страницы ссылаются на `/`.
### Устаревшая документация и контрактные артефакты
- `AGENTS.md` говорит, что `npm run lint` проверяет только backend, а frontend-тестов нет.
- `apps/docs/docs/development/testing.md` говорит, что frontend-тестов нет.
- `apps/docs/docs/development/commands.md` не описывает `test:frontend`, docs scripts и frontend
lint.
- `apps/docs/docs/frontend/routes.md` не описывает `/login`, `/register`, `/profile`,
`/portfolios`, `/portfolios/:id` и `/screener`.
- `apps/docs/docs/frontend/overview.md` не описывает auth, portfolio, screener и test-директории.
- `apps/docs/docs/backend/api.md` не содержит portfolio и screener endpoints.
- `apps/docs/docs/backend/portfolio.md` документирует `PATCH /api/v1/portfolios/:id/patch`, хотя
controller реализует `PATCH /api/v1/portfolios/:id`.
- backend Swagger JSON по `/api/docs-json` и `apps/frontend/src/api/types.ts` содержат только ранние paths для
health, search, shares, bonds и candles.
## Доменная модель
### Quality Gate
Quality gate: это повторяемая команда, которую разработчик может запускать без внешних зависимостей,
если сама команда явно не говорит обратного.
Стандартные проверки:
- `npm run lint`
- `npm run test:backend`
- `npm run test:frontend`
- `npm run build:backend`
- `npm run build:frontend`
- `npm run build:docs`
- `npm run format:check`
Opt-in проверки:
- Live MOEX integration checks. Они могут требовать network access и не должны запускаться в
стандартных unit tests или CI jobs без явного запроса.
### Источник API-контракта
Авторитетный backend contract: NestJS Swagger document, который генерируется из controllers и DTO
decorators по `/api/docs-json`.
Сгенерированные или синхронизированные артефакты:
- `/api/docs-json`: live Swagger JSON, канонический machine-readable contract.
- `apps/frontend/src/api/types.ts`: сгенерированные TypeScript path и schema types.
- Docusaurus API pages: поясняющая документация, но не канонический machine contract.
### Источник документации
Документация должна описывать текущее состояние репозитория, а не исторический план реализации.
Superpowers specs и plans остаются историей проекта. README, AGENTS и Docusaurus pages являются
актуальной onboarding-поверхностью.
## ADR
### Решение
Разделить backend tests на детерминированные unit tests и opt-in live MOEX integration tests.
### Обоснование
Стандартная backend test command сейчас смешивает unit-поведение и доступность внешней сети. Это
делает failures неоднозначными и порождает шумные Vitest serialization errors, когда Axios
возвращает rejection с non-cloneable configuration fields. Unit tests должны проверять логику
приложения на контролируемых fixtures. Live MOEX tests полезны, но должны быть отдельной явно
названной командой с понятным требованием к окружению.
### Последствия
- `npm run test:backend` становится стабильной offline-командой.
- Live MOEX coverage остаётся доступным через отдельную integration command.
- Часть существующих specs изменится с "real MOEX smoke test" на "service behavior with mocked
`MoexClientService`".
- Contract drift станет видимым, потому что OpenAPI snapshots и frontend generated types будут
обновлены в рамках этой работы.
## Backend Architecture
### Граница unit tests
Service tests для `SharesService`, `BondsService`, `CandlesService` и `SecuritiesService` должны
mock'ать `MoexClientService` и `CacheService`.
Mocked data должны проверять поведение, важное для MoexVibe:
- нормализованные share data возвращаются из cached или fetched MOEX client data;
- нормализованные bond data корректно обрабатывают отсутствующие market fields как nullable values;
- candles мапятся в public response shape;
- search и screener используют детерминированные fixture rows;
- cache metadata остаётся представленной через `{ data, meta }`, где этого требуют service
contracts.
### Граница live integration tests
Live MOEX checks должны быть изолированы в `*.integration.spec.ts` files или эквивалентном явном
test path. Они должны запускаться только через отдельную команду, например
`npm run test:integration -w apps/backend`, и должны документировать, что для них требуется network
access.
Integration command не должна входить в стандартный `npm run test:backend`.
### OpenAPI decorators
Существующие controllers должны отдавать достаточно Swagger metadata для generated path types:
- Auth routes: register, login, refresh, logout, me, profile update.
- Securities routes: search и screener.
- Portfolio routes: list, create, detail, update, delete, position mutations, analytics.
- Существующие shares, bonds, candles и health routes.
В реализации нужно предпочитать существующие DTO и response DTO. Если для response нет DTO и
добавление полного DTO слишком раздувает первый проход, можно использовать минимальные response
decorators без изменения runtime behavior.
## Frontend Architecture
### Generated Types
`apps/frontend/src/api/types.ts` должен быть перегенерирован из текущего backend Swagger JSON после
того, как backend Swagger metadata будет покрывать актуальные routes.
Существующие hand-written `responses.ts` и API wrapper modules остаются на месте в этом эпике. Цель:
свежесть контракта, а не полный rewrite клиента.
### Tests
Frontend tests уже существуют и проходят. Этот эпик не должен переписывать frontend testing
architecture. Если API response types изменятся, frontend tests нужно обновлять только там, где
перегенерированный contract выявит реальное несоответствие.
## OpenAPI Contract Scope
Синхронизированный contract должен включать минимум эти paths под `/api/v1`:
- `GET /health`
- `POST /auth/register`
- `POST /auth/login`
- `POST /auth/refresh`
- `POST /auth/logout`
- `GET /auth/me`
- `PATCH /auth/me`
- `GET /securities/search`
- `GET /securities/screener`
- `GET /securities/shares/{secid}`
- `GET /securities/shares/{secid}/marketdata`
- `GET /securities/shares/{secid}/dividends`
- `GET /securities/shares/{secid}/history`
- `GET /securities/shares/{secid}/candles`
- `GET /securities/bonds/{secid}`
- `GET /securities/bonds/{secid}/marketdata`
- `GET /securities/bonds/{secid}/history`
- `GET /securities/bonds/{secid}/candles`
- `GET /portfolios`
- `POST /portfolios`
- `GET /portfolios/{id}`
- `PATCH /portfolios/{id}`
- `DELETE /portfolios/{id}`
- `POST /portfolios/{id}/positions`
- `PATCH /portfolios/{id}/positions/{positionId}`
- `DELETE /portfolios/{id}/positions/{positionId}`
- `GET /portfolios/{id}/analytics`
## Documentation Architecture
### README
Обновить README так, чтобы quickstart и test sections упоминали backend, frontend и docs
workspaces.
### AGENTS
Обновить AGENTS:
- `apps/docs` является частью workspace.
- `npm run lint` запускает backend и frontend lint.
- frontend tests существуют.
- pre-commit checks существуют через Husky и lint-staged.
- CI существует в `.gitea/workflows/ci.yml`.
### Docusaurus
Обновить текущие onboarding pages:
- development commands;
- testing;
- code generation;
- frontend overview;
- frontend routes;
- frontend API client;
- backend API;
- backend portfolio.
Исправить Docusaurus config или docs links так, чтобы `npm run build:docs` больше не сообщал о
broken links на `/`. Отдельное update-check warning про permissions в `/Users/ksv741/.config`
является внешним к репозиторию и в этот эпик не входит.
## Этапы реализации
### Этап 1: стабилизировать стандартные проверки
1. Исправить неиспользуемую backend test variable, которая ломает lint.
2. Перевести стандартные backend service specs с live MOEX calls на mocked dependencies.
3. Вынести или добавить live MOEX smoke coverage под opt-in integration command.
4. Проверить `npm run lint` и `npm run test:backend`.
### Этап 2: обновить contract artifacts
1. Добавить или завершить Swagger metadata для актуальных routes.
2. Перегенерировать `apps/frontend/src/api/types.ts`.
3. Проверить `/api/docs-json` и синхронизировать `apps/frontend/src/api/types.ts` с текущим contract.
4. Проверить, что generated paths включают auth, screener и portfolio routes.
### Этап 3: обновить документацию
1. Обновить README и AGENTS.
2. Обновить Docusaurus development, frontend, backend и portfolio pages.
3. Исправить Docusaurus broken `/` link warning.
4. Проверить `npm run build:docs`.
### Этап 4: полная проверка
Запустить:
```bash
npm run lint
npm run test:backend
npm run test:frontend
npm run build:backend
npm run build:frontend
npm run build:docs
npm run format:check
```
## Acceptance Criteria
- `npm run lint` завершается с exit code 0.
- `npm run test:backend` завершается с exit code 0 без live MOEX/network dependency.
- `npm run test:frontend` завершается с exit code 0.
- `npm run build:backend` завершается с exit code 0.
- `npm run build:frontend` завершается с exit code 0.
- `npm run build:docs` завершается с exit code 0 и больше не сообщает о Docusaurus broken links на
`/`.
- `npm run format:check` завершается с exit code 0.
- `apps/frontend/src/api/types.ts` содержит актуальные auth, screener и portfolio paths.
- `/api/docs-json` содержит актуальные auth, screener и portfolio paths.
- README, AGENTS и Docusaurus docs больше не утверждают, что frontend tests отсутствуют.
- Portfolio docs используют `PATCH /api/v1/portfolios/:id`, что соответствует controller.
## Риски
- Swagger decorators могут показать DTO gaps, которые раньше были скрыты hand-written frontend
types. Первый проход должен оставаться сфокусированным на свежести paths и schemas; redesign
API-клиента откладывается.
- Live MOEX tests могут по-прежнему падать в окружениях с network restrictions. Это допустимо только
для opt-in integration command, но не для default backend test command.
- Regenerating OpenAPI artifacts может дать большой diff. Generated changes нужно ревьюить отдельно
от hand-written docs changes.
## Self-Review спецификации
- Placeholder scan: placeholder markers и незавершённые sections отсутствуют.
- Internal consistency: default tests остаются offline, live MOEX checks являются opt-in.
- Scope check: scope ограничен quality gates, contract snapshots и актуальностью docs.
- Ambiguity check: acceptance criteria называют конкретные commands и contract paths.