The shared base tsconfig had strict off, so null-safety and union narrowing were not checked. Strict is now on for apps/web with 5 small typing fixes. check-db.ts and migrate-drafts.js depended on Payload, which is no longer a dependency, and are removed. CLAUDE.md no longer claims Payload. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
47 lines
2.6 KiB
Markdown
47 lines
2.6 KiB
Markdown
# mintel.me
|
|
|
|
Personal website of a senior freelance engineer. Next.js 16 (App Router), pnpm monorepo.
|
|
App lives in `apps/web`. Concept and scope: `apps/web/plans/freelance-relaunch.md` (read it first).
|
|
|
|
## Commands (run from repo root)
|
|
|
|
- `pnpm --filter @mintel/web typecheck` — must pass with zero errors
|
|
- `pnpm --filter @mintel/web test` — unit specs (Vitest); 0 tests run counts as a failure
|
|
- `pnpm --filter @mintel/web test:coverage` — `src/domain` must stay at 100%
|
|
- `pnpm --filter @mintel/web test:mutation` — Stryker on `src/domain`, ~2 min, must score 100
|
|
- `pnpm --filter @mintel/web lint`
|
|
|
|
## How to work here (spec first)
|
|
|
|
1. Write the behavior as concrete cases (inputs, outputs, edge cases, errors) as a `*.spec.ts`.
|
|
2. Run it and confirm it fails for the right reason (missing behavior, not an import error).
|
|
3. Implement the simplest clean solution, run again.
|
|
4. Run typecheck, coverage and mutation. Survivors mean weak specs or dead code: fix one or the other.
|
|
5. Report the exact commands and results. "Done" means they were run on the current code.
|
|
Never weaken, skip or delete a test to make it pass.
|
|
|
|
## Architecture rules
|
|
|
|
- Functional core, imperative shell. Pure logic goes in `apps/web/src/domain/` (no I/O, no clock, no
|
|
randomness, no framework imports; pass `today` etc. in as arguments). Everything there is covered 100%
|
|
and mutation-tested. Pages, routes and adapters stay thin and call into the core.
|
|
- Parse at the boundary into precise types (`Result`, discriminated unions); no nullable state bags.
|
|
- No `any`, `@ts-ignore`, `!` non-null assertions or eslint-disable to silence errors. Fix the cause.
|
|
|
|
## Do not
|
|
|
|
- Read or edit `.env*` (only `.env.example`). Never print or log secrets.
|
|
- Commit scratch files (`tmp*`, `*.log`, `*.tmp`, debug HTML, build output). They are gitignored; keep it so.
|
|
- Use `--no-verify`, force-push, push to `main`, or run `reset --hard`, `clean`, `rm -rf` without asking.
|
|
- Edit `.gitea/workflows/*` or deploy config without asking.
|
|
- Upgrade `vitest` past 4.1.x: `@stryker-mutator/vitest-runner` 10.0.0 runs zero tests per mutant under
|
|
vitest 5 and reports false survivors. Re-verify mutation results after any tooling bump.
|
|
- Add dependencies for trivial things, or touch unrelated code (no drive-by refactors).
|
|
|
|
## Gotchas
|
|
|
|
- Stryker needs `plugins` listed explicitly in `stryker.config.json` (pnpm layout) and ignores the large
|
|
asset folders via `ignorePatterns`; keep them in sync when adding top-level folders.
|
|
- `@mintel/*` packages are `link:` dependencies on a sibling `at-mintel` checkout.
|
|
- Git branches: work on `feat/*`, never directly on `main`.
|