Skip to content

Scaffold and config layer #33

Closed
Closed

Description

@Abuubkar

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 dev serves a page; vite preview serves 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-elements and react/jsx-no-literals error in the sections and routes directories, and do not apply to the Base component directory
  • The Oxlint react plugin is listed explicitly, and the default plugin set is re-listed alongside it (setting plugins replaces the defaults)
  • baseUrl is not set anywhere in tsconfig — tsgolint does not support it and Vite+ silently skips type-checking when present. Path aliases go through paths
  • 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

  1. self-assigned this
    on Sep 5, 2026
  2. Abuubkar commented on Sep 5, 2026

    @Abuubkar
    OwnerAuthor

    Done on branch ticket/33-scaffold (14a257e). Every acceptance criterion verified by running it, not by inspection.

    Verified

    Criterion Evidence
    vite dev serves HTTP 200, SSR'd HTML with StyleX classes
    vite preview serves the production build HTTP 200, and dev-only data-style-src attributes absent
    Build emits prerendered HTML + Worker bundle + generated Wrangler config dist/client/index.html, dist/server/index.js, dist/server/wrangler.json
    vp check passes format + lint + type-check clean on 17 files
    Lint fires in feature code <div> → "is forbidden. Use Box or a layout component from base/"; literal text → jsx-no-literals
    Lint does not fire in base/ same file moved there produces zero errors
    react plugin listed, defaults re-listed setting plugins replaces the default set
    No baseUrl absent, with a comment explaining why
    Husky absent; Vite+ owns core.hooksPath core.hooksPath = .vite-hooks/_, no .husky
    Pre-commit is format + lint on staged only staged: { '*': ['vp fmt', 'vp lint --fix'] }
    CI runs full checks placeholder step is report-only here
    Example env committed, real gitignored staging verified to contain no .env or .dev.vars
    Runs with every credential absent build, dev and preview all ran with test keys and no account

    StyleX 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-literals checks JSX attributes by default. With noStrings: true alone, <html lang="en"> and <Box as="main"> were errors — structural props, not user-facing copy. Fixed with ignoreProps: 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, Field and Icon require their strings as props.

    2. Oxfmt would have rewritten the design canvas and every research document. vp check initially reported formatting issues in 19 files including RCM Landing.dc.html and all eight research docs. Both are primary sources, and ADR 0001 requires the canvas to stay byte-identical. fmt and lint now carry ignorePatterns for the canvas, docs/, prototypes/ and the generated route tree. Confirmed untouched afterwards.

    Smaller deviations

    • Scaffolded with @tanstack/cli create --blank --no-toolchain --deployment cloudflare rather than vp create @tanstack/start. The research's --toolchain none is no longer valid — the flag is now --no-toolchain, and --blank avoids the Tailwind and devtools starter we do not want. Same end state.
    • pnpm 11 moved build-script approval to pnpm-workspace.yaml under allowBuilds, not onlyBuiltDependencies in package.json.
    • Path alias is ~/* 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.ts and an index route exist only to prove the stack end to end — StyleX compiling, resolveJsonModule working, 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.css is real, not placeholder: it carries the reduced-motion block (with *::details-content, which *, *::before, *::after does not cover), [hidden] { display: none !important }, and scrollbar-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.

  3. Abuubkar commented on Sep 5, 2026

    @Abuubkar
    OwnerAuthor

    Done on branch ticket/33-scaffold. All acceptance criteria verified by running the project. Two deviations from plan documented in the resolution comment.

  4. added a commit that references this issue on Sep 5, 2026
    14a257e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

ready-for-agentSpec is complete and ready for an agent to implement

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions