# PikaOA 运行与交付

## 配置真相

- PikaOA 运维配置的唯一真相是 `config/pikaoa.yaml`。
- 稳定开发运行面由 `config/pikaoa.yaml#developmentRuntime.targets.NC01` 声明：
  - source branch：`master`；
  - consumer：`pikaoa-dev-nc01`；
  - runtime namespace：`pikaoa-dev`；
  - CI namespace：`pikaoa-ci`；
  - GitOps branch：`nc01-pikaoa-dev-gitops`；
  - Argo Application：`pikaoa-dev-nc01`；
  - 公网入口：`https://oa-dev.hwpod.com`；
  - NodePort：`32080`。
- 生产运行面由 `config/pikaoa.yaml#releaseRuntime.targets.NC01` 声明：
  - source branch：`release`；
  - consumer：`pikaoa-nc01`；
  - runtime namespace：`pikaoa`；
  - CI namespace：`pikaoa-ci`；
  - GitOps branch：`nc01-pikaoa-gitops`；
  - Argo Application：`pikaoa-nc01`；
  - 公网入口：`https://oa.hwpod.com`；
  - NodePort：`32096`。
- development 与 production 必须保持独立：
  - PostgreSQL role/database；
  - Kubernetes Secret；
  - 附件 PVC；
  - GitOps branch；
  - Argo Application；
  - namespace 与公网入口。
- 已退役路径不得恢复：
  - `testRuntime`；
  - `pikaoa-test` namespace；
  - `pikaoa-test-nc01` consumer/Repository；
  - `pikaoa test-target` CLI；
  - 动态测试 namespace；
  - namespace-local PostgreSQL。

## 对象与模块边界

- PikaOA 是可扩展企业办公平台：
  - 模块通过 descriptor 注册；
  - 模块拥有自己的 schema 初始化、HTTP route、outbox event 和 worker；
  - 新模块复用 identity、附件、审计、可观测性和 API 错误合同。
- 业务对象均为平级 REST 资源：
  - 伙伴、伙伴分类、合同、合同版本、发票和附件都使用服务端生成的 UUIDv7；
  - 对象之间只保存 typed ID 关联；
  - 不把伙伴、合同或发票建模为另一个对象的从属资源。
- 合同版本关系：
  - 每个合同版本拥有独立全局 ID；
  - `contractId`、`previousVersionId` 和当前版本投影建立版本链；
  - 发票可分别关联合同 ID 与合同版本 ID。
- 首版审计与一致性：
  - 跨模块关联未完成一致性核验时只返回 `blocking=false` warning；
  - 完整身份/RBAC、严格审计门禁和强一致性校验不作为 MVP 上线前置。

## 数据库与 Secret

- development 与 production 都使用 NC01 host PostgreSQL：
  - owning YAML：`config/platform-db/postgres-nc01.yaml`；
  - development role/database：`pikaoa_dev`；
  - production role/database：`pikaoa`；
  - 业务 schema：`pikaoa`；
  - development export：`platform-infra/pikaoa-dev.env`；
  - production export：`platform-infra/pikaoa.env`。
- 不迁移旧 test 数据：
  - development 使用全新 role/database；
  - 旧 test 数据、namespace 和运行对象可直接丢弃；
  - 不增加兼容、回填或双写路径。
- Secret 分发的唯一真相是 `config/secrets-distribution.yaml`：
  - development scope：`pikaoa-dev`；
  - development Secret：`pikaoa-dev-runtime`；
  - production scope：`pikaoa`；
  - production Secret：`pikaoa-runtime`。
- runtime Secret 只包含敏感键：
  - `DATABASE_URL`；
  - `PIKAOA_SESSION_SECRET`；
  - `OA_ADMIN_TOKEN`；
  - `PIKAOA_BOOTSTRAP_ADMIN_PASSWORD`；
  - `PIKAOA_BOOTSTRAP_EMPLOYEE_PASSWORD`。
- 非敏感 `pikaoa.yaml` 由 `pikaoa-runtime-config` ConfigMap 提供：
  - API、Worker 和 initializer 从 ConfigMap 挂载配置；
  - `DATABASE_URL` 在应用校验前由环境变量覆盖空配置值；
  - 禁止把 `pikaoa.yaml` 写入 runtime Secret。
- Secret 来源和运行面输出必须脱敏：
  - 只披露 sourceRef、key、presence、fingerprint 和摘要；
  - 禁止从 Kubernetes Secret、Pod 环境、日志或数据库反解值；
  - 禁止在命令参数、issue、截图或报告中写入 token、密码或完整 DSN。

## 首次引导

- 首次创建 development 数据库与导出：

  ```bash
  bun scripts/cli.ts platform-db postgres plan \
    --config config/platform-db/postgres-nc01.yaml
  bun scripts/cli.ts platform-db postgres apply \
    --config config/platform-db/postgres-nc01.yaml \
    --confirm --wait
  bun scripts/cli.ts platform-db postgres export-secrets \
    --config config/platform-db/postgres-nc01.yaml \
    --confirm
  ```

- 首次同步 development Secret：

  ```bash
  bun scripts/cli.ts secrets plan \
    --config config/secrets-distribution.yaml \
    --scope pikaoa-dev
  bun scripts/cli.ts secrets sync \
    --config config/secrets-distribution.yaml \
    --scope pikaoa-dev \
    --confirm
  ```

- PaC consumer 只在首次引导时执行 bootstrap：

  ```bash
  bun scripts/cli.ts platform-infra pipelines-as-code bootstrap \
    --target NC01 \
    --consumer pikaoa-dev-nc01 \
    --dry-run
  bun scripts/cli.ts platform-infra pipelines-as-code bootstrap \
    --target NC01 \
    --consumer pikaoa-dev-nc01 \
    --confirm
  ```

- bootstrap 完成后不得再次用于 source delivery、恢复或补跑。
- 旧 Repository CR 与新声明使用同一 URL 时：
  - 先精确确认旧对象属于已退役 PikaOA test consumer；
  - 只退役该旧对象；
  - 立即由已合并 owning YAML 的 bootstrap 创建新对象；
  - 禁止修改共享 PaC controller、admission 或其他 consumer。

## 自动交付

- development 和 production 都使用 PaC 自动交付：
  - GitHub source PR merge；
  - GitHub webhook；
  - Gitea controlled mirror 与 immutable snapshot；
  - PaC/Tekton；
  - GitOps branch；
  - Argo 自动同步；
  - runtime readiness 与 `/healthz`。
- 正常交付的唯一触发：
  - development：合并 `pikainc/pikaoa@master` PR；
  - production：合并 `pikainc/pikaoa@release` PR。
- `.tekton` 制品必须由 UniDesk source-artifact renderer 生成：

  ```bash
  bun scripts/cli.ts platform-infra pipelines-as-code source-artifact write \
    --target NC01 \
    --consumer pikaoa-dev-nc01 \
    --source-worktree <clean-pikaoa-worktree> \
    --confirm --json
  bun scripts/cli.ts platform-infra pipelines-as-code source-artifact check \
    --target NC01 \
    --consumer pikaoa-dev-nc01 \
    --source-worktree <clean-pikaoa-worktree> \
    --json
  ```

- 自动链禁止人工补齐：
  - 不人工创建 PipelineRun；
  - 不人工 mirror sync；
  - 不人工 Argo sync/refresh；
  - 不在 source PR merge 后再次 bootstrap/apply。
- 自动链失败时：
  - 使用 `platform-infra pipelines-as-code status|history|debug-step` 只读归因；
  - consumer 私有缺陷回到 owning YAML、renderer 或 source artifact 修复；
  - 共享 PaC/controller/admission 故障只报告，不在 PikaOA 任务中修改公共 CI/CD 基础设施。

## 公网入口

- 公网入口的聚合真相是 `config/platform-infra/public-edge.yaml#targets.NC01`。
- 产品 hostname、NodePort 和 health path 只从 `config/pikaoa.yaml` 的 configRef/path 解析。
- 受控入口：

  ```bash
  bun scripts/cli.ts platform-infra public-edge plan --target NC01
  bun scripts/cli.ts platform-infra public-edge apply --target NC01 --dry-run
  bun scripts/cli.ts platform-infra public-edge status --target NC01
  ```

- 公网入口 mutation 只由 `master` merge 触发的唯一 PaC authority执行；PikaOA任务和 L1 会话不得执行 `apply --confirm`、内部 `reconcile` 或直接改写 Caddy。

- NC01 共享 edge 约束：
  - 复用唯一 Caddy `80/443` listener；
  - 不访问 PK01；
  - 保留 UDP `443`；
  - 单站探针失败只输出 `blocking=false` warning；
  - 禁止为 PikaOA 启动第二个独立 `80/443` proxy。

## CLI-first 验收

- 所有业务功能先使用 PikaOA CLI 验收：
  - CLI 只调用与 Web 相同的公开 HTTP API；
  - development endpoint 使用 `https://oa-dev.hwpod.com`；
  - production endpoint 使用 `https://oa.hwpod.com`；
  - `OA_ADMIN_TOKEN` 只通过进程环境注入，不创建 session 文件；
  - CLI 输出不得打印 token。
- 最小顺序：
  - `health`；
  - `health --ready`；
  - `metrics`；
  - `modules`；
  - `whoami`；
  - 员工与角色；
  - 伙伴分类与伙伴；
  - 合同 v1；
  - 合同 v2 版本链；
  - 发票关联与废弃；
  - 附件与审计；
  - 合同和发票 PDF `import-preview`。
- PDF import-preview 约束：
  - 原 PDF 作为附件保留；
  - 自动提取结果包含置信度与 `manualReviewRequired`；
  - 用户可人工校对后再创建或更新业务对象；
  - 提取 warning 不阻塞手工校对流程。
- CLI 通过后才进入 Web 验收：
  - 只使用 `$unidesk-webdev` 的 `web-probe`；
  - 禁止裸 Playwright；
  - 验证管理员登录、合同/发票/PDF 校对主路径和移动视口。

## 可观测性

- OTel 从第一版启用：
  - API、Worker 与 CLI 使用 OpenTelemetry；
  - runtime endpoint 由 `config/pikaoa.yaml` 声明；
  - exporter 失败只记录 `blocking=false` warning；
  - trace 不记录 Secret、完整 DSN、PDF 内容或业务敏感字段。
- Prometheus 从第一版启用：
  - API 与 Worker 使用 owning YAML 的 label selector 和 scrape annotation；
  - API 与 Worker 都提供 `/metrics`；
  - 重点核验数据库、迁移、HTTP、pgx pool、Worker 周期和业务模块指标。
- 受控验收入口：
  - OTel/Tempo 使用 `$unidesk-otel`；
  - Prometheus 与 Web 哨兵使用 `$unidesk-monitor`；
  - 指标、trace 或版本一致性漂移不得改变业务 ready 终态。

## 退役与推广

- development 验收通过后退役旧 test 对象：
  - `pikaoa-test` namespace；
  - 旧 test Repository/Argo/GitOps 资源；
  - 旧 test Secret source 与数据库 role/database；
  - 旧 test CLI 状态目录。
- 退役必须精确限定旧 test 对象：
  - 禁止删除 `pikaoa` production namespace；
  - 禁止删除 `pikaoa-ci`；
  - 禁止删除 `pikaoa-dev`；
  - 禁止触碰其他 PaC consumer。
- production 推广：
  - 先完成 development CLI/Web/OTel/Prometheus 验收；
  - 再通过正常 `master -> release` PR 推广；
  - `release` PR merge 是生产自动交付的唯一触发；
  - 生产推广不复制 development 数据。
