12 KiB
Quality Gate, API Contract, and Documentation Refresh Design
Status
Approved for specification on 2026-06-14.
PRD
Problem
MoexVibe has accumulated coordination debt between tests, generated contracts, and documentation. The application still builds, but the default backend quality gate is not trustworthy:
npm run lintfails on an unused variable in a backend test.npm run test:backendfails because some backend tests call the live MOEX API through the realMoexClientService.- The live MOEX failures surface as Vitest
DataCloneErrorreports because Axios errors contain non-cloneable request configuration functions. docs/openapi/openapi.yamlandapps/frontend/src/api/types.tsdo not include currentauth,portfolios, andsecurities/screenerendpoints.- README, AGENTS, and Docusaurus pages describe an older state of the repo in several places.
npm run build:docssucceeds but emits Docusaurus broken-link warnings for/.
This makes future feature work slower: contributors cannot tell which command output matters, which API contract is current, or whether backend tests are failing because of application behavior or a network dependency.
Goals
- Make default quality checks deterministic and suitable for local development and CI.
- Keep live MOEX checks available, but move them out of the default unit-test path.
- Re-establish a clear source of truth for the OpenAPI contract.
- Regenerate or synchronize frontend OpenAPI types with the current backend routes.
- Bring README, AGENTS, and Docusaurus docs in line with the current repo.
- Remove actionable Docusaurus broken-link warnings from the docs build.
Non-Goals
- No user-facing feature changes.
- No deep refactor of
PortfolioServiceorMoexClientService. - No migration to a fully generated frontend API client.
- No Redis, database, auth model, or portfolio analytics redesign.
- No CI provider migration.
Current Findings
Passing Checks
npm run test:frontendpasses: 22 files, 95 tests.npm run format:checkpasses.npm run build:backendpasses.npm run build:frontendpasses.npm run build:docsproduces static files successfully.
Failing or Noisy Checks
npm run lintfails inapps/backend/src/modules/securities/screener.service.spec.tsbecausemoexClientis assigned but not used.npm run test:backendfails with unhandled Vitest errors. The affected specs instantiate the realMoexClientServiceand call 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- similar service specs for shares and bonds also rely on live MOEX access.
npm run build:docswarns that many pages link to/.
Stale Documentation and Contract Artifacts
AGENTS.mdsaysnpm run lintis backend-only and frontend tests are absent.apps/docs/docs/development/testing.mdsays frontend tests are absent.apps/docs/docs/development/commands.mdomitstest:frontend, docs scripts, and frontend lint.apps/docs/docs/frontend/routes.mdomits/login,/register,/profile,/portfolios,/portfolios/:id, and/screener.apps/docs/docs/frontend/overview.mdomits auth, portfolio, screener, and test directories.apps/docs/docs/backend/api.mdomits portfolio and screener endpoints.apps/docs/docs/backend/portfolio.mddocumentsPATCH /api/v1/portfolios/:id/patch, while the controller implementsPATCH /api/v1/portfolios/:id.docs/openapi/openapi.yamlandapps/frontend/src/api/types.tsonly contain the early health, search, shares, bonds, and candles paths.
Domain Model
Quality Gate
A quality gate is a repeatable command that developers can run without external dependencies unless the command explicitly says otherwise.
Default gates:
npm run lintnpm run test:backendnpm run test:frontendnpm run build:backendnpm run build:frontendnpm run build:docsnpm run format:check
Opt-in gates:
- Live MOEX integration checks. These may use network access and should not run in default unit-test or CI jobs unless explicitly requested.
Contract Source
The authoritative backend contract is the NestJS Swagger document generated from controllers and DTO
decorators at /api/docs-json.
Generated or synchronized artifacts:
docs/openapi/openapi.yamlas a checked-in human-readable snapshot.apps/frontend/src/api/types.tsas generated TypeScript path and schema types.- Docusaurus API pages as explanatory documentation, not the canonical machine contract.
Documentation Source
Documentation should describe the current repository state, not a historical implementation plan. Superpowers specs and plans remain project history; README, AGENTS, and Docusaurus pages are the current onboarding surface.
ADR
Decision
Split backend tests into deterministic unit tests and opt-in live MOEX integration tests.
Rationale
The default backend test command currently mixes unit behavior with external network availability. That makes failures ambiguous and produces noisy Vitest serialization errors when Axios rejects with non-cloneable configuration fields. Unit tests should verify application logic with controlled fixtures. Live MOEX tests are still valuable, but they belong in a separately named command with an explicit environment requirement.
Consequences
npm run test:backendbecomes stable offline.- Live MOEX coverage remains available through a dedicated integration command.
- Some existing specs will change from "real MOEX smoke test" to "service behavior with mocked
MoexClientService". - Contract drift becomes visible because OpenAPI snapshots and frontend generated types are updated as part of this work.
Backend Architecture
Unit Test Boundary
Service tests for SharesService, BondsService, CandlesService, and SecuritiesService should
mock MoexClientService and CacheService.
The mocked data should exercise behavior that matters to MoexVibe:
- normalized share data is returned from cached or fetched MOEX client data;
- normalized bond data handles missing market fields as nullable values;
- candles are mapped into the public response shape;
- search and screener behavior uses deterministic fixture rows;
- cache metadata remains represented through
{ data, meta }where service contracts require it.
Live Integration Test Boundary
Live MOEX checks should be isolated in *.integration.spec.ts files or an equivalent explicit test
path. They should only run through a dedicated command such as npm run test:integration -w apps/backend and should document that network access is required.
The integration command should not be part of the default npm run test:backend command.
OpenAPI Decorators
Controllers that already exist should expose enough Swagger metadata for generated path types:
- Auth routes: register, login, refresh, logout, me, profile update.
- Securities routes: search and screener.
- Portfolio routes: list, create, detail, update, delete, position mutations, analytics.
- Existing shares, bonds, candles, and health routes.
The implementation should prefer existing DTOs and response DTOs. If a response lacks a DTO and adding one would be large, the first pass may use minimal response decorators while keeping runtime behavior unchanged.
Frontend Architecture
Generated Types
apps/frontend/src/api/types.ts should be regenerated from the current backend Swagger JSON after
backend Swagger metadata includes the current routes.
The existing hand-written responses.ts and API wrapper modules remain in place for this epic. The
goal is contract freshness, not a full client rewrite.
Tests
Frontend tests already exist and pass. This epic should not rewrite frontend testing architecture. If API response types change, update frontend tests only where the regenerated contract reveals a real mismatch.
OpenAPI Contract Scope
The synchronized contract should include at least these paths under /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
Update README so quickstart and test sections mention backend, frontend, and docs workspaces.
AGENTS
Update AGENTS to reflect:
apps/docsis part of the workspace.npm run lintruns backend and frontend lint.- frontend tests exist.
- pre-commit checks exist through Husky and lint-staged.
- CI exists under
.gitea/workflows/ci.yml.
Docusaurus
Update current onboarding pages:
- development commands;
- testing;
- code generation;
- frontend overview;
- frontend routes;
- frontend API client;
- backend API;
- backend portfolio.
Fix Docusaurus config or docs links so npm run build:docs no longer reports broken links to /.
The separate update-check warning about /Users/ksv741/.config permissions is external to the repo
and does not need to be fixed in this epic.
Implementation Phases
Phase 1: Stabilize Default Checks
- Fix the unused backend test variable that breaks lint.
- Convert default backend service specs away from live MOEX calls.
- Move or add live MOEX smoke coverage under an opt-in integration command.
- Verify
npm run lintandnpm run test:backend.
Phase 2: Refresh Contract Artifacts
- Add or complete Swagger metadata for current routes.
- Regenerate
apps/frontend/src/api/types.ts. - Synchronize
docs/openapi/openapi.yamlwith the current contract. - Verify generated paths include auth, screener, and portfolio routes.
Phase 3: Refresh Documentation
- Update README and AGENTS.
- Update Docusaurus development, frontend, backend, and portfolio pages.
- Fix Docusaurus broken
/link warning. - Verify
npm run build:docs.
Phase 4: Full Verification
Run:
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 lintexits 0.npm run test:backendexits 0 without live MOEX/network dependency.npm run test:frontendexits 0.npm run build:backendexits 0.npm run build:frontendexits 0.npm run build:docsexits 0 and no longer reports Docusaurus broken links for/.npm run format:checkexits 0.apps/frontend/src/api/types.tsincludes current auth, screener, and portfolio paths.docs/openapi/openapi.yamlincludes current auth, screener, and portfolio paths.- README, AGENTS, and Docusaurus docs no longer claim that frontend tests are absent.
- Portfolio docs use
PATCH /api/v1/portfolios/:id, matching the controller.
Risks
- Swagger decorators may expose DTO gaps that were previously hidden by hand-written frontend types. Keep the first pass focused on path and schema freshness; defer API-client redesign.
- Live MOEX tests may still fail under network restrictions. That is acceptable only for the opt-in integration command, not for the default backend test command.
- Regenerating OpenAPI artifacts can produce broad diffs. Review generated changes separately from hand-written docs changes.
Spec Self-Review
- Placeholder scan: no placeholder markers or incomplete sections.
- Internal consistency: default tests are offline; live MOEX checks are opt-in.
- Scope check: focused on quality gates, contract snapshots, and docs freshness.
- Ambiguity check: acceptance criteria name concrete commands and contract paths.