fix: 分离日常发布与首次初始化(09-09-existing-deploy-seed-separation)
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-09-09 12:47:30 +08:00
父节点 81102c26cf
当前提交 b87cc55aca
共修改 17 个文件,包含 662 行新增和 11 行删除
+73 -1
查看文件
@@ -19,6 +19,77 @@ operations require explicit approval and evidence.
- Do not execute real payments, import bank statements, connect payment
providers or write ERP without a separate approved Trellis task.
## Scenario: Deployment Seed Separation
### 1. Scope / Trigger
Daily releases preserve operator-maintained configuration. This local candidate
contract does not assert production has been deployed.
### 2. Signatures
- Shared entry: `cd server && npm run deploy:init`.
- `DEPLOY_DATA_MODE=existing|initialize` is mandatory; no default.
- deploy.sh passes mode via Compose run `-e`; Compose init calls the same entry.
With `entrypoint: ["sh", "-c"]`, command must be a one-element list containing
the entire shell expression, not a folded scalar subject to argv splitting.
Verify entry reachability and propagation of a nonzero child exit, not only
the YAML text or Compose config rendering.
Approved direct calls use `run --rm --no-deps -T -e DEPLOY_DATA_MODE=existing init`
with established project/file/env selectors and an already healthy database.
### 3. Contracts
- Validate mode before subprocess/DB access; then config precheck, migrate deploy,
initialize-only seed:config/seed:trialrun, and read-only configuration checks.
- Existing never invokes either seed, even on missing configuration. Migrations
are not read-only. No implicit repair or mode fallback.
- Require nonzero counts of enabled expenseType, enabled approvalRule and active
reimbursement workflowDefinition. Mirror current reimbursement predicates.
No forced v1, roles, thresholds or values equal to seed defaults.
- Bounded repeatable-read transaction explicitly sets READ ONLY. Output fixed
check codes/counts/maintenance hints only, never row payloads.
- Empty core configuration blocks switching, including intentional disablement.
Nonempty checks do not prove amount coverage, assignees or business readiness.
- Workspace/sequence fallbacks, optional flags/calendar and employee/account
readiness stay outside this gate; do not create missing records.
### 4. Validation & Error Matrix
- Missing/invalid mode → deployment.data_mode_required before migrate/seed.
- Subcommand failure → deployment.init_command_failed; no later stages.
- Missing core → REQUIRED_CONFIGURATION_MISSING with safe check list, then
deployment.required_configuration_missing; never auto-seed existing data.
- Query/connection errors → deployment.init_failed, nonzero, no raw exception.
- INIT_PASS proves only this init/check stage, not public release success.
### 5. Good / Base / Bad Cases
- Good: existing custom flags/workflows/calendars and versions survive.
- Base: explicitly initialize an empty synthetic database with seed in order.
- Bad: repair missing records by replaying seed, or default to initialize.
### 6. Tests Required
- deploy-init.test.js mode/order/errors/read-only checks join the static gate.
- Keep deployment-db-lifecycle and deployment-safety-contract regressions.
- Opt-in deploy-init.integration.test.js uses DEPLOY_INIT_TEST_DATABASE_URL:
loopback, uniquely named hyb_seed_test_* empty synthetic DB. No production
default URL, reset, real archive or remote access. Operator owns exact cleanup.
Missing URL means skipped, not integration PASS.
- Test actual initialize, repeated existing execution, hashes of 17 config
models including timestamps/versions, and each missing-core failure.
### 7. Wrong vs Correct
Wrong: values differ from defaults → overwrite them on every deployment.
Correct: preserve values; stop only for approved minimum missing-core checks.
Expense types require authorized configuration repair; do not invent a UI route.
Approval rules and workflow definitions have existing admin pages.
Raw seed commands remain available for separately approved initialization;
this does not prevent an administrator explicitly running seed. Old-image
rollback cannot reverse migrations or initialization data.
## Scenario: Existing Application Release Must Not Manage Database Containers
### 1. Scope / Trigger
@@ -59,7 +130,8 @@ operations require explicit approval and evidence.
without a container may incur an extra cached build. This assumes the current
build-only worker definition; future image overrides need their own compatibility
review, rather than treating a previous container reference as new configuration.
Preserve migration/seed command content and order, safe logs, identity/path
Preserve migrations and initialize-only seed order through the shared
deploy:init entry above, safe logs, identity/path
preflights, rollback window, build markers and backup-contract refresh.
- Missing timeout tooling or unsupported isolation options fail closed. Do not
retry a command without isolation to accommodate an older Compose executable.