4.1 KiB
ADR-003: Next.js Frontend And Go Backend Target
Status
Accepted and implemented in repository revision b14b4fc on 2026-08-16;
production rollout and live smoke tests remain pending (see DEP-001)
Date
2026-08-12
Context
The original application was a Next.js full-stack Web workload plus a Node process that periodically called an internal Worker tick endpoint. The Go modular monolith subsequently took ownership of the HTTP and business backend, while Next.js retained SSR and an internal Go identity bridge. That remaining server-side frontend seam caused the first production login path to fail with an RSC error and added Web-to-Go DNS/configuration coupling.
The user explicitly approved a stricter boundary: the frontend is a static page set and every runtime API is provided by Go.
Decision
The approved topology has two long-lived same-origin ACK workloads:
- Next.js is a build tool only. An unprivileged Nginx workload serves its static
out/pages and assets. Web has no SSR, Middleware, Route Handlers, runtime ConfigMap, session Secret, database credential, or internal Go URL. - The browser calls same-origin
/api/**,/uploads/**, and/generated-results/**; Ingress routes them directly to Go. Browser route guards are presentation behavior, never an authorization boundary. - Go owns the existing
/api/**,/uploads/**, and/generated-results/**contracts; identity, administration, assets, jobs, billing, usage, providers, storage, Webhooks, readiness, and an initially embedded WorkerLoop. - RDS PostgreSQL remains the source of relational truth and cross-instance concurrency.
- Initial schema creation is a manual/CI operator action using the versioned SQL plus application-role grants. No migration Job reuses the static Web image.
- Split the embedded WorkerLoop into a third workload only after independent scaling or failure-isolation needs are demonstrated.
The implementation must preserve the existing HTTP and Cookie Interface, multi-tenant authorization, idempotency, task state, wallet, storage, and Webhook behavior. It must continue calling claim_generation_jobs and billing_post_wallet_entry; Go process-local locks cannot replace these database functions.
The checked-in source and ACK manifests implement this boundary. The live cluster must still be verified after publishing new immutable Web and Go images.
Rationale
- Establishes clear runtime and Secret ownership between UI and backend.
- Removes request-time frontend rendering and Web-to-Go internal transport.
- Allows backend lifecycle, testing, and future scaling to evolve independently of Next.js.
- Removes the internal HTTP tick seam once the Go WorkerLoop is production-ready.
- Keeps the initial workload count at two rather than introducing a separate API and Worker before evidence justifies it.
- Preserves the already-reviewed PostgreSQL concurrency and migration contracts.
Consequences
- Production pages are public static resources; all protected data and actions must be authorized by Go on every request.
- API failures surface as client state instead of fatal RSC rendering failures.
- New runtime endpoints belong in Go. Reintroducing Next Route Handlers, Middleware authentication, or request-Cookie SSR violates this decision.
- Go API replica count initially also changes WorkerLoop concurrency and provider/RDS load.
- The Web workload can scale independently, but Go remains one replica until generated/uploaded assets use OSS or another shared store.
- Executable HTTP/Cookie compatibility and static-boundary tests are mandatory.
Supersedes
- ACK-001. Production does not deploy the Node Worker or give Web database ownership.
Related
.project-docs/10-decisions/proposals/20260812-go-backend-migration-6f4a92__next-go-architecture.md.project-docs/30-worklog/tasks/20260812-next-go-architecture-4d81e2.md.project-docs/30-worklog/tasks/20260812-go-backend-migration-6f4a92.md.project-docs/10-decisions/proposals/20260816-static-frontend-go-api-4f8c2a7d__static-web-go-api.md.project-docs/30-worklog/tasks/20260816-static-frontend-go-api-4f8c2a7d.md- RDS-001 and RDS-002 in
.project-docs/10-decisions/decision-index.md