chore(api): decommission Next.js UI (#185) #209
No reviewers
Labels
No labels
area:auth
area:ci
area:db
area:infra
area:native
area:pwa
area:service
epic
feature
foundation
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
james/carol!209
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "185-decommission-nextjs-ui"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #185.
Summary
The universal client (
apps/client/) now ports every screen the PWA used to render (#184 slices 1–3) and the API container serves its static bundle as a fallback (#186). This PR deletes the Next.js UI surface so the API is, in fact, just the API plus the SPA shell.What got deleted vs. what stayed
Deleted (UI surface):
apps/api/app/(app)/— every authenticated screen (account, applications, chat, experience, network, notes, profile, projects, skills, plus the layout + sidebar components +dev/design-system playground).apps/api/app/login/,apps/api/app/register/,apps/api/app/offline/— public auth + offline shell.apps/api/app/page.tsx,apps/api/app/layout.tsx,apps/api/app/providers.tsx— root surfaces.apps/api/app/manifest.ts,apps/api/app/sw.ts,apps/api/app/sw-register.tsx— PWA infrastructure.apps/api/app/components/— auth-status, oauth-buttons, theui/primitive set.apps/api/app/themes/— CSS files + the registry init script. (Pure-data preferences moved toapps/api/lib/themes/preferences.ts.)apps/api/tsconfig.sw.json— service-worker TS config.apps/api/lib/i18n/—next-intlrequest config +set-locale-action. Only the deleted UI consumed it.apps/api/lib/query/client.ts— the TanStack Query factory used only byapp/providers.tsx.apps/api/tests/themes/registry.test.ts,apps/api/tests/i18n/resolve.test.ts— tests of deleted modules.Stayed (API surface untouched):
apps/api/app/api/**/route.tshandlers.apps/api/app/[[...spa]]/route.ts(renamed from[...spa]— see the fix commit below).apps/api/lib/api/,apps/api/lib/auth/,apps/api/lib/dto/,apps/api/lib/profile/,apps/api/lib/spa/,apps/api/lib/storage/— all referenced by/api/*.apps/api/lib/themes/—cookie.ts,server.ts, and the newpreferences.tskeep the carol_theme cookie and/api/settingshonest.apps/api/public/icon.svg+icon-192.png+icon-512.png— kept per the ticket; the eventual Expo PWA can reuse them.packages/i18n/messages/— the catalog the universal client consumes.apps/api/lib/dto/— they are all still consumed by/api/*route handlers. None turned out to be UI-only.Wave structure
Each wave is a separate commit so reviewers can take it in chunks:
chore(api): delete pwa screens, components, and themes (#185)— UI pages, shared components, theme registry, plus the preferences-only test split.chore(api): delete root layout, providers, and PWA service worker (#185)— root layout, providers, and the@serwist/nextinfrastructure.chore(api): drop next-intl request config and tanstack query client (#185)— cascading dead code.chore(api): drop UI deps, prune public-route allowlist, refresh docs (#185)—next.config.mjssimplification,package.jsondep removal, lockfile,lib/auth/public-routes.ts,vitest.config.ts, README + CLAUDE.md + docs/ci.md.fix(api): make SPA catch-all optional so/serves index.html (#185)— surfaced during smoke testing.Config / contract changes
apps/api/next.config.mjs— dropped thewithSerwistandwithNextIntlwrappers. Keptoutput: "standalone",outputFileTracingRoot,serverExternalPackages, and the webpack externals.apps/api/package.json— removed@serwist/next,next-intl,serwist,@carol/i18n,@tanstack/react-{query,query-devtools,form,table}, andlucide-react. Lockfile regenerated.apps/api/lib/auth/public-routes.ts— removed/offline,/manifest.webmanifest,/sw.js, and the/workbox-prefix. Kept/,/login,/register, and the favicon icons so the SPA shell remains reachable andproxy.ts's redirect target doesn't loop.README.md— removedDEFAULT_LOCALEandSUPPORTED_LOCALESfrom the Configuration table (the API no longer reads either env var; the client has its own constants).CLAUDE.md— rewrote the "Themes are pluggable" and "No hardcoded user-facing strings" bullets, plus the PWA / TanStack stack-default bullets, to point at the universal client.Catch-all rename —
[...spa]→[[...spa]]The required catch-all only matched paths with at least one segment, so
/was falling through to Next's_not-found. The optional form matches the empty segments case, and the handler normalisesparams.spa ?? []to keep the existing SPA-fallback logic inlib/spa/serve.tsunchanged. Pinned with a new test.PWA regression callout
Deleting
manifest.ts,sw.ts, andsw-register.tsxremoves PWA install + offline shell until the Expo Web bundle ships its own. Tracked in #208 —feat(client): PWA install + offline shell via Expo. The API-side icons (apps/api/public/icon{.svg,-192.png,-512.png}) stay so the Expo follow-up can reuse them.Test plan
All run from the repo root.
pnpm install --frozen-lockfilepnpm -F @carol/api typecheckpnpm -F @carol/api lintpnpm -F @carol/api test(554 passed, 107 skipped)pnpm -F @carol/api openapi:checkpnpm -F @carol/api openapi:coveragepnpm -F @carol/api build(standalone build emits 35 routes —/api/**+[[...spa]])pnpm -F @carol/api-client checkpnpm -F @carol/client typecheckpnpm -F @carol/client lintpnpm -F @carol/client testpnpm -F @carol/client export:webpodman build -t carol:185 .GET /api/health→ 200 JSON{"status":"ok",...}GET /→ 200 HTML (SPA shell)GET /login→ 200 HTML (no redirect, no 404)GET /register→ 200 HTMLGET /_expo/static/js/web/entry-<hash>.js→ 200 withCache-Control: public, max-age=31536000, immutableGET /icon.svg→ 200 image/svg+xmlGET /api/auth/me(unauth) → 401application/problem+json(the proxy keeps API paths on JSON rails)GET /noteswithSec-Fetch-Dest: document(unauth) → 302 to/login?next=%2Fnotes🤖 Generated with Claude Code
Wave 4 of the Next.js UI teardown: - next.config.mjs sheds withSerwist + withNextIntl wrappers; keeps the standalone output, tracing root, and webpack externals needed for the Node-only DB layer. - package.json drops the UI-only deps that became unreachable: @serwist/next, next-intl, @tanstack/react-{query,query-devtools,form,table}, lucide-react, serwist, @carol/i18n. pnpm-lock.yaml regenerated. - lib/auth/public-routes.ts loses /offline, /manifest.webmanifest, /sw.js, and /workbox- (PWA-specific paths deleted with the UI). Keeps /, /login, /register so the proxy redirect to /login still terminates after the catch-all takes over. - vitest.config.ts coverage exclusions slim down — there's no UI left to exclude. - CLAUDE.md (themes / i18n bullets), README.md (env-var table), and docs/ci.md (coverage exclusions) drop the dead-path references. Part of #185, ADR-0027. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>/serves index.html (#185)📊 Test coverage
Patch coverage: no testable lines changed.
Overall (
app/,lib/,db/, excluding UI per ADR-0019):Soft thresholds per ADR-0019. Coverage is informational and does not block merge.
Trivy (container image)
Threshold:
high· Total findings: 121 · At/above threshold: 16.27.0, 7.28.0, 8.5.0