Skip to content

Scaffold Next.js frontend in web/ (Track C) - #17

Open
kirillakovalenko wants to merge 2 commits into
mainfrom
feat/scaffold-nextjs
Open

Scaffold Next.js frontend in web/ (Track C)#17
kirillakovalenko wants to merge 2 commits into
mainfrom
feat/scaffold-nextjs

Conversation

@kirillakovalenko

@kirillakovalenko kirillakovalenko commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Scaffolds the Track C frontend in web/ — Next.js 16 (App Router), React 19,
Tailwind 4, TypeScript — configured for static export to Firebase Hosting. It runs,
builds, lints, and is deployable. It renders a placeholder page, deliberately.

Targets main directly. This was originally stacked on #16 so it could build on a tree
with the prototype already archived; now that #16 has merged, that is simply the state
of main, and this PR contains only the Next.js work — 2 commits, 20 files.

Motivation

Implementation-Plan Track C, first task: "Scaffold with static export to Firebase
Hosting."
Track C is meant to run against a mock catalog and a stubbed proxy so it
never blocks on Track A or B — but it needs to exist first.

Changes

  • web/ — Next.js 16 App Router app with src/ layout and @/* import alias.
  • web/next.config.tsoutput: "export", trailingSlash: true (emits
    out/route/index.html, so any static host serves it with no rewrite rules), and
    images.unoptimized (the default next/image loader needs a server).
  • firebase.json at repo root — hosting from web/out, immutable caching for
    /_next/static/**, no-cache for HTML, plus X-Content-Type-Options,
    Referrer-Policy, and X-Frame-Options.
  • .firebaserc.example.firebaserc itself is gitignored until infra is
    provisioned (Phase 0 task 6), so a placeholder project id cannot be deployed by
    accident.
  • web/.env.exampleNEXT_PUBLIC_* only, with a note that in a static export every
    one of those is compiled into browser JavaScript and is therefore public.
  • Replaced the generated start script with preview. next start fails outright
    under output: "export" — it needs a Node server a static export doesn't have, and
    Next.js errors telling you to serve the folder instead. npm run preview does that
    via serve, pinned as a devDependency rather than fetched through npx so it works
    offline. This matters while the team develops locally without deploy access.
  • engines.node >=20.9 and .nvmrc — keeps a team on mixed machines on one Node
    version without reaching for Docker.
  • Root .gitignore — Node/Next/Firebase sections.
  • CLAUDE.md — Commands section now lists the real frontend commands; repo-state and
    Environment sections updated; the route-handler constraint recorded under Target
    architecture.
  • web/README.md — how to run and deploy it, and what is deliberately missing.
  • Dropped the create-next-app Vercel/Next branding SVGs; kept AGENTS.md, which is
    Next 16's own agent guidance and is what pointed me at the bundled docs.

This settles an open question in PRD §5. The PRD lists the market data service as
"Cloud Function / or Next.js route handler". Those are mutually exclusive: under
output: "export" Next.js supports no Route Handlers, Server Actions, Middleware, or
next.config headers/redirects/rewrites. Since Track C specifies static export,
Track B must ship as a standalone Cloud Function. That is why hosting headers are in
firebase.json rather than next.config.ts. Nothing in the PRD's design needs the
features we gave up — no user state is persisted anyway (invariant 1).

What is deliberately missing. The device select screen, symptom form, and result
dashboard all read device_catalog.json, whose schema is frozen in Phase 0 task 9 —
which has not happened. Building them now would invent the contract that Tracks A, B,
and D queue behind, which CLAUDE.md explicitly warns against. So this stops at a running
shell. Also absent: a real favicon (still the Next.js default) and any visual design.

Validation

  • npm run build — compiles, typechecks, and writes a 40-file static export to
    web/out/ with out/index.html titled "Revive or Recycle". Google fonts are
    self-hosted as .woff2 in the bundle, so there is no runtime third-party request.
  • npm run lint — ESLint clean, exit 0.
  • npm run dev — dev server ready in 612ms; curl localhost:3000 returns HTTP 200
    and serves the expected title. Server stopped afterward, port 3000 confirmed clear.
  • npm run preview — serves the built out/ folder, HTTP 200 with the expected
    title. This replaced npm run start, which I confirmed fails with
    "next start" does not work with "output: export" configuration.
  • git status --short — confirms node_modules/, web/out/, and .next/ are all
    correctly ignored; only 19 source and config files are staged.

Not validated: firebase deploy. The Firebase CLI is not installed locally and no GCP
project exists yet (Phase 0 task 6), so hosting config is written but unexercised.

Risk

Low. Additive — this creates a new directory and touches no existing code. There is
nothing deployed to break.

  • firebase.json is unexercised. The public: "web/out" path and header rules are
    written from the docs, not verified against a real deploy. First deploy should be to a
    preview channel.
  • trailingSlash: true fixes the URL shape now (/describe/, not /describe).
    Changing it later after links are public means redirects.
  • Pinned to Next 16 / React 19 / Tailwind 4, all recent majors. Next 16 in particular
    ships an AGENTS.md warning that its APIs differ from older knowledge — I read the
    version's own bundled docs in node_modules/next/dist/docs/ rather than relying on
    recall, and the static-export constraints above come from there.
  • The .firebaserc gitignore is a deliberate departure from the Firebase convention of
    committing it. Once the project id exists the team may prefer to commit it instead;
    that is a one-line change.

Rollout and Recovery

Merges after #16. Nothing ships to users — there is no Firebase project yet, so this
changes no running system. CI (pr-description-check.yml) does not touch web/.

To recover, revert the merge commit; web/ and the two root config files disappear and
nothing else is affected, since no existing file depends on them.

git revert -m 1 <merge-sha>

Follow-ups this unblocks, in order: provision the GCP project and fill .firebaserc
(task 6), freeze device_catalog.json (task 9), then the rest of Track C against the
mock fixture.

kirillakovalenko and others added 2 commits July 29, 2026 08:49
Next.js 16 (App Router) + React 19 + Tailwind 4 + TypeScript, configured
for static export to Firebase Hosting per Implementation-Plan Track C.
Runs, builds, lints, and deploys; renders a placeholder page.

Stops at a running shell on purpose. The device select screen, symptom
form, and result dashboard all read device_catalog.json, whose schema is
frozen in Phase 0 task 9 — building them now would invent the contract
that Tracks A, B, and D queue behind.

Settles an open question in PRD §5: it lists the market data service as
"Cloud Function / Next.js route handler", but Next.js does not support
Route Handlers under output: "export". Track B must ship as a standalone
Cloud Function. Hosting headers move to the repo-root firebase.json,
since next.config headers are unsupported under static export too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`npm run start` failed outright under output: "export" — next start
requires a Node server that a static export does not have. Next.js
errors and points at serving the folder instead.

Replace it with `npm run preview` (serve out), with serve pinned as a
devDependency rather than fetched via npx, so previewing a build works
offline. This matters while the team is developing locally without
deploy access.

Add engines.node >=20.9 and .nvmrc so a team on mixed machines without
Docker stays on one Node version.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jpatrickdevine

Copy link
Copy Markdown
Contributor

@kirillakovalenko I approved but then I realized it's merging into the chore branch? Was that intentional or did you want to merge the feature branch into main?

@kirillakovalenko
kirillakovalenko changed the base branch from chore/archive-legacy-prototype to main July 31, 2026 02:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants