docs: 更新 PikaOA 开发与发布运行面
Pipelines as Code CI / hwlab-web-probe-sentinel-nc01- Success
Pipelines as Code CI / platform-infra-gitea-nc01- Success
Pipelines as Code CI / unidesk-host- Success

This commit is contained in:
Codex
2026-07-16 08:43:47 +02:00
parent 76d13c0f14
commit cd18f6fed6
2 changed files with 219 additions and 187 deletions
+1 -1
View File
@@ -149,6 +149,6 @@
- OTel/可观测性: `docs/reference/observability.md`
- YAML-first: `docs/reference/yaml-first-ops.md`
- Platform infrastructure: `docs/reference/platform-infra.md`
- PikaOA 临时测试运行面: `docs/reference/pikaoa.md`
- PikaOA development/release 运行面: `docs/reference/pikaoa.md`
- Webterm 配置与受控部署: `docs/reference/webterm.md`
- Secretary: `docs/reference/secretary-reference.md`
+218 -186
View File
@@ -1,225 +1,257 @@
# PikaOA
# PikaOA 运行与交付
## 配置真相
- PikaOA 平台配置唯一真相是 `config/pikaoa.yaml`
- 测试运行面固定使用
- Target`NC01`
- route`NC01:k3s`
- namespace`pikaoa-test`
- 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`
- 测试 namespace 不根据 commit、instance 或任务动态生成。
- `pikaoa``pikaoa-ci` 是正式交付保护 namespace。
- 测试入口不得渲染、覆盖或删除保护 namespace 中的对象。
- 生产运行面固定使用:
- 生产运行面由 `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`
- 测试公网入口固定使用 `https://oa-dev.hwpod.com`
- 生产交付与公网配置分别以以下 selector 为真相
- `config/pikaoa.yaml#releaseRuntime.targets.NC01`
- `config/pikaoa.yaml#delivery.targets.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。
## 数据库边界
## 对象与模块边界
- 生产与测试数据库固定使用 NC01 host PostgreSQL,不创建 namespace-local PostgreSQL。
- `config/platform-db/postgres-nc01.yaml` 声明独立的:
- 生产 role/database`pikaoa`
- role`pikaoa_test`
- database`pikaoa_test`
- schema`pikaoa`
- 生产 `DATABASE_URL` export`platform-infra/pikaoa.env`
- 测试 `DATABASE_URL` export`platform-infra/pikaoa-test.env`
- `pikaoa-test` namespace 不创建 PostgreSQL StatefulSet、Service 或临时数据库。
- 数据库生命周期独立于 namespace 和业务 workload。
- 迁移采用全新 role/database,不复制旧数据。
- 数据库准备、Secret export 与后续状态查询只走 `platform-db postgres` 受控入口
- 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 初始化
## 数据库与 Secret
- `config/secrets-distribution.yaml` 声明
- source`platform-infra/pikaoa-test.env`
- target`pikaoa-test-nc01`
- scope`pikaoa-test`
- Kubernetes Secret`pikaoa-test-runtime`
- `platform-infra/pikaoa-test.env` 必须包含:
- 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`
- `DATABASE_URL``platform-db postgres export-secrets` 写入并保留。
- `createIfMissing` 只为 `PIKAOA_SESSION_SECRET` 生成值,不覆盖已有 `DATABASE_URL`
- 管理员和员工密码继续使用既有 external raw sources
- `~/.unidesk/.env/pikaoa-admin-password.txt`
- `~/.unidesk/.env/pikaoa-employee-password.txt`
- Secret 输出只披露对象、key、presence、fingerprint 和摘要,不读取或打印值。
- `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。
## Test Target CLI
## 首次引导
- 受控入口是 `bun scripts/cli.ts pikaoa test-target`
- `config/pikaoa.yaml#testRuntime` 声明固定 namespace、镜像、PVC、Secret 引用、迁移、工作负载、探针和暴露端口。
- 所有创建对象都带以下所有权标签:
- `app.kubernetes.io/managed-by=unidesk-pikaoa-test-target`
- `pikaoa.unidesk.io/test-runtime=true`
- `pikaoa.unidesk.io/target=<target-id>`
- `pikaoa.unidesk.io/instance=<instance-id>`
- `stop` 只允许删除同时匹配固定 namespace 和全部所有权标签的运行面。
- CLI 使用异步任务状态目录记录有界状态和事件,不建立第二数据库、控制器、租约或锁服务。
- 首次创建 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
```
1. 使用 `platform-db postgres` 受控入口和 `config/platform-db/postgres-nc01.yaml` 准备 `pikaoa_test` role/database,并 export `DATABASE_URL`
2. 执行 foundation
- 首次同步 development Secret
```bash
bun scripts/cli.ts pikaoa test-target start \
--target NC01 \
--instance default \
--step foundation \
--confirm
```
```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
```
3. foundation 只创建带所有权标签的固定 `pikaoa-test` Namespace 和附件 PVC,不要求业务 Secret 已存在。
4. 执行 Secret 下发:
- PaC consumer 只在首次引导时执行 bootstrap:
```bash
bun scripts/cli.ts secrets sync \
--config config/secrets-distribution.yaml \
--scope pikaoa-test \
--confirm
```
```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
```
5. `secrets sync` 按 YAML 声明补齐允许生成的本地来源,并下发 `pikaoa-test-runtime`
6. 使用同一 commit 依次执行
- `--step init`,仅初始化全新数据库
- `--step api`
- `--step worker`
- `--step web`
7. Web 固定通过 `152.53.229.148:32080` 的 NodePort 入口验收。
- bootstrap 完成后不得再次用于 source delivery、恢复或补跑
- 旧 Repository CR 与新声明使用同一 URL 时
- 先精确确认旧对象属于已退役 PikaOA test consumer
- 只退役该旧对象
- 立即由已合并 owning YAML 的 bootstrap 创建新对象
- 禁止修改共享 PaC controller、admission 或其他 consumer
## 单步运行
## 自动交付
- foundation 不需要 `--commit`,也不检查业务 Secret。
- init、api、worker、web 和 all 必须显式提供 `--commit`。
- 每个 `start` 立即返回任务 ID;使用同一 target、instance 和 step 的 `status` 查询终态。
- request identity 包含:
- target
- instance
- 产品 commit
- step
- 当前 step 的稳定 structural manifest fingerprint。
- request fingerprint 对 Secret `stringData` 只保留 key 结构和脱敏占位,不包含 Secret 原值。
- request fingerprint 排除 `pikaoa.unidesk.io/expires-at` 等每次渲染变化的易变字段
- 完全相同 request 重复提交只返回已有任务状态,不并行创建第二任务。
- 不同 request 遇旧任务处于 queued/running 且 worker 存活时返回 `start-instance-conflict`。
- 不同 request 遇旧任务已 succeeded/failed/canceled,或 queued/running 但 worker 明确缺失时:
- 原子退役该 step 的旧有界状态目录;
- 继续使用同一 `target/instance/step` 状态路径提交新任务;
- `status` 只读取该 step 的最新任务。
- foundation 也遵循相同规则。
- foundation 需要显式形成新 request 时,可以:
- 提供新的 `--commit` 修订标识;
- 修改 foundation 的稳定 manifest 结构。
- 不为重跑引入第二状态库、控制器、租约或长期历史存储。
- initializer、rollout 或运行面查询失败返回具名失败码,不静默进入下一阶段。
- OTel exporter、配置版本和 commit 对齐漂移只产生 `blocking=false` warning,不恢复 dedicated 门禁。
- 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
```
- `pikaoa-test-nc01` 独立 test CI/CD 复用同一 owning YAML
- 产品 `master` 只生成 `.tekton/pikaoa-test-nc01-pac.yaml`
- API、Worker、Web 并行构建并以 digest 发布 GitOps
- initializer 通过 Argo `PreSync` 在 API、Worker、Web 前初始化全新数据库
- 不创建专用测试集群;
- 不生成动态 namespace
- 不创建 namespace-local PostgreSQL
- 不把测试 CI/CD 变成生产交付或用户业务的阻塞门禁。
- GitOps 接管后,手动 `test-target start|stop` mutation 仅用于暂停 Argo 自动同步后的有界调试;禁止 CLI direct-apply 与 Argo 同时写入
- 生产 `pikaoa-nc01` 已完成 bootstrap
- 产品 `release` 只生成 `.tekton/pikaoa-nc01-pac.yaml`
- 正常 `release` PR merge 是生产 PipelineRun 的唯一触发入口;
- API、Worker、Web 并行构建并以 digest 发布到生产 GitOps branch
- Argo Application `pikaoa-nc01` 自动同步 `pikaoa` namespace
- 禁止人工补建 PipelineRun 代替 source merge。
- 生产使用 NC01 host PostgreSQL 独立 `pikaoa` database/role,不使用 namespace-local PostgreSQL。
- 生产库逻辑备份由 `config/platform-db/postgres-nc01.yaml#backup.logicalDumps` 声明,写入 NC01 host 本地目录。
- 生产附件主存储保持 NC01 k3s PVC,独立备份由 `config/pikaoa.yaml#delivery.targets.NC01.attachmentsBackup` 声明:
- source PVC 只读挂载;
- Restic repository 使用 NC01 hostPath `/var/backups/unidesk/pikaoa/attachments-restic`
- `backup`、`check`、`forget/prune` 与 `restore-smoke` 均由 YAML 渲染;
- `restore-smoke` 只恢复到临时 `emptyDir`
- Secret 只包含 `RESTIC_PASSWORD`,不需要 SFTP key 或 known_hosts。
- PikaOA 公网 exposure 由 `config/pikaoa.yaml` 的产品 target 唯一声明:
- `testRuntime.targets.NC01.exposure` 拥有 `oa-dev.hwpod.com` 与 NodePort `32080`
- `releaseRuntime.targets.NC01.exposure` 拥有 `oa.hwpod.com` 与 NodePort `32096`
- 两站健康路径继续使用 `/healthz`
- 产品 YAML 不再拥有 Caddy listener、workDir、证书目录或 Compose
- 平台聚合只通过 `configRef/path` 读取 exposure,不复制 hostname 或 upstream。
- 公网入站 HTTPS/Public Edge 由
`config/platform-infra/public-edge.yaml` 唯一声明,受控入口是:
- 自动链禁止人工补齐
- 不人工创建 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 apply --target NC01 --confirm
bun scripts/cli.ts platform-infra public-edge status --target NC01
```
- 共享边缘复用现有 `pikaoa-edge` 容器、workDir、Caddy data/config 和证书状态;
禁止启动第二个 TCP `80/443` listener
- VPN subscription 由 `config/platform-infra/vpn-subscription.yaml` 独立拥有,
通过 `configRef/path` 聚合 `proxy.hwpod.com/subscribe` 的 HTTPS/8443 upstream
与 TLS SNI。
- `excludedRoutes: [PK01]` 保证该入口不访问 PK01`preservedUdpPorts: [443]`
保证 Hysteria UDP 443 不被 `h3` 抢占,并由 status/apply 前置检查验证。
- PikaOA 与 VPN subscription 是 R9.1 已解析消费者;其他产品引用未迁移时,
`plan/status` 输出 `blocking=false` warning,只有 `apply --confirm` 拒绝 mutation。
- `public-edge apply` 只修改 NC01 共享 Caddy,不访问 PK01。
- 生产初始化模式是 `fresh-database-only`,不实现旧数据迁移、兼容或回滚。
- 版本、审计和配置一致性异常只产生 `blocking=false` warning,不作为 MVP 业务门禁。
- PR、构建或单测不能替代固定 NodePort 原入口验收。
- NC01 共享 edge 约束:
- 复用唯一 Caddy `80/443` listener
- 不访问 PK01
- 保留 UDP `443`
- 单站探针失败只输出 `blocking=false` warning
- 禁止为 PikaOA 启动第二个独立 `80/443` proxy。
## 生产最短只读验收
## CLI-first 验收
- 先执行运行面与 Argo 对账
- 所有业务功能先使用 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 校对主路径和移动视口。
```bash
trans NC01:k3s kubectl get deploy,pod,svc,pvc -n pikaoa -o wide
trans NC01:k3s kubectl get application -n argocd pikaoa-nc01
```
## 可观测性
- 运行面通过判定
- API、Web、Worker、FRPC Deployment 全部 Ready
- Pod 全部 Running 且没有新增重启
- 附件 PVC 为 Bound
- Argo 为 `Synced` 和 `Healthy`
- 再验证公网和共享可观测性
- 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 终态。
```bash
curl -fsSI https://oa.hwpod.com/
curl -fsSI https://oa-dev.hwpod.com/
bun scripts/cli.ts platform-infra observability metrics-query \
--target NC01 \
--query 'pikaoa_database_ready' \
--full
```
## 退役与推广
- 公网与可观测性通过判定
- 公网 HTTPS 返回 200
- 生产 API 和 Worker 的 `pikaoa_database_ready` 均为 1
- 使用 `$unidesk-webdev` 完成管理员桌面与移动视口登录
- 使用 `$unidesk-otel` 查询登录 `traceId`span error 数为 0
- 密码只从 owning YAML 声明的 `sourceRef` 读取,禁止出现在 CLI 参数、日志、截图或任务报告中。
- 完整身份/RBAC、严格一致性审计和附件备份增强属于独立后续任务,不阻塞上述 MVP 验收。
## 本地验证
- `config/fixtures/pikaoa-test-target.yaml` 只用于 renderer 和 CLI 测试。
- fixture target 固定为 `validationOnly=true`,不得连接真实 route。
- 最小验证包括:
- `bun --check scripts/src/pikaoa-test-target.ts`
- `bun test scripts/src/pikaoa-test-target-async.test.ts`
- `bun scripts/cli.ts check --syntax-only`
- `pikaoa test-target plan --step foundation`
- `git diff --check`。
- 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 数据。