18 KiB
Дизайн стабилизации quality gate, API-контракта и документации
Статус
Реализовано 2026-06-24. Все этапы выполнены.
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-тесты падают: из-за поведения приложения или из-за сетевой зависимости.
Цели
- Сделать стандартные проверки детерминированными и пригодными для локальной разработки и CI.
- Сохранить live MOEX-проверки, но вынести их из стандартного unit-test пути.
- Вернуть понятный источник правды для OpenAPI-контракта.
- Перегенерировать или синхронизировать frontend OpenAPI-типы с текущими backend routes.
- Привести README, AGENTS и Docusaurus-документацию к текущему состоянию репозитория.
- Убрать 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.tsapps/backend/src/modules/securities/securities.service.spec.tsapps/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 lintnpm run test:backendnpm run test:frontendnpm run build:backendnpm run build:frontendnpm run build:docsnpm 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 /healthPOST /auth/registerPOST /auth/loginPOST /auth/refreshPOST /auth/logoutGET /auth/mePATCH /auth/meGET /securities/searchGET /securities/screenerGET /securities/shares/{secid}GET /securities/shares/{secid}/marketdataGET /securities/shares/{secid}/dividendsGET /securities/shares/{secid}/historyGET /securities/shares/{secid}/candlesGET /securities/bonds/{secid}GET /securities/bonds/{secid}/marketdataGET /securities/bonds/{secid}/historyGET /securities/bonds/{secid}/candlesGET /portfoliosPOST /portfoliosGET /portfolios/{id}PATCH /portfolios/{id}DELETE /portfolios/{id}POST /portfolios/{id}/positionsPATCH /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: стабилизировать стандартные проверки ✅
- Исправлена неиспользуемая backend test variable, которая ломала lint.
- Backend service specs переведены с live MOEX calls на mocked dependencies.
- Live MOEX smoke coverage вынесена под opt-in
test:integrationcommand. npm run lintиnpm run test:backendпроходят.
Этап 2: обновить contract artifacts ✅
- Swagger metadata проверена — все актуальные routes присутствуют.
openapi-artifacts.spec.tsсоздан — проверяет checked-in frontend types.npm run codegen -w apps/frontendвыполнен — types.ts содержит auth, screener, portfolio paths.- Backend и frontend билды проходят.
Этап 3: обновить документацию ✅
- README и AGENTS обновлены (упоминают frontend tests, docs workspace, CI, Husky).
- Docusaurus development, frontend, backend и portfolio pages обновлены.
- Docusaurus broken
/link warning устранён (intro.mdslug: /). npm run build:docsпроходит без broken link warnings.
Этап 4: полная проверка ✅
Все команды завершаются с exit code 0:
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.