docs: record Next and Go target architecture
This commit is contained in:
1 parent
a235266bed
commit
4485899654
2 files changed
+220
No files matched your search
+165
@@ -0,0 +1,165 @@
|
||||
# Proposal: Next.js Frontend And Go Backend Architecture
|
||||
|
||||
## Status
|
||||
|
||||
- Proposed by task: `20260812-go-backend-migration-6f4a92`
|
||||
- Human direction: confirmed on 2026-08-12
|
||||
- Implementation: not started
|
||||
- Canonical promotion: pending Integration Gate
|
||||
|
||||
## Decision
|
||||
|
||||
Adopt a same-origin, two-workload target architecture:
|
||||
|
||||
```text
|
||||
Browser
|
||||
|
|
||||
v
|
||||
ACK Ingress
|
||||
|-- page and static paths ----------------> Next.js frontend
|
||||
|-- /api, /uploads, /generated-results ---> Go backend
|
||||
|
||||
Next.js frontend -- internal HTTP for SSR --> Go backend
|
||||
Go backend ------> RDS PostgreSQL
|
||||
Go backend ------> Alibaba Cloud OSS
|
||||
Go backend ------> generation providers and Webhook destinations
|
||||
Go backend ------> embedded asynchronous WorkerLoop
|
||||
```
|
||||
|
||||
The initial steady state is one Next.js Pod and one Go Pod. The Go process owns the HTTP backend and the asynchronous task loop. Split the Worker into a third workload only after measured traffic, backlog, independent scaling, or failure-isolation requirements justify the additional deployment and operations cost.
|
||||
|
||||
## Module Interfaces And Seams
|
||||
|
||||
### Next.js frontend Module
|
||||
|
||||
Interface:
|
||||
|
||||
- Serves pages, static assets, and SSR output.
|
||||
- Browser calls remain same-origin and retain the current `/api/**` paths.
|
||||
- SSR forwards the incoming Cookie and request origin to the Go session/introspection interface.
|
||||
|
||||
Implementation constraints:
|
||||
|
||||
- Must not connect to RDS.
|
||||
- Must not hold provider, OSS, billing, or migration credentials.
|
||||
- Must not independently decide account status, organization status, `sessionVersion`, or authorization after the Go identity Module owns them.
|
||||
- Retaining SSR means Next.js remains a server process; it is database-free, not necessarily statically exported.
|
||||
|
||||
### Go backend Module
|
||||
|
||||
External Interface:
|
||||
|
||||
- Preserve current browser and public HTTP paths, JSON fields, status codes, Cookie behavior, idempotency rules, and tenant-not-found behavior.
|
||||
- Own health and database readiness endpoints.
|
||||
|
||||
Deep internal Modules:
|
||||
|
||||
- `Identity`: login, logout, current session, password changes, role and organization authorization.
|
||||
- `Administration`: organizations, accounts, account archival, usage administration, settings visibility, and logs.
|
||||
- `Assets`: upload, registration, list/get/delete, authenticated download, and metadata.
|
||||
- `Jobs`: submit, query, cancel, retry, claim, provider polling, terminal transitions, refunds, and Webhooks.
|
||||
- `Billing`: quotes, wallets, price rules, charges, settlements, refunds, ledger queries, and adjustments.
|
||||
- `Usage`: platform/public attribution and immutable usage recording.
|
||||
|
||||
Internal seams exist only where multiple Adapters are real:
|
||||
|
||||
- Object storage: Alibaba Cloud OSS and a local development Adapter.
|
||||
- Provider execution: Jimeng/Volcengine, EvoLink, Bailian, Seedance, and deterministic fake Adapters.
|
||||
- PostgreSQL transport: `pgx` Pool and transaction Adapter; domain callers do not learn SQL transport details.
|
||||
- Clock/ID sources only where deterministic tests require alternate Adapters.
|
||||
|
||||
Do not create one repository Interface per table or translate every TypeScript store function into a shallow Go RPC.
|
||||
|
||||
### PostgreSQL concurrency authority
|
||||
|
||||
RDS remains the source of truth for relational state and cross-instance concurrency. Go must continue calling:
|
||||
|
||||
- `claim_generation_jobs(text, integer, integer)` for `FOR UPDATE SKIP LOCKED`, lease acquisition, stale-lock recovery, priority, and schedule ordering.
|
||||
- `billing_post_wallet_entry(...)` for organization-scoped idempotency, wallet row locking, balance enforcement, and ledger insertion.
|
||||
|
||||
Do not replace either function with Go process-local locks. A Go Pod restart, multiple replicas, or a rolling update must not weaken job or wallet correctness.
|
||||
|
||||
### WorkerLoop lifecycle
|
||||
|
||||
The initial Go process embeds a context-cancelled WorkerLoop:
|
||||
|
||||
- HTTP readiness becomes healthy only when database schema and required privileges are ready.
|
||||
- WorkerLoop uses a bounded batch and provider concurrency.
|
||||
- Shutdown stops new claims, allows a bounded drain, and releases/ages leases according to the existing database contract.
|
||||
- Horizontal Go scaling also scales WorkerLoop concurrency and database/provider load. Until that coupling is acceptable, keep the Go Deployment replica count explicit.
|
||||
|
||||
## Authentication Compatibility Contract
|
||||
|
||||
The existing `zhinian_session` contract is part of the migration Interface, not an implementation detail:
|
||||
|
||||
- HMAC-SHA256 over base64url JSON payload.
|
||||
- Value format: `payload.signature`.
|
||||
- Cookie chunk size 3000 characters; names `zhinian_session`, `.1`, `.2`, up to 20 chunks.
|
||||
- Payload version 1, `authMode`, expiry, user/client identity, and `sessionVersion` validation.
|
||||
- `HttpOnly`, `SameSite=Lax`, `Path=/`, production `Secure`, and complete chunk clearing on logout.
|
||||
- Each authenticated request revalidates active user, `sessionVersion`, organization state, and role constraints in PostgreSQL.
|
||||
|
||||
Go may parse the existing Cookie to avoid a forced logout. If an implementation deliberately changes the format, the release plan must explicitly announce and test a one-time global re-login.
|
||||
|
||||
## Storage Contract
|
||||
|
||||
Production generated and uploaded assets must use shared object storage before either workload scales horizontally. The current local runtime directory is acceptable only for explicit development or a documented single-Pod fallback.
|
||||
|
||||
The migration should move toward private OSS objects with authenticated or presigned access. Until that is implemented, preserve current URL/storage-path/delete behavior and document the existing `public-read` exposure.
|
||||
|
||||
## Deployment And Secret Ownership
|
||||
|
||||
| Workload | Owns |
|
||||
|---|---|
|
||||
| Next.js | public origin and internal Go base URL; no business Secret |
|
||||
| Go backend | application RDS URL/CA, session Secret, provider keys, OSS credentials, Webhook Secret, public API keys |
|
||||
| Migration Job | separate DDL-capable RDS URL/CA and application role name |
|
||||
|
||||
Ingress routes must explicitly send `/api`, `/uploads`, and `/generated-results` to Go and all page/static paths to Next. The internal Worker tick endpoint and Node Worker Deployment disappear only when the Go WorkerLoop is complete and verified.
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
Although the target is approved as a complete architecture, implementation should remain reversible:
|
||||
|
||||
1. Freeze executable golden contracts for HTTP, Cookie, authorization, database functions, task state, billing, and Webhooks.
|
||||
2. Implement Go health/readiness, configuration, PostgreSQL, and identity foundations.
|
||||
3. Migrate vertical slices behind exact path routing. Only side-effect-free reads may be shadowed.
|
||||
4. Keep exactly one owner for every write path; never dual-write jobs, wallets, OSS objects, login counters, Provider operations, or Webhooks.
|
||||
5. Use expand/contract database changes so the previous release remains deployable during the rollback window.
|
||||
6. Stop and drain the Node Worker, account for provider tasks and existing leases, then enable Go WorkerLoop.
|
||||
7. Remove Next Route Handlers, RDS/provider/OSS Secrets, and Node Worker only after parity tests pass.
|
||||
|
||||
## Required Acceptance Tests
|
||||
|
||||
- Cookie creation/parsing/chunking/tamper/expiry/logout and optional no-logout cross-language compatibility.
|
||||
- Concurrent failed login lockout and concurrent password change.
|
||||
- Cross-user, cross-organization, role, public-client, and 401/403/404 authorization matrix.
|
||||
- Job idempotency, database claim uniqueness, stale lease recovery, retry scheduling, cancellation, and terminal transitions.
|
||||
- Wallet idempotency, concurrent charge/no-overdraft, refund and settlement replay, and organization ledger reconciliation.
|
||||
- Provider recovery around external acceptance versus `provider_task_id` persistence.
|
||||
- Webhook byte/HMAC contract, attempt limits, persisted status, and restart behavior.
|
||||
- OSS upload/download/delete/content-type and URL/storage-path compatibility.
|
||||
- Versioned migration checksum/lock/role privileges and readiness failure for missing schema or grants.
|
||||
- Next SSR without RDS credentials, same-origin browser behavior, ACK manifests, image builds, and controlled rollout/rollback.
|
||||
|
||||
## Consequences
|
||||
|
||||
Benefits:
|
||||
|
||||
- Clear ownership and Secret isolation.
|
||||
- Back-end lifecycle and scaling no longer tied to Next.js upgrades.
|
||||
- Removal of the fragile HTTP polling Worker seam.
|
||||
- Go domain logic can be tested through stable Module Interfaces.
|
||||
|
||||
Costs and risks:
|
||||
|
||||
- Large behavior-compatible rewrite across two languages and build systems.
|
||||
- Contract generation/versioning and distributed tracing become required maintenance.
|
||||
- Authentication, tenant isolation, task recovery, wallet correctness, storage, and Webhooks are high-risk parity areas.
|
||||
- An embedded WorkerLoop couples API replica count with task/provider concurrency until deliberately split.
|
||||
|
||||
## Relationship To Existing Decisions
|
||||
|
||||
- Retains `RDS-001`: production PostgreSQL is explicit and fail-closed.
|
||||
- Retains `RDS-002`: schema changes remain versioned, checksummed, advisory-locked one-shot migrations.
|
||||
- Supersedes `ACK-001` only after implementation: Go, rather than Next Web, owns database access and asynchronous execution; the separate HTTP-polling Node Worker is removed.
|
||||
Reference in new issue
Block a user