From cd18f6fed677c490ddb993c1453ec87bd64bfc22 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 16 Jul 2026 08:43:47 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20PikaOA=20=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E4=B8=8E=E5=8F=91=E5=B8=83=E8=BF=90=E8=A1=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 2 +- docs/reference/pikaoa.md | 404 +++++++++++++++++++++------------------ 2 files changed, 219 insertions(+), 187 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6dc959a9..a262ef49 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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`。 diff --git a/docs/reference/pikaoa.md b/docs/reference/pikaoa.md index b9504d2b..4bfe5382 100644 --- a/docs/reference/pikaoa.md +++ b/docs/reference/pikaoa.md @@ -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=`; - - `pikaoa.unidesk.io/instance=`。 -- `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 \ + --confirm --json + bun scripts/cli.ts platform-infra pipelines-as-code source-artifact check \ + --target NC01 \ + --consumer pikaoa-dev-nc01 \ + --source-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 数据。