# Engineering Standards — Quinn Prospector The house rules for this repo. Project-specific; inherits the workspace-wide TypeScript standards (`~/.claude/instructions/typescript-code-standards.md`) and the no-stubs / SOLID / DRY commandments. When in doubt, match the existing `src/markets/` module — it is the reference implementation of these rules. ## 1. Feature-sliced architecture (backend `src/`) One **NestJS feature module per domain** (`markets/`, `prospects/`, `reports/`, `campaigns/`, …). A module owns one bounded concern and exposes it through: ``` / .module.ts — NestJS wiring (imports, providers, exports) .controller.ts — HTTP surface only (no logic) .service.ts — I/O + orchestration (DB, other services) .ts — pure domain logic, one concern per file dto/*.ts — class-validator request DTOs *.test.ts — co-located Vitest, next to the unit it tests index.ts — public API manifest (the only cross-module entry) README.md — what/why for the feature (see §4) ``` - **No cross-feature reach-in.** Import another feature only through its `index.ts` / its exported `*Module`. Never deep-import its internals. - **New domain → new module**, not a new file bolted onto an existing one. ## 2. Separate pure logic from I/O Domain logic is **pure functions in their own files** (`registry.ts`, `locality.ts`, `tour-window.ts`, `timezone.ts`, `stats.ts`). The `*.service.ts` does I/O (SQL, HTTP) and calls the pure layer. This is why the aggregations are exhaustively unit-testable with no database. - Pure files: no `@Injectable`, no repo, no `Date.now()` baked in — take `now` as a parameter so tests are deterministic. - **Reuse, don't re-implement.** `markets/stats.ts` composes `reports/reports.ts#buildReport` rather than copying the funnel logic. Extract shared logic to a pure module both features import. ## 3. Type & quality discipline - `strict: true`, **no `any`**, no `as unknown as`, no `@ts-ignore`. - **Explicit return types** on every exported function. - **Discriminated unions over boolean flags**; make illegal states unrepresentable. - **No stubs / TODOs / fallbacks** in production code — complete or fail loudly. - **No dead code** — delete it; no `_unused`, no "kept for migration" re-exports. - **File size**: soft 300 LOC, hard 500 (tests exempt). Split god files. - Validate all inputs at the edge (DTOs + `class-validator`); handle every error. ## 4. Filesystem as modular documentation Documentation lives **next to the code it describes**, not in a far-off wiki. - Every feature module has a **`README.md`** stating: what it does, the domain model + key decisions (and what was deliberately rejected), a file table (one concern per row), and the HTTP surface. `src/markets/README.md` is the template. - `src/README.md` is the **module index** — one line per feature, kept current. - Add/refresh a module's README **when you build or materially change it**. Do **not** mass-generate hollow READMEs — an empty doc is worse than none. - Comments explain **why**, not what. Code is the source of truth for "what". ## 5. Testing - **Vitest**, co-located `*.test.ts`. Full-sentence `it('…')` names. - Cover the pure layer exhaustively (it's cheap and deterministic). - Deterministic: pass `now`/seeds in; no wall-clock, no network in unit tests. - Green bar before commit: `npm run typecheck && npm test && npm run build`. ## 6. Persistence & migrations - Schema changes are **numbered SQL migrations** in `migrations/` (`000N_.sql`). - TypeORM entities in `src/entities/` mirror the schema; export via `src/entities/index.ts`. - Mutating an existing table → read-modify-write the full row; never blind upsert. ## 7. Git - **Atomic, scoped commits**: `git commit -- `, never blind `git add -A`. - Conventional-commit subject; end with the `Co-Authored-By` trailer. - **Verify before commit** (§5), **push after** (fast-forward only). - Branch: work on `main` directly (this repo's convention). ## 8. Frontend (`web/`) - Vite + React, served same-origin by this backend; installs as a Chrome PWA. - One **view per `web/src/views/*.tsx`**, wired in `App.tsx` (NAV + router + titles). - All HTTP through `web/src/api.ts` (typed `apiFetch`); no inline `fetch`. - Reuse existing CSS classes (`card`, `funnel`, `vchart`, `bars`) before adding new. - `designs/*.html` are the visual/behavior contract — match them.