# Дизайн стабилизации 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.