diff --git a/.project-docs/10-decisions/adr-003-next-go-target.md b/.project-docs/10-decisions/adr-003-next-go-target.md index 208451c..6c25a3f 100644 --- a/.project-docs/10-decisions/adr-003-next-go-target.md +++ b/.project-docs/10-decisions/adr-003-next-go-target.md @@ -2,7 +2,7 @@ ## Status -Accepted target; Go implementation merged into `main` on 2026-08-14 (see `.project-docs/30-worklog/current-state.md`); deployment and traffic cutover pending +Accepted target; Go implementation merged into `main` on 2026-08-14 (see `.project-docs/30-worklog/current-state.md`); first production deployment pending — there is no legacy production instance, so no cutover applies (see `DEP-001` in the decision index) ## Date diff --git a/.project-docs/10-decisions/decision-index.md b/.project-docs/10-decisions/decision-index.md index d49d12c..86090d3 100644 --- a/.project-docs/10-decisions/decision-index.md +++ b/.project-docs/10-decisions/decision-index.md @@ -5,14 +5,15 @@ | ID | Decision | Status | Date | Applies To | Detail | |---|---|---|---|---|---| | RDS-001 | Production persistence uses explicit direct PostgreSQL through one server-only adapter; local JSON is explicit development/test mode. | Accepted | 2026-08-12 | Server stores and scripts | `ZHINIAN_DATA_BACKEND=postgres` fails closed and never silently falls back. | -| RDS-002 | Database changes use versioned, checksummed, advisory-locked migrations executed by a one-shot deployment Job. | Accepted | 2026-08-12 | Database schema and ACK rollout | Migrations do not run in each Web pod init container. | -| ACK-001 | Worker remains an HTTP poller and does not receive RDS credentials; Web owns database access. | Accepted | 2026-08-12 | ACK workloads | Worker calls the internal Web Service with a shared internal token. | -| ADR-003 | Target architecture is a same-origin Next.js frontend plus Go modular-monolith backend with an initially embedded WorkerLoop. | Accepted target; Go implementation merged into `main` 2026-08-14; deployment/cutover pending | 2026-08-12 | Application and ACK architecture | Current ACK-001 topology remains authoritative until code migration and cutover pass the required compatibility tests. See `adr-003-next-go-target.md`. | +| RDS-002 | Database changes use versioned, checksummed, advisory-locked migrations. | Accepted; execution amended 2026-08-14 | 2026-08-12 | Database schema and rollout | Initial production schema is executed manually from `database/migrations/*.sql` plus application-role grants; the one-shot Job manifest is retained but not part of the deployment path. | +| ADR-003 | Target architecture is a same-origin Next.js frontend plus Go modular-monolith backend with an initially embedded WorkerLoop. | Accepted target; Go implementation merged into `main` 2026-08-14; first production deployment pending | 2026-08-12 | Application and ACK architecture | First deployment runs the split topology directly; no legacy production instance exists. See `adr-003-next-go-target.md`. | +| DEP-001 | Production starts fresh: the first production deployment runs the ADR-003 split topology (Next.js frontend + Go backend), there is no legacy cutover or Node Worker, and the schema is initialized by manually executed SQL. | Accepted | 2026-08-14 | Deployment model and schema initialization | Human decision: no migration Job pod; super administrator is bootstrapped from `ZHINIAN_BOOTSTRAP_ADMIN_*` configuration at Go startup. | ## Superseded Decisions | ID | Decision | Superseded By | Date | |---|---|---|---| +| ACK-001 | Worker remains an HTTP poller and does not receive RDS credentials; Web owns database access. | `DEP-001`: production never deploys the Node Worker; the Go backend owns database access and embeds the WorkerLoop. | 2026-08-14 | ## Decision Criteria diff --git a/.project-docs/20-architecture/data-flow.md b/.project-docs/20-architecture/data-flow.md index a2ce4bf..d04561d 100644 --- a/.project-docs/20-architecture/data-flow.md +++ b/.project-docs/20-architecture/data-flow.md @@ -6,12 +6,12 @@ |---|---|---|---| | Web persistence | Routes/services/stores | PostgreSQL adapter -> RDS | Parameterized SQL; related statements share one Pool client transaction. | | Worker processing | Worker process | Internal Web Service `/api/internal/worker/tick` | Authenticated by internal token; Worker has no RDS credentials. | -| Schema rollout | ACK migration Job | RDS PostgreSQL | Versioned checksummed migrations under an advisory lock. | +| Schema rollout | Manual SQL execution by the deployment operator | RDS PostgreSQL | Versioned checksummed files under `database/migrations/`; 0001 then 0002, then application-role grants. | | Readiness | ACK probe | Web `/api/ready` -> RDS | Verifies connection, 11 runtime tables, required privileges, and 2 functions. | ## Approved Target Flows -The Go implementation for these flows is merged into `main` under `backend/`; they become active only after the single-writer deployment cutover routes traffic to Go and drains the Node Worker: +The Go implementation for these flows is merged into `main` under `backend/`; they become active on the first production deployment, which routes `/api`, `/uploads`, and `/generated-results` to Go from day one: | Flow | Source | Destination | Required behavior | |---|---|---|---| @@ -34,7 +34,7 @@ The Go implementation for these flows is merged into `main` under `backend/`; th - Alibaba Cloud ACK resources under `deploy/ack/`. - Internal Worker HTTP endpoint is cluster-internal and blocked from public Ingress routing. -In the approved target, the internal Worker HTTP endpoint is removed only after the Node Worker is drained and the Go WorkerLoop is verified. It remains part of the deployed implementation until that cutover. +The internal Worker HTTP endpoint remains part of the local-development implementation only; production never deploys the Node Worker and uses the embedded Go WorkerLoop from the first rollout. ## Last Updated diff --git a/.project-docs/20-architecture/module-map.md b/.project-docs/20-architecture/module-map.md index 8d3e08b..9d4fda4 100644 --- a/.project-docs/20-architecture/module-map.md +++ b/.project-docs/20-architecture/module-map.md @@ -6,9 +6,9 @@ |---|---|---| | `lib/server/database.ts` | Server-only PostgreSQL Pool, TLS, queries, transactions, readiness | Only deep database transport boundary for runtime stores. | | `lib/server/{data-store,account-store,billing-store}.ts` | Domain persistence with PostgreSQL/local implementations | Preserve exported interfaces for callers. | -| `database/migrations/` | Immutable versioned PostgreSQL schema changes | Applied by `scripts/migrate-postgres.mjs`; 0001 initial schema, 0002 generation lifecycle fencing. | +| `database/migrations/` | Immutable versioned PostgreSQL schema changes | Executed manually for the first deployment (0001 initial schema, 0002 generation lifecycle fencing); the Node runner and Job manifest are retained but not part of the deployment path. | | `scripts/postgres-client.mjs` | Validated database configuration for Node operations scripts | Shared by migration/bootstrap/import scripts. | -| `deploy/ack/` | ACK deployment resources and secret/config templates | Migration Job precedes Web/Worker rollout; Go ownership changes wait for cutover. | +| `deploy/ack/` | ACK deployment resources and secret/config templates | First production deployment uses the split topology; the migration Job manifest is deprecated (manual SQL). | | `app/api/ready/route.ts` | Database/schema/privilege readiness endpoint | Separate from process-level liveness. | | `backend/cmd/zhinian-api` | Go application entrypoint, configuration, HTTP server composition, readiness | Locally runnable; production routing still owned by Next.js. | | `backend/internal/*` | ADR-003 deep modules and adapters, 18 packages: `identity`, `administration`, `assets`, `billing`, `usage`, `jobs`, `providers`, `webhook`, `httpapi`, `publicapi`, `application`, `orchestration`, `postgres`, `localstore`, `logging`, `settings`, `templates`, `prompt` | Merged into `main`; unrouted until cutover. | @@ -22,7 +22,7 @@ ## Approved Target Module Map -The target below is implemented in `backend/internal/` and merged into `main`; deployment and traffic cutover remain pending: +The target below is implemented in `backend/internal/` and merged into `main`; the first production deployment remains pending: | Target Module | Go package | Implementation notes | |---|---|---| diff --git a/.project-docs/20-architecture/system-overview.md b/.project-docs/20-architecture/system-overview.md index ef4a95e..ba767d6 100644 --- a/.project-docs/20-architecture/system-overview.md +++ b/.project-docs/20-architecture/system-overview.md @@ -2,9 +2,9 @@ ## Current Architecture -The deployed production architecture is the Next.js Web workload plus a separate HTTP-polling Node Worker. Production server state is stored directly in PostgreSQL through a shared server-only adapter; development and tests can explicitly use local JSON. ACK deploys database migration, Web, Worker, Service, and Ingress resources separately. +There is no deployed production architecture yet. Local development keeps the Next.js full-stack Web workload plus the HTTP-polling Node Worker; production server state is stored directly in PostgreSQL through a shared server-only adapter, and development/tests can explicitly use local JSON. -ADR-003's Go backend is implemented and merged into `main` under `backend/` (see the Module Map), but no Go workload is deployed and no production traffic is routed to it. Until the single-writer cutover passes its compatibility checks, the Next.js/Node topology above remains the deployed and authoritative truth. +The first production deployment will run the ADR-003 split topology directly: Next.js serves pages/static/SSR, and the merged Go backend under `backend/` owns `/api`, `/uploads`, and `/generated-results`. There is no legacy production instance, so there is no cutover and no Node Worker in production — the Go process embeds the WorkerLoop from day one. The deployment artifacts for the Go workload are still to be built. ## Approved Target Architecture @@ -12,20 +12,20 @@ The accepted target in ADR-003 is a same-origin Next.js frontend plus Go modular | Target component | Responsibility | Constraint | Implementation state | |---|---|---|---| -| Next.js frontend | Pages, static assets, SSR, browser UI | Calls Go over HTTP; no RDS/provider/OSS/business Secret. | Existing; unchanged until cutover. | -| Go backend | Existing HTTP/file contracts, identity, administration, assets, jobs, billing, usage, providers, storage, Webhooks, readiness | Owns relational access and initially embeds WorkerLoop. | Implemented in `backend/` and merged; unrouted in production. | -| RDS PostgreSQL | Relational state and cross-instance concurrency | Retains versioned migrations and both concurrency-sensitive database functions. | Production database; migrations 0001/0002 apply at rollout. | -| Migration Job | Schema and application-role grants | Remains one-shot and separate from long-lived workloads. | Existing Job; migration 0002 included. | +| Next.js frontend | Pages, static assets, SSR, browser UI | Calls Go over HTTP; no RDS/provider/OSS/business Secret. | Local dev also runs its API routes; production serves pages only. | +| Go backend | Existing HTTP/file contracts, identity, administration, assets, jobs, billing, usage, providers, storage, Webhooks, readiness | Owns relational access and embeds the WorkerLoop. | Implemented in `backend/` and merged; first production deployment pending. | +| RDS PostgreSQL | Relational state and cross-instance concurrency | Retains versioned migrations and both concurrency-sensitive database functions. | Schema initialized by manual SQL (migrations 0001/0002) plus role grants. | +| Migration Job | Schema and application-role grants | Remains one-shot and separate from long-lived workloads. | Manifest retained but not used; initial schema is executed manually. | | Alibaba Cloud OSS | Shared generated/uploaded assets | Must be production-ready before horizontal workload scaling. | Still behind a storage Adapter; not validated against real OSS. | -Ingress will eventually route page/static paths to Next.js and `/api`, `/uploads`, and `/generated-results` to Go. The initial target remains two long-lived Pods (`Next x1 + Go x1`). The Go implementation is complete and merged; deployment and traffic cutover are not. +Ingress will route page/static paths to Next.js and `/api`, `/uploads`, and `/generated-results` to Go from the first deployment. The initial target is two long-lived Pods (`Next x1 + Go x1`). ## Main Components | Component | Responsibility | Notes | |---|---|---| | Next.js Web | Browser/API routes, domain services, persistence calls, internal Worker tick endpoint | Owns the PostgreSQL pool and `/api/ready` until cutover. | -| Worker | Periodically invokes the internal Worker tick endpoint | No direct database connection or RDS Secret. | +| Worker | Periodically invokes the internal Worker tick endpoint | Local development only; production uses the embedded Go WorkerLoop. | | PostgreSQL adapter | Backend selection, Pool lifecycle, TLS, parameterized queries, transactions, readiness | Server-only module at `lib/server/database.ts`. | | Go backend | `cmd/zhinian-api` plus 18 `internal/` packages: identity, administration, assets, billing, usage, jobs, providers, webhook, httpapi, publicapi, application, orchestration, postgres, localstore, logging, settings, templates, prompt | Merged into `main`; locally runnable and contract-tested; unrouted in production. | | Contract fixtures | Language-neutral JSON contracts for auth, admin, assets, billing, http, jobs, logs, providers, settings, usage, webhook under `contracts/` | Shared executable acceptance source for TypeScript and Go consumers. | @@ -39,12 +39,13 @@ Ingress will eventually route page/static paths to Next.js and `/api`, `/uploads - Store callers depend on stable store interfaces, not `pg` or SQL details. - Multi-statement consistency uses one transaction client; atomic job claim and wallet posting remain database functions. - Database credentials are injected only into Web and migration workloads; Worker uses the internal HTTP boundary. -- The merged Go implementation must not be routed in production before the cutover review; Next Route Handlers, Secrets, and ACK manifests stay under their current owners until then. +- The Go implementation must be validated against non-production RDS/OSS/provider/Webhook dependencies before the first production rollout; Next Route Handlers stay in the repository for local development. ## Related Decisions -- Current implementation: `RDS-001`, `RDS-002`, and `ACK-001`. -- Accepted target: `ADR-003`; it supersedes ACK-001 only after verified implementation and cutover. +- Current implementation: `RDS-001` and `RDS-002` (schema execution now manual SQL per `DEP-001`). +- Accepted target: `ADR-003`; it supersedes ACK-001 once the first production deployment runs the Go stack. +- First-deployment model: `DEP-001`. ## Last Updated diff --git a/.project-docs/30-worklog/current-state.md b/.project-docs/30-worklog/current-state.md index 294321e..2957f77 100644 --- a/.project-docs/30-worklog/current-state.md +++ b/.project-docs/30-worklog/current-state.md @@ -8,13 +8,14 @@ This file is the integrated default-branch snapshot. Feature tasks record progre - `79d29bb` (cross-platform ACK manifest validation fix) - `4485899` (task-scoped Next.js frontend plus Go backend target design and explicit not-implemented progress record) - `064e155` (canonical ADR-003, architecture, current-state, history, and commitment promotion) -- `b8db39d` (merge of `aef5a97` — completed Go backend modules: foundation, identity, current-session, password lifecycle, plus remaining modules; tasks `20260812-go-migration-foundation-b74c9e21`, `20260813-go-identity-vertical-c4e91a72`, `20260813-go-auth-me-http-8d6f3a21`, `20260813-go-auth-lifecycle-3f9a6c12`, `20260813-go-remaining-modules-7d3a9e42`) +- `b8db39d` (merge of `aef5a97` — completed Go backend modules; tasks `20260812-go-migration-foundation-b74c9e21`, `20260813-go-identity-vertical-c4e91a72`, `20260813-go-auth-me-http-8d6f3a21`, `20260813-go-auth-lifecycle-3f9a6c12`, `20260813-go-remaining-modules-7d3a9e42`) - `d0fb346` (merge of `c1cbd78` — Go backend implementation, contract fixtures, migration 0002, and task-scoped records into `main`; tasks `20260813-go-remaining-modules-7d3a9e42` and `20260814-go-remaining-integration-5e7c9a1b`) - `f10cdd9` (record of completed task `20260812-architecture-task-breakdown-a83f61c2`) +- `ff055c9` (config-driven super-admin bootstrap in the Go backend, task `20260814-go-bootstrap-admin-6e2b7d9c`) ## Current Focus -ADR-003's Go modular-monolith backend is implemented and merged into `main` under `backend/`: `cmd/zhinian-api` plus 18 `internal/` packages (154 Go files), 24 language-neutral contract fixtures under `contracts/`, and lifecycle-fencing migration `0002_generation_lifecycle_fencing.sql`. The deployed production architecture remains the Next.js full-stack Web plus HTTP-polling Node Worker (ACK-001): no Go traffic cutover, Next Route Handler deletion, or manifest/Secret ownership change has happened, and no Go workload is deployed. +ADR-003's Go modular-monolith backend is implemented and merged into `main` under `backend/` (`cmd/zhinian-api`, 18 `internal/` packages, 24 contract fixtures, migration 0002). There is no production instance of this application yet: the **first production deployment** will run the ADR-003 split topology directly — Next.js serves pages/static/SSR, Go owns `/api`, `/uploads`, and `/generated-results` — so there is no legacy cutover, no Node Worker drain, and no legacy production session compatibility to preserve. Next.js route handlers remain in the repository for local development only. The production schema is initialized by manually executing the versioned SQL files; the ACK migration Job is not part of the deployment path. ## Recently Completed @@ -22,31 +23,33 @@ ADR-003's Go modular-monolith backend is implemented and merged into `main` unde - 2026-08-12: Added versioned PostgreSQL migrations, strict backend selection, verified-CA TLS, database readiness, and ACK Web/Worker/migration manifests. - 2026-08-12: Accepted and documented the Next.js frontend plus Go backend target, migration contracts, and acceptance criteria. - 2026-08-14: Implemented and merged the Go backend (foundation, identity, administration, assets, billing, usage, jobs/providers/webhooks/worker loop, public and compatibility HTTP surfaces) with language-neutral contract fixtures and migration 0002. -- 2026-08-14: Reconciliated canonical architecture, decision, history, commitment, and positioning memory with the merged Go implementation (task `20260814-go-memory-reconcile-7f2a9c41`). +- 2026-08-14: Reconciled canonical architecture, decision, history, commitment, and positioning memory with the merged Go implementation (task `20260814-go-memory-reconcile-7f2a9c41`). +- 2026-08-14: Added config-driven first-super-administrator bootstrap to the Go backend (task `20260814-go-bootstrap-admin-6e2b7d9c`). +- 2026-08-14: Recorded the first-deployment model: no production cutover, manual schema initialization without the migration Job pod (task `20260814-deploy-model-reconcile-9b4c2e7f`). ## In Progress -- None. All Go implementation feature tasks are merged; five feature worktrees remain `ready_for_integration` with completed records and can be released after review. +- None. ## Next Recommended Steps -1. Validate the merged Go backend against a non-production RDS instance (real application role, verified-CA TLS), real OSS, provider credentials, external Webhooks, and production-like Worker recovery before any Go traffic cutover. -2. Obtain the product/release decisions deferred by ADR-003: parse existing `zhinian_session` cookies without logout versus one-time global re-login, and the public `/api/v1` compatibility promise. -3. After validation, plan the single-writer cutover: route `/api`, `/uploads`, and `/generated-results` to Go, drain and stop the Node Worker, and only then delete Next Route Handlers and relocate RDS/provider/OSS Secrets and ACK manifests. -4. Release the five completed Go feature worktrees once their records and merges are confirmed. +1. Build the Go workload deployment artifacts for the first production deployment: Go container image, ACK Deployment/Service manifests, and Ingress routing that sends page/static paths to Next.js and `/api`, `/uploads`, `/generated-results` to Go. +2. Initialize the production schema by manually executing `database/migrations/0001_initial_schema.sql` then `0002_generation_lifecycle_fencing.sql` as the migration role, then apply the application-role grants (tables plus the two concurrency functions). +3. Configure `ZHINIAN_BOOTSTRAP_ADMIN_*` on the first Go startup; the process creates the first super administrator exactly once. +4. Validate against non-production RDS (real application role, verified-CA TLS), real OSS, provider credentials, and external Webhooks before the first production rollout. +5. Confirm the public `/api/v1` compatibility promise for external consumers. ## Open Questions / Blockers - Target RDS PostgreSQL version, connection budget, endpoint, TLS enforcement, CA bundle, database roles, and ACK network policy remain deployment inputs. -- Go Cookie compatibility (no-logout parsing versus forced re-login) still needs a product decision. -- Public `/api/v1` compatibility obligations for the cutover need explicit confirmation. +- Real OSS bucket/credential configuration is still needed for shared asset storage. +- Public `/api/v1` support promises for external consumers need explicit confirmation. ## Risky Areas -- Database migrations and least-privilege grants must be tested against the actual RDS instance before production cutover. -- Web pods still own runtime files; PostgreSQL does not make local uploads/generated assets safe for horizontal Web scaling. +- Database grants and least-privilege roles must be tested against the actual RDS instance before the first rollout. - The current image runs as root; moving to a non-root user requires an explicit writable-path ownership design. -- The merged Go code is contract-tested but unrouted; parity gaps can only surface under real provider, OSS, RDS, and Webhook traffic. +- The Go code is contract-tested but has never run against real provider, OSS, RDS, and Webhook traffic; parity gaps can only surface under real dependencies. ## Last Updated diff --git a/.project-docs/30-worklog/tasks/20260814-deploy-model-reconcile-9b4c2e7f.md b/.project-docs/30-worklog/tasks/20260814-deploy-model-reconcile-9b4c2e7f.md new file mode 100644 index 0000000..18ee3bd --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260814-deploy-model-reconcile-9b4c2e7f.md @@ -0,0 +1,47 @@ +# Task: Record first-deployment model and manual schema initialization + +## Identity + +- Task ID: 20260814-deploy-model-reconcile-9b4c2e7f +- Mode: Integration +- Branch: main +- Worktree: /Users/brother7/Documents/AI/NianAIGC +- Base commit: ff055c972de50f34ac6eabf3e977610949482bba +- Owner: dsh +- Status: Ready for Integration + +## Scope + +- Apply two human decisions from 2026-08-14 to canonical memory and deployment documentation: + 1. There is no production cutover: the first production deployment runs the ADR-003 split topology (Next.js frontend + Go backend) directly; no legacy production instance, no Node Worker in production. + 2. Schema initialization is executed manually with the versioned SQL files; the ACK migration Job pod is not deployed. +- Related: the first super administrator is created from `ZHINIAN_BOOTSTRAP_ADMIN_*` configuration at Go startup (implemented in task `20260814-go-bootstrap-admin-6e2b7d9c`); legacy account import is not required. + +## Intent And Constraints + +- Keep the versioned-SQL discipline (RDS-002); only the execution mechanism changes from the one-shot Job to manual execution. +- Do not claim any production validation that has not happened. +- Keep the migration Job manifest on disk, marked deprecated, for optional future automation. + +## Outcome + +- Added `DEP-001` to the decision index; moved `ACK-001` to Superseded Decisions; amended `RDS-002` execution detail; updated the ADR-003 status to "first production deployment pending". +- Rewrote `current-state.md` Current Focus, Next Recommended Steps, Open Questions, and Risky Areas around the first-deployment model; recorded `ff055c9` under Integrated Through. +- Updated `system-overview.md`, `module-map.md`, and `data-flow.md` to describe the split-topology first deployment and manual schema initialization. +- Updated `commitments.md` (dropped cutover obligations; added Go deployment artifacts, manual schema init, bootstrap config, and first-rollout validation commitments) and `business-rules.md` (manual schema execution rule; removed the moot cookie-compatibility question). +- Updated deployment guidance in `docs/DEPLOYMENT.md`, `README.md`, and `README.zh-CN.md` to manual SQL execution and config-driven bootstrap; marked `deploy/ack/migration-job.yaml` deprecated with a header comment. + +## Verification + +- `check_project_docs.py` and `check_doc_drift.py --task-id 20260814-deploy-model-reconcile-9b4c2e7f` pass. +- `npm run deploy:check` passes with the deprecated manifest comment in place. + +## Follow-ups + +- Build the Go workload deployment artifacts (image, manifests, Ingress split) for the first production deployment. +- Execute the manual schema initialization and role grants against the real RDS before the first rollout. +- Decide whether to delete the deprecated `migration-job.yaml` later. + +## Promotion Candidates + +- None beyond what this integration task already applied. diff --git a/.project-docs/40-domain/business-rules.md b/.project-docs/40-domain/business-rules.md index 4c9fa0e..4f96fad 100644 --- a/.project-docs/40-domain/business-rules.md +++ b/.project-docs/40-domain/business-rules.md @@ -10,13 +10,12 @@ - All new organization balance entries are organization-owned; generation charge/refund entries keep member attribution for consumption reporting. - Logged-in users may change their own password; account management and organization member actions require admin roles. - Public `/api/v1` access authenticates with API keys and stays outside browser SSO middleware; API data is partitioned by the API account owner. -- Database schema changes ship as versioned, checksummed, advisory-locked one-shot migrations; they never run in each Web pod init container. +- Database schema changes stay versioned and checksummed in `database/migrations/`; the initial production schema is created by manually executing the SQL files plus application-role grants (no migration Job pod), and schema changes must never run inside long-lived pod startup. - Generated and uploaded assets remain runtime/object-storage state; PostgreSQL does not make them shared for horizontal scaling. ## Open Questions -- Whether Go must parse existing `zhinian_session` cookies without logout, or a one-time global re-login is acceptable at cutover. -- The exact public `/api/v1` compatibility promise to preserve during and after the Go cutover. +- The exact public `/api/v1` compatibility promise to preserve for external consumers. ## Last Reviewed diff --git a/.project-docs/80-commitments/commitments.md b/.project-docs/80-commitments/commitments.md index 855d7f5..7d3253e 100644 --- a/.project-docs/80-commitments/commitments.md +++ b/.project-docs/80-commitments/commitments.md @@ -4,12 +4,15 @@ Track future-facing memory: promised follow-ups, unfinished loops, timed checks, | Date | Commitment | Trigger / Due | Owner | Status | Next Action | |---|---|---|---|---|---| -| 2026-08-12 | Validate migration, TLS, permissions, and readiness against the real Alibaba Cloud RDS instance. | Before production cutover | Deployment owner | Open | Back up RDS, provision roles/CA/network access, then run the one-shot migration Job. | -| 2026-08-12 | Keep Web at one replica until generated assets use OSS or another shared store. | Before raising Web replicas | Deployment owner | Open | Configure and validate external object storage. | +| 2026-08-12 | Validate migration, TLS, permissions, and readiness against the real Alibaba Cloud RDS instance. | Before the first production rollout | Deployment owner | Open | Back up RDS, provision roles/CA/network access, then execute the SQL files manually. | +| 2026-08-12 | Keep each workload at one replica until generated assets use OSS or another shared store. | Before raising replicas | Deployment owner | Open | Configure and validate external object storage. | | 2026-08-12 | Harden the runtime image to non-root after writable paths are designed. | Security hardening follow-up | Application owner | Open | Define ownership for runtime and settings paths, then update Docker/ACK security context. | | 2026-08-12 | Implement ADR-003 only after executable compatibility contracts exist. | Before starting the Go migration | Application owner | Completed | Contracts exist under `contracts/`; Go implementation merged 2026-08-14. | -| 2026-08-14 | Validate the merged Go backend against non-production RDS, real OSS, provider credentials, external Webhooks, and production-like Worker recovery before any Go traffic cutover. | Before Go cutover | Deployment owner | Open | Stand up non-production RDS/OSS and run the contract and recovery suites against the Go binary. | -| 2026-08-14 | Decide Cookie cutover behavior (parse existing `zhinian_session` without logout vs. one-time global re-login) and confirm the public `/api/v1` support promise. | Before freezing cutover contracts | Product owner | Open | Product/release decision with explicit re-login or no-logout announcement. | +| 2026-08-14 | Build the Go workload deployment artifacts: container image, ACK Deployment/Service manifests, and Ingress routing that sends page/static paths to Next.js and `/api`, `/uploads`, `/generated-results` to Go. | Before the first production deployment | Application owner | Open | Create the Go Dockerfile, split-topology manifests, and Ingress rules, then validate on a non-production cluster. | +| 2026-08-14 | Initialize the production schema by manually executing `database/migrations/0001_initial_schema.sql`, then `0002_generation_lifecycle_fencing.sql`, then the application-role grants. No migration Job pod is deployed. | Before the first Go/Web rollout | Deployment owner | Open | Run the SQL as the migration role against RDS and verify the application-role grants with the readiness checks. | +| 2026-08-14 | Configure `ZHINIAN_BOOTSTRAP_ADMIN_PHONE` / `ZHINIAN_BOOTSTRAP_ADMIN_PASSWORD` / `ZHINIAN_BOOTSTRAP_ADMIN_NAME` for the first Go startup; the process creates the first super administrator exactly once. | First Go startup | Deployment owner | Open | Provide strong bootstrap credentials through the deployment Secret/ConfigMap. | +| 2026-08-14 | Validate the Go backend against non-production RDS, real OSS, provider credentials, and external Webhooks before the first production rollout. | Before the first production deployment | Deployment owner | Open | Stand up non-production RDS/OSS and run the contract and recovery suites against the Go binary. | +| 2026-08-14 | Confirm the public `/api/v1` support promise for external consumers. | Before the first production deployment | Product owner | Open | Product decision on which v1 endpoints and behaviors are guaranteed for partners. | ## Use diff --git a/.project-docs/90-maintenance/stale-items.md b/.project-docs/90-maintenance/stale-items.md index af06b72..849ebc7 100644 --- a/.project-docs/90-maintenance/stale-items.md +++ b/.project-docs/90-maintenance/stale-items.md @@ -10,8 +10,8 @@ This is the integrated registry of stale or conflicting canonical memory. Update ## Missing Context - RDS deployment inputs (target version, connection budget, endpoint, TLS/CA bundle, database roles, ACK network policy) — needed before production validation. -- Go Cookie compatibility decision (no-logout parsing versus forced re-login) and the public `/api/v1` support promise — needed before freezing cutover contracts. - Real OSS bucket/credential configuration — needed before horizontal scaling or Go asset validation. +- The public `/api/v1` support promise for external consumers — needed before the first production deployment. ## Feature Task Routing diff --git a/README.md b/README.md index 9c6d344..c12fced 100644 --- a/README.md +++ b/README.md @@ -247,7 +247,7 @@ cp .env.example .env.local database/migrations/ ``` -首次部署和每次发布均先执行 `npm run db:migrate`。迁移器使用 advisory lock、版本记录和校验和,避免多个发布任务并发迁移或已应用脚本被静默改写。 +首次部署和每次 schema 变更均按 `database/migrations/*.sql` 中的版本化 SQL 文件手工执行(先 0001 后 0002,再加角色授权语句),不部署迁移 Job Pod;执行完成后再滚动工作负载。 当前仍保留必要数据表,供上传、生成任务和用量记录使用: diff --git a/README.zh-CN.md b/README.zh-CN.md index 4f211b8..5820155 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -181,7 +181,7 @@ npm run bootstrap:admin -- --phone 13800138000 --password '请替换为强密码 ## 组织账号管理 -组织、账号、角色、停用、密码重置和归档均由平台本地接口处理,不再调用外部组织服务。生产部署前请先运行 `npm run db:migrate` 应用 [`database/migrations`](./database/migrations) 中的版本化迁移。 +组织、账号、角色、停用、密码重置和归档均由平台本地接口处理,不再调用外部组织服务。生产部署前由部署负责人手工执行 [`database/migrations`](./database/migrations) 中的版本化 SQL 文件(先 0001 后 0002)及角色授权语句完成建库建表,不部署迁移 Job Pod;超级管理员由 Go 后端首次启动时通过 `ZHINIAN_BOOTSTRAP_ADMIN_*` 环境变量自动创建一次。 ## 账号、组织用量与计费 @@ -212,7 +212,7 @@ npm run bootstrap:admin -- --phone 13800138000 --password '请替换为强密码 其中 EvoLink 按固定 `1 USD = 7.20 CNY` 换算,并在价格目录中列出质量、分辨率、画面比例和参考图数量档位;参数化报价按基础成本乘以所选档位系数,组合倍率取所选档位中的最高倍率。即梦 4.6 官方计费说明要求以控制台实时价格为准,因此该条目是平台维护的参考基准。超管只在价格目录中调整上浮倍率,标准成本、参数档案和规则状态由平台维护;来源链接和定价口径会随规则保留。 -使用 PostgreSQL 时,升级前必须执行 `npm run db:migrate`。迁移器会串行应用尚未执行的版本,并拒绝校验和发生变化的已应用脚本。`local` 模式下,本地 JSON 数据会在读取时按相同口径兼容旧记录。 +使用 PostgreSQL 时,首次部署和每次 schema 变更均按 `database/migrations/*.sql` 中的版本化 SQL 文件手工执行(拒绝已应用脚本被静默改写),执行完成后再滚动工作负载。`local` 模式下,本地 JSON 数据会在读取时按相同口径兼容旧记录。 ## 引擎说明 diff --git a/deploy/ack/migration-job.yaml b/deploy/ack/migration-job.yaml index 9c1e8ed..c3969ea 100644 --- a/deploy/ack/migration-job.yaml +++ b/deploy/ack/migration-job.yaml @@ -1,3 +1,7 @@ +# DEPRECATED (2026-08-14): the initial production schema is executed manually +# from database/migrations/*.sql plus application-role grants. This Job is not +# part of the first-deployment path; keep the manifest only as an optional +# automation reference. apiVersion: batch/v1 kind: Job metadata: diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index bd92ed3..e451f71 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -15,20 +15,21 @@ kubectl -n zhinian create secret generic zhinian-rds-ca \ --from-file=ca.pem=./path/to/downloaded-rds-ca.pem kubectl apply -f deploy/ack/configmap.yaml kubectl apply -f deploy/ack/secrets.example.yaml # 仅作模板;先替换全部占位值 -kubectl apply -f deploy/ack/migration-job.yaml -kubectl -n zhinian wait --for=condition=complete job/zhinian-db-migrate --timeout=5m kubectl apply -f deploy/ack/web.yaml -f deploy/ack/worker.yaml \ -f deploy/ack/service.yaml -f deploy/ack/ingress.yaml ``` -迁移 Job 运行 `node scripts/migrate-postgres.mjs`,读取镜像内 -`database/migrations/*.sql`。迁移使用独立的 `zhinian-migration-db` Secret,以便 -授予建表/变更权限;Web 的 `zhinian-web-db` 应只具有应用运行权限。每次发布先运行 -迁移并确认成功,再滚动 Web。 +数据库 schema 由部署负责人在发布前手工执行,**不部署迁移 Job Pod**(清单 +`deploy/ack/migration-job.yaml` 已弃用保留):使用迁移角色账号依次执行 +`database/migrations/0001_initial_schema.sql`、`0002_generation_lifecycle_fencing.sql`, +再执行应用角色授权语句(表权限 + 两个并发函数 `claim_generation_jobs` 与 +`billing_post_wallet_entry` 的 EXECUTE 权限,参见 +`scripts/migrate-postgres.mjs` 中的 `provisionApplicationRole`)。Web/Go 的数据库 +账号应只具有应用运行权限。以后每次 schema 变更同样按版本化 SQL 文件手工执行,并在 +变更后再滚动工作负载。 -首次把已有数据库纳入版本化迁移前必须先做 RDS 快照/逻辑备份,并在维护窗口执行。迁移器 -遇到重复的历史 `usage_events.job_id` 会安全失败并要求人工审计,不会自动删除计费/用量 -记录;清理后重新运行同一 Job。 +迁移 SQL 包含重复数据保护:遇到重复的历史 `usage_events.job_id` 会失败并要求人工 +审计,不会自动删除计费/用量记录;清理后重新执行对应文件。 替换模板占位符后,可先运行 `npm run deploy:check` 做仓库内静态契约检查;真正发布前仍需 使用目标 ACK 集群的 `kubectl apply --dry-run=server` 验证 CRD/准入策略和 Ingress 行为。 @@ -64,7 +65,7 @@ Secret/ConfigMap 后触发 Deployment 滚动更新。 | --- | --- | | `ZHINIAN_DATA_BACKEND` | 生产固定为 `postgres`;配置错误不会降级到本地 JSON | | `DATABASE_URL` | PostgreSQL URI,仅存 Secret;不要写入镜像、ConfigMap 或日志 | -| `DATABASE_APP_ROLE` | 迁移 Job 使用;与 Web 的 RDS 用户名一致,用于授予最小应用权限 | +| `DATABASE_APP_ROLE` | 应用角色名;手工执行授权语句时使用,与 Web/Go 的 RDS 用户名一致 | | `DATABASE_SSL_MODE` | `disable` 或 `verify-full`;RDS SSL 生产建议 `verify-full` | | `DATABASE_CA_CERT_PATH` | 已挂载 CA 文件路径 | | `DATABASE_POOL_MAX` | 单个 Web Pod 最大连接数 | @@ -159,12 +160,15 @@ ALI_OSS_PUBLIC_BASE_URL= npm run bootstrap:admin -- --phone 13800138000 --password '请替换为强密码' --name '平台超级管理员' ``` -生产部署前设置 `DATABASE_APP_ROLE` 并执行 `npm run db:migrate`,然后运行一次超级管理员 -初始化命令。迁移器只向该应用角色显式授予当前业务表 DML 和两个数据库函数 EXECUTE; -不会授予未来对象的默认权限、`schema_migrations` 或 DDL 权限。新增表/函数时必须随对应 -版本迁移显式更新授权。旧账号使用 -`npm run migrate:accounts -- path/to/legacy-accounts.json` 导入;迁移会保留用量并把历史 -素材、任务、项目和模板映射到平台账号。 +生产部署前先手工执行版本化 SQL 完成建库建表与授权(见上文"手工建库建表"步骤),然后 +通过环境变量初始化超级管理员:Go 后端首次启动时读取 +`ZHINIAN_BOOTSTRAP_ADMIN_PHONE` / `ZHINIAN_BOOTSTRAP_ADMIN_PASSWORD` / +`ZHINIAN_BOOTSTRAP_ADMIN_NAME`(密码至少 8 位,名称缺省为"平台超级管理员"),仅在 +不存在任何超级管理员时创建一次,无需单独脚本。旧的 `npm run bootstrap:admin` 脚本 +仅为本地/Next 开发保留。授权只向应用角色显式授予当前业务表 DML 和两个数据库函数 +EXECUTE;不会授予未来对象的默认权限、`schema_migrations` 或 DDL 权限。新增表/函数时 +必须随对应版本 SQL 显式更新授权。旧账号导入脚本 `npm run migrate:accounts` 仅为历史 +遗留工具保留,新部署无需使用。 ## 旧版组织账号接口(已停用) @@ -234,7 +238,7 @@ Docker Compose 会挂载: 本地 JSON 数据层、上传文件和生成结果都会放在 `.runtime/` 下。`local` 仅适合单实例开发;如临时使用,必须备份该目录。 服务端日志也会放在 `.runtime/logs/` 下,建议和运行时数据一起备份或接入服务器日志采集。 -生产 PostgreSQL 发布前必须执行 `npm run db:migrate`,或先完成 ACK 的 `zhinian-db-migrate` Job。迁移器使用版本记录、校验和、事务和 advisory lock;迁移成功后再滚动 Web。首次打开 `/billing` 或提交真实任务时,系统会自动导入内置标准成本目录;平台参数档案会同步,已有倍率会保留,超级管理员只维护上浮倍率。 +生产 PostgreSQL 发布前必须按顺序手工执行版本化 SQL 文件(0001 再 0002)与角色授权;不部署 `zhinian-db-migrate` Job。执行完成后再滚动工作负载。首次打开 `/billing` 或提交真实任务时,系统会自动导入内置标准成本目录;平台参数档案会同步,已有倍率会保留,超级管理员只维护上浮倍率。 建议备份: