Repository navigation
Scaffold and config layer #33
Description
Parent
Spec: #20
What to build
A working project skeleton that a developer can clone, install and run with no third-party accounts of any kind — no Cloudflare, Google Workspace, PostHog or Turnstile. Running the dev server serves a statically prerendered page; the production build emits prerendered HTML alongside a Worker bundle.
Scaffold with Vite+ (vp create @tanstack/start, then vp migrate). The StyleX unplugin must come first in the plugin list. Configure prerendering and the Cloudflare target.
Lint enforces the two rules that can be reliably enforced — no raw elements and no literal JSX strings — scoped to feature code only. The Base component directory is exempt, because Base components exist to render raw tags.
Commit hooks stay fast: format and lint on staged files only. Everything slower runs in CI.
Acceptance criteria
-
vite devserves a page;vite previewserves the production build including prerendered HTML - The build emits prerendered HTML into the client output plus a Worker bundle and generated Wrangler config
-
vp check(format, lint, type-check) passes on a clean tree -
react/forbid-elementsandreact/jsx-no-literalserror in the sections and routes directories, and do not apply to the Base component directory - The Oxlint
reactplugin is listed explicitly, and the default plugin set is re-listed alongside it (settingpluginsreplaces the defaults) -
baseUrlis not set anywhere in tsconfig — tsgolint does not support it and Vite+ silently skips type-checking when present. Path aliases go throughpaths - Husky is not installed; the Vite+ hook dispatcher owns
core.hooksPath - Pre-commit runs format and lint on staged files only — no type-check, no build
- A CI workflow runs full checks plus a build on push and pull request
- Example env files are committed with working local defaults; real env files are gitignored
- A fresh clone runs end to end with every third-party credential absent
Blocked by
None — can start immediately.
Activity
Abuubkar commentedon Sep 5, 2026
Done on branch
ticket/33-scaffold(14a257e). Every acceptance criterion verified by running it, not by inspection.Verified
vite devservesvite previewserves the production builddata-style-srcattributes absentdist/client/index.html,dist/server/index.js,dist/server/wrangler.jsonvp checkpasses<div>→ "is forbidden. Use Box or a layout component from base/"; literal text →jsx-no-literalsbase/reactplugin listed, defaults re-listedpluginsreplaces the default setbaseUrlcore.hooksPathcore.hooksPath = .vite-hooks/_, no.huskystaged: { '*': ['vp fmt', 'vp lint --fix'] }.envor.dev.varsStyleX compiles:
.xe4q7t1{margin-block:4rem}in the CSS and<main class="x28iz9x xe4q7t1 …">in the prerendered HTML, LightningCSS-minified.Two things differed from the plan
1.
jsx-no-literalschecks JSX attributes by default. WithnoStrings: truealone,<html lang="en">and<Box as="main">were errors — structural props, not user-facing copy. Fixed withignoreProps: true, which restricts the rule to children.This also corrects a claim on #11, where I wrote that the rule "catches JSX text children only" and attributes pass unflagged. That is true of the configuration now committed, not of the rule's defaults. The attribute-string gap is real and remains the reason
IconButton,FieldandIconrequire their strings as props.2. Oxfmt would have rewritten the design canvas and every research document.
vp checkinitially reported formatting issues in 19 files includingRCM Landing.dc.htmland all eight research docs. Both are primary sources, and ADR 0001 requires the canvas to stay byte-identical.fmtandlintnow carryignorePatternsfor the canvas,docs/,prototypes/and the generated route tree. Confirmed untouched afterwards.Smaller deviations
@tanstack/cli create --blank --no-toolchain --deployment cloudflarerather thanvp create @tanstack/start. The research's--toolchain noneis no longer valid — the flag is now--no-toolchain, and--blankavoids the Tailwind and devtools starter we do not want. Same end state.pnpm11 moved build-script approval topnpm-workspace.yamlunderallowBuilds, notonlyBuiltDependenciesinpackage.json.~/*per the spec; the scaffold's#/*subpath imports were dropped so there is one alias rather than two.Placeholders for later tickets
A minimal
Box,messages.json,messages.tsand an index route exist only to prove the stack end to end — StyleX compiling,resolveJsonModuleworking, and lint having something legal to pass. #21 replaces the styling with real tokens and #22 replaces the route with the Hero.src/styles/app.cssis real, not placeholder: it carries the reduced-motion block (with*::details-content, which*, *::before, *::afterdoes not cover),[hidden] { display: none !important }, andscrollbar-gutter: stable.Note for #21 and #32
The client bundle measured 100.12 kB gzip, within a hair of the 98.9 kB the research measured independently. The performance budget on #18 is confirmed against a real build of this project.
Abuubkar commentedon Sep 5, 2026
Done on branch
ticket/33-scaffold. All acceptance criteria verified by running the project. Two deviations from plan documented in the resolution comment.Scaffold: TanStack Start + StyleX + Cloudflare, running with no accounts