Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions plugins/lt-dev/agents/fullstack-updater.md
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,10 @@ end-to-end:

- API: Phases 2 (jest→vitest) and 3 (eslint→oxlint, prettier→oxfmt) of the skill.
- App: Phase 4 of the skill (vitest+happy-dom, oxlint with vue plugin, oxfmt).
- BOTH: Phase 5 (`check` / `check:fix` / `check:envs` scripts), Phase 6
- BOTH: Phase 5 (`check` / `check:fix` scripts), Phase 6
(`scripts/check-server-start.sh` with the ANSI-strip + `NITRO_PORT` guards),
Phase 7 (`config.env.ts` offers pattern), Phase 8 (`scripts/check-envs.sh` +
fixture), Phase 9 (`main.ts` log levels + CORS + `QuietHttpExceptionFilter`),
Phase 7 (`config.env.ts` offers pattern), Phase 8 (env contract test in
`src/config.env.spec.ts`), Phase 9 (`main.ts` log levels + CORS + `QuietHttpExceptionFilter`),
Phase 10 (GitLab CI), Phase 11 (docker-compose healthchecks).

**Critical gotchas to surface in TodoWrite progress** (these consumed days in
Expand Down Expand Up @@ -638,7 +638,7 @@ If blocked at any phase:
| All linting passes (oxlint 0/0 in both subprojects) | ✅ |
| All tests pass (no skips, no `it.skip`, no `--passWithNoTests`) | ✅ |
| `<pm> run check` from monorepo root prints "Successfully ran target check for 2 projects" | ✅ |
| `<pm> run check:envs` (api) prints "All env configurations OK." | ✅ |
| `src/config.env.spec.ts` (api) covers every entry of `REQUIRED_DEPLOYED_ENV_VARS` and passes in `<pm> test` | ✅ |
| Pre-existing failures fixed, not silenced | ✅ |
| Types regenerated (only when api-client is actually imported) | ✅ |
| Report generated | ✅ |
2 changes: 1 addition & 1 deletion plugins/lt-dev/skills/checking-upstream-first/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Both halves of the stack are affected the same way — the frontend is not the e

- `Dockerfile`, `docker-entrypoint.sh`, `.dockerignore`, `.gitlab-ci.yml`
- `tsconfig*.json`, `nest-cli.json`, `.oxlintrc.json`, `vitest*.config.ts`
- `scripts/**` (`check.mjs`, `check-envs.sh`, `check-server-start.sh`), the `check:*` /
- `scripts/**` (`check.mjs`, `check-server-start.sh`), the `check:*` /
`copy:*` / `migrate:*` chains in `package.json`
- `src/config.env.ts`, `.env.example`, `src/main.ts`, `src/server/server.module.ts`,
`migrations/**`
Expand Down
12 changes: 7 additions & 5 deletions plugins/lt-dev/skills/modernizing-toolchain/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
name: modernizing-toolchain
description: 'Migrates lenne.tech projects from the legacy jest+eslint+prettier toolchain to the current vitest+oxlint+oxfmt baseline used by nest-server-starter and nuxt-base-starter. Covers swc decoratorMetadata config, the @Prop union-type fix, supertest default-import correction, the Nitro PORT-vs-NITRO_PORT bug, and the config.env.ts + check-envs.sh patterns. Activates when aligning a project with current starter conventions, and on Mongoose union-type errors or ERR_SOCKET_BAD_PORT crashes. NOT for dependency version bumps (use maintaining-npm-packages). NOT for nest-server major upgrades (use nest-server-updating).'
description: 'Migrates lenne.tech projects from the legacy jest+eslint+prettier toolchain to the current vitest+oxlint+oxfmt baseline used by nest-server-starter and nuxt-base-starter. Covers swc decoratorMetadata config, the @Prop union-type fix, supertest default-import correction, the Nitro PORT-vs-NITRO_PORT bug, and the config.env.ts fail-fast pattern with its contract test. Activates when aligning a project with current starter conventions, and on Mongoose union-type errors or ERR_SOCKET_BAD_PORT crashes. NOT for dependency version bumps (use maintaining-npm-packages). NOT for nest-server major upgrades (use nest-server-updating).'
---

# Modernizing the lenne.tech Toolchain

## When This Skill Activates

- Migrating an existing API/App from jest → vitest, eslint → oxlint, prettier → oxfmt
- Adopting the `check` / `check:fix` / `check:envs` pipeline used by the starters
- Adopting the `check` / `check:fix` pipeline used by the starters
- Debugging Mongoose `"Cannot determine a type for the X field (union/intersection/ambiguous type was used)"` after switching to vitest+SWC
- Debugging `ERR_SOCKET_BAD_PORT` from `node .output/server/index.mjs` in any check pipeline
- Debugging missing or stale `types.gen.ts` after a Nuxt update
Expand Down Expand Up @@ -39,7 +39,7 @@ Eleven phases in fixed order, each assuming the previous one landed. Every phase
| 5 | `check` pipeline |
| 6 | `scripts/check-server-start.sh` (port-robust, ANSI-safe) |
| 7 | `config.env.ts` |
| 8 | `scripts/check-envs.sh` + `tests/fixtures/.env.deployed-test` |
| 8 | Env contract test (`src/config.env.spec.ts`) |
| 9 | `main.ts` |
| 10 | GitLab CI |
| 11 | `docker-compose.yml` |
Expand All @@ -48,15 +48,17 @@ Full commands, file contents and per-phase traps: [`reference/migration-checklis

## Done Signals

After all phases, both must be true:
After all phases, all three must be true:

1. `<pm> run check` from the monorepo root prints
```
Lerna (powered by Nx) Successfully ran target check for 2 projects
```
with both api and app green (audit + format:check + lint + test + build + check-server-start).

2. `<pm> run check:envs` (api) prints `All env configurations OK.` (six envs across two phases).
2. `src/config.env.spec.ts` (api) passes as part of `<pm> test` and covers every unconditional
entry of `REQUIRED_DEPLOYED_ENV_VARS` (deployed envs fail-fast without it, local/e2e/ci start
without any `.env`).

3. **No tests skipped, no warnings tolerated**: pre-existing failures in either subproject must be
fixed as part of the migration, not silenced. The `check` pipeline is intentionally strict —
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,19 +287,15 @@ Adopt these scripts in EACH subproject (api + app). The shape mirrors `nest-serv
"audit": "<pm> audit --omit=dev || echo '\\n[check] audit reported issues; continuing.'",
"check": "<pm> run audit && <pm> run format:check && <pm> run lint && <pm> run test && <pm> run build && bash scripts/check-server-start.sh",
"check:fix": "<pm> install && <pm> run format && <pm> run lint:fix && <pm> run test && <pm> run build && bash scripts/check-server-start.sh",
"check:naf": "<pm> install && <pm> run format && <pm> run lint:fix && <pm> run test && <pm> run build && bash scripts/check-server-start.sh",
"check:envs": "bash scripts/check-envs.sh",
"check:envs:docker": "bash scripts/check-envs.sh --docker"
"check:naf": "<pm> install && <pm> run format && <pm> run lint:fix && <pm> run test && <pm> run build && bash scripts/check-server-start.sh"
}
```

For monorepos, add a root `package.json` aggregator:
```jsonc
{
"check": "lerna run --concurrency 1 check",
"check:fix": "lerna run --concurrency 1 check:fix",
"check:envs": "cd projects/api && <pm> run check:envs",
"check:envs:docker": "cd projects/api && <pm> run check:envs:docker"
"check:fix": "lerna run --concurrency 1 check:fix"
}
```
`--concurrency 1` is **mandatory** so api and app don't fight over MongoDB or ports.
Expand Down Expand Up @@ -354,8 +350,8 @@ The canonical shape:
- `REQUIRED_DEPLOYED_ENV_VARS` array — single source of truth for both the runtime fail-fast
guard and the `.env.example` documentation.
- Auto-derive `appUrl` from `baseUrl` (strip leading `api.`) — operators only set `NSC__BASE_URL`.
- `ci.mongoose.uri` defaults to `127.0.0.1` (NOT `mongo:27017`) so `check:envs` Phase 1 works
outside Docker. CI pipelines override via `NSC__MONGOOSE__URI`.
- `ci.mongoose.uri` defaults to `127.0.0.1` (NOT `mongo:27017`) so the `ci` env boots outside
Docker. CI pipelines override via `NSC__MONGOOSE__URI`.

The fail-fast guard at the bottom of `config.env.ts`:
```ts
Expand All @@ -379,14 +375,27 @@ if (DEPLOYED.has(resolved.env)) {
export default resolved;
```

## Phase 8 — `scripts/check-envs.sh` + `tests/fixtures/.env.deployed-test`
## Phase 8 — Env contract test (`src/config.env.spec.ts`)

The check-envs script verifies all six NODE_ENVs. Phase 1 runs without a `.env` (local/e2e/ci must
start, develop/test/production must fail-fast). Phase 2 with a fixture `.env` (all six must
start). Phase 3 (optional, `--docker`) repeats inside the production image.
The fail-fast guard from Phase 7 is verified by a unit test, so every `<pm> test` and every
`check` run covers it. No separate script, no fixture `.env`, no server boot. The test asserts:

Fixture `tests/fixtures/.env.deployed-test` carries public dummy values for every required
NSC__* var. Generate fresh dummies — never reuse real secrets.
- `develop`, `test` and `production` throw while a required `NSC__*` var is missing, and the
error names every missing var.
- The same envs resolve once all required vars carry a value.
- `local`, `e2e` and `ci` resolve without any `NSC__*` var.
- A `COMPLETE` map of public dummy values covers every unconditional entry of
`REQUIRED_DEPLOYED_ENV_VARS`; a test fails when an entry is added without a dummy. Entries
with a `condition` get their own opt-in case. Generate fresh dummies, never real secrets.

Copy the spec from nest-server-starter and adapt `COMPLETE` to the project's required vars.

Do not adopt a legacy `scripts/check-envs.sh` / `check:envs` script. Observed 2026-09 in
nest-server-starter: it matched the log line "Server startet at" while the app logs "Server
started at", so all nine boot cases hit the 60s timeout, and its Phase 2 copied
`tests/fixtures/.env.deployed-test`, which `.gitignore` (`.env.*`) kept out of every clone. The
script could not pass on any machine; a project still carrying it should delete it along with
the fixture and the `check:envs*` package.json entries.

## Phase 9 — `main.ts` (offers pattern)

Expand All @@ -411,7 +420,6 @@ Two stages (`test`, `build`). Cache root + per-subproject `node_modules`. Jobs:
- `audit`: `allow_failure: true`, prints findings only
- `api:test`: vitest e2e against MongoDB service alias
- `app:test`: Playwright with full api+app server bring-up (mirrors offers)
- `check:envs`: six-env smoke matrix in CI with MongoDB service
- `build`: api + app build

## Phase 11 — `docker-compose.yml`
Expand Down
Loading