Skip to content

Latest commit

 

History

History
63 lines (54 loc) · 6.58 KB

stack.md

File metadata and controls

63 lines (54 loc) · 6.58 KB

The stack

What each piece is, why the template uses it, and what could go wrong with it. Versions are pinned exactly in package.json; the ADRs hold the longer reasoning.

Piece Why it is here Risk
Node 26, pnpm 12 pnpm blocks dependency build scripts unless allowed, holds back releases younger than a day and refuses a package whose trust level drops (pnpm-workspace.yaml) Low
TypeScript 7 The native compiler keeps pnpm check fast. It has no JavaScript compiler API, so tools that need one run on workarounds (ADR 0002) Medium
TanStack Start and Router, Vite 8 Server rendering, file routes and server functions in one Node service, with typed loaders and search params Medium: Start calls itself a release candidate
Nitro 3 The deployment layer: the production server, graceful shutdown, prerendered static pages (ADR 0004) Medium: beta
React 19 with the React Compiler Memoization without hand-written useMemo, through the stable Babel preset (ADR 0006) Low
Tailwind 4, shadcn/ui on Radix Accessible primitives copied into src/components/ui/, styled with classes only, which the CSP requires (ADR 0010) Low
Effect 4 HttpApi The API contract: schemas, endpoints and typed errors in src/contract, the OpenAPI document generated from it, and handlers tested without a database (ADR 0001, ADR 0007) Medium: 4.0.0 is the first stable release of v4, and most published examples are still v3
Hey API, TanStack Query The client generated from openapi.json: fetch functions, query options and MSW handlers Medium: a next snapshot until a stable release supports TS 7
TanStack Form with Effect Schema Forms validate with the same schemas the server checks, loaded on the first interaction Low
Better Auth Email and password sessions, verification, reset and session management. Account actions run through server functions, and rate limits are counted in Postgres (ADR 0003, ADR 0013) Medium: several workarounds, listed below
Postgres 18, Drizzle ORM 0.45 SQL-shaped queries with typed results, uuidv7() ids, migrations generated by drizzle-kit and linted by squawk (ADR 0005, ADR 0014) Low
Oxlint with tsgolint, Oxfmt, Fallow Type-aware lint, formatting, dead code, architecture boundaries, complexity and duplication, all fast enough for every commit Low; Oxfmt is 0.x
Vitest 5, Playwright, axe Unit, API, component (browser mode) and integration tests in Vitest; end-to-end and accessibility tests in five browser projects Low
Lighthouse behind Caddy Page performance measured over HTTPS and HTTP/2, as in production (ADR 0011) Medium: GitHub's runners score an unchanged page 99 on mobile
lefthook, Renovate, Betterleaks, grype, zizmor Pre-commit jobs, dependency and image-digest updates, secret scanning, image scanning and workflow linting Low; Betterleaks is a 2.0.0 release candidate

The pre-release pieces (TanStack Start, Nitro, Oxfmt, Hey API) are upgraded one per pull request with every gate passing (skill upgrade-prerelease-deps). Most of the churn stays in a few files: the Effect HTTP imports (effect/http-api, effect/http), for example, appear only in src/contract, src/server/api and scripts/openapi.ts.

Upstream issues we track

Code that exists because of an upstream bug or missing feature links the issue next to it. These are the ones that change something here when they are fixed:

Upstream What changes here
hey-api/hey-api#4235 Leave the next snapshot for a stable release (ADR 0002)
typescript-eslint/typescript-eslint#10940 Drop the peer rule for the TanStack lint plugins in pnpm-workspace.yaml
better-auth/better-auth#11078 Replace the endpoint allowlist plugin (src/server/http/auth-endpoints.ts) with enabledPaths
better-auth/better-auth#11433 Lower the /revoke-other-sessions budget in tests/db/query-budget.test.ts to a constant
better-auth/better-auth#9920 Generate the auth schema instead of maintaining src/server/db/schema/auth.ts by hand
TanStack/router#8246 Unknown server function ids answer 404 (ADR 0009)
TanStack/router#7473 Revisit prerendering through Nitro (ADR 0004)
TanStack/router#8520 Route chunks preload their static imports; re-run pnpm lighthouse (ADR 0011)
TanStack/form#2132 Remove src/lib/no-devtools-event-client.ts and its alias in vite.config.ts
GoogleChrome/lighthouse#16539 Mobile scores stop counting preloaded scripts against first paint; CI goes back to the target bar
A Nitro release with nitrojs/nitro#4620 and #4654 (merged after 3.0.260903-beta) Consider Nitro's maxRequestBodySize in place of the bodyLimit middleware in src/start.ts
drizzle-team/drizzle-orm#3807, #5347 Simplify scripts/check-drift.ts (absolute --out, UNLOGGED tables)
microsoft/playwright#42731 Remove the Firefox COOP preference in playwright.config.ts after Playwright 1.63
evilmartians/lefthook#1167 Run the security job of .config/lefthook.yml inline instead of through a pnpm script, once a release has the fix
oxc-project/oxc#17021, #23695 Lint directives through Oxlint instead of tests/unit/repo-policy.test.ts; the plain plugin specifier in .oxlintrc.json
stryker-mutator/stryker-js#6210 Add mutation testing as a gate (below)

Mutation testing

StrykerJS 10's Vitest runner builds its per-test name filter in a way Vitest 5 no longer matches, so every test inside a describe is skipped and every mutant survives. Once a release fixes it, a pnpm mutate script can run Stryker on the files a pull request changes and on all of src/ nightly, with these minimum scores:

Files Minimum score
Every module in COVERAGE_GATE (vitest.config.ts) except the two below 100
src/features/auth/utils/describe-session.ts, src/features/auth/utils/safe-redirect.ts 90
src/features/*/components/**, src/components/errors/** 80