Files
orbit/docs/07-data-model.md

106 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 数据模型与实现基线
更新:2026-09-17。当前为基础实现阶段,完整调度与编排引擎仍在开发计划中。
## 1. 模块与依赖
- `model/`:ID、摘要、JSON、命名空间记录等公共原语。
- `platform/model/`:应用、命名空间、凭据、幂等、事件、订阅交付及审计。
- `pulse/model/`:队列、执行门控、会话、任务、尝试、回执、并发许可和调度计划。
- `weave/model/`:定义及不可变版本、实例、步骤激活、等待、信号、查询轮次与恢复记录。
- `internal/storage/mysql/`:连接、事务与显式迁移,不向 SDK 暴露。
- `sdk/go/`:独立 Go module;对外 DTO 与服务端模型分别维护。
模型使用普通 Go struct 与 `db` 标签,模型与持久化字段提供中文注释,SQL 表和字段同步维护中文 COMMENT。SQL 是可审查的版本化迁移。目前未引入 ORM,也没有自动同步表结构。
## 2. 存储约定
| 项目 | 当前实现 |
| --- | --- |
| 数据库基线 | MySQL 8.4+,本轮在 8.4.10 验证 |
| Go 工具链 | Go 1.27.1;服务端和 SDK 分别编译测试 |
| 标识 | 128 位加密随机 ID;数据库 `BINARY(16)`,对外 32 位小写十六进制字符串 |
| 摘要 | SHA-256,数据库 `BINARY(32)`;执行令牌及凭据原文不进入模型 |
| 租户隔离 | 运行实体以 `(namespace_id, id)` 为主键,具体资源关联使用包含命名空间的复合外键 |
| 时间 | `DATETIME(6)`,数据库会话与驱动统一 UTC;运行授权依赖数据库时间 |
| 状态 | Go 类型常量 + SQL `CHECK`;状态版本独立于时间戳 |
| CAS | `revision` 从 1 开始;服务层必须带期望版本条件更新并检查受影响行数 |
| 暂停 | 实例执行状态与 `paused` 分开,控制版本与通用门控同事务协调 |
| 参数 | 版本化 JSON 文档或业务侧引用;平台不内置行业字段 |
| 删除 | 关联数据默认 `RESTRICT`,没有级联删除执行历史 |
| 不可变历史 | 流程版本、计划版本、状态事件、审计事件的 `UPDATE` 被数据库触发器拒绝 |
随机 ID 的索引成本需要后续容量测试,不将该选择描述为已经验证的大规模吞吐保证。运行账户应最小授权,迁移与保留清理使用不同身份;触发器不是对数据库管理员的防篡改保证。
## 3. 实体清单
下表与初始迁移中的 30 个实体一致;迁移自身另有 `orbit_schema_migrations` 记录。
| 模块 | Go 模型 | 数据表 |
| --- | --- | --- |
| platform | `Application` | `orbit_applications` |
| platform | `Namespace` | `orbit_namespaces` |
| platform | `Credential` | `orbit_credentials` |
| platform | `IdempotencyKey` | `orbit_idempotency_keys` |
| platform | `Event` | `orbit_events` |
| platform | `Subscription` | `orbit_subscriptions` |
| platform | `Delivery` | `orbit_deliveries` |
| platform | `AuditEvent` | `orbit_audit_events` |
| pulse | `Queue` | `pulse_queues` |
| pulse | `ExecutionGate` | `pulse_execution_gates` |
| pulse | `WorkerSession` | `pulse_worker_sessions` |
| pulse | `Task` | `pulse_tasks` |
| pulse | `Attempt` | `pulse_attempts` |
| pulse | `AttemptReceipt` | `pulse_attempt_receipts` |
| pulse | `ConcurrencyLimit` | `pulse_concurrency_limits` |
| pulse | `Permit` | `pulse_permits` |
| pulse | `Schedule` | `pulse_schedules` |
| pulse | `ScheduleVersion` | `pulse_schedule_versions` |
| pulse | `Occurrence` | `pulse_schedule_occurrences` |
| weave | `Definition` | `weave_definitions` |
| weave | `DefinitionVersion` | `weave_definition_versions` |
| weave | `Instance` | `weave_instances` |
| weave | `Step` | `weave_steps` |
| weave | `Activation` | `weave_activations` |
| weave | `Wait` | `weave_waits` |
| weave | `Signal` | `weave_signals` |
| weave | `PollState` | `weave_poll_states` |
| weave | `PollRound` | `weave_poll_rounds` |
| weave | `InboxEvent` | `weave_inbox` |
| weave | `PendingAdvance` | `weave_pending_advances` |
设计文档中的 `task_events` / `result_events` 当前合并为 `orbit_events`,通过聚合类型、事件类型和状态版本区分;对外投递使用 `orbit_deliveries`,内部流程接续使用 `weave_inbox`。`weave_pending_advances` 保存暂停或分批推进后的续接检查点。
## 4. 已落实的数据库约束
- 幂等身份在命名空间、操作和资源作用域内唯一;保存请求摘要和原响应。
- 一个任务的执行代次唯一,当前尝试必须属于同命名空间、同任务。
- 计划触发按计划与 UTC 原触发时间唯一,计划修改不会绕过触发去重。
- 定义版本不可覆盖,实例绑定明确的版本记录。
- 步骤属于指定实例,激活属于指定步骤;避免同租户内错接另一个流程。
- 查询轮次与任务分别唯一;轮次、单轮尝试预算和截止时间独立保存。
- 内部事件与外部订阅交付有去重键,租用状态要求有效租用字段。
- 终态必须有结束时间,待执行任务不能伪造有效执行租约。
## 5. 仍需服务层事务保证的条件
外键与 `CHECK` 无法代替执行引擎。以下属于后续服务实现与回归目标:
1. 权限验证、凭据校验、命名空间过滤和队列消费授权。
2. 同一次事务更新任务、尝试、租约、并发许可、事件与流程交付记录。
3. CAS 竞争、数据库时间校验、门控与开始授权串行化。
4. 对幂等重复请求比较语义摘要,返回原响应或冲突。
5. 计划当前版本与版本内容原子发布,信号匹配正确的业务操作。
6. 查询轮次、预算、下一任务创建同事务提交;未知结果按证据核查。
7. 不可变版本发布前的流程图校验、表达式类型与结构化汇合验证。
当前模型方法只校验局部状态或预算,不能被当作已经实现了执行授权和业务幂等。
## 6. 迁移与回归
入口是 `orbit-migrate up|status`。应用进程只检查迁移状态,不执行 DDL。迁移持有数据库级命名锁,逐语句应用;失败保留 dirty 标记。由于 MySQL DDL 不整体回滚,修复必须先对照语句和实际表结构完成核查,不提供自动清除 dirty 的命令。
已应用的迁移不得修改。后续使用新的前向迁移;回归环境使用独立临时数据库。初始迁移尚未在生产部署。
命令与验证记录见 [开发计划](08-development-plan.md) 和 [基础阶段验证报告](reports/phase-0.md)。