# DataOps Platform 数据模型

> 图中“当前”表示已有建库脚本、Alembic 迁移或 Neo4j 读写代码；“目标”仅用于后续迁移设计，尚未部署到生产。

## 1. PostgreSQL 当前表

```mermaid
erDiagram
    users {
        varchar id PK
        varchar username UK
        varchar password "旧认证，仅本地验收"
        boolean is_admin
    }
    data_orders {
        serial id PK
        varchar order_no UK
        varchar status
        integer result_product_id "逻辑引用"
        integer result_dataflow_id "Neo4j 节点 ID"
        integer data_source "Neo4j 节点 ID"
        jsonb graph_analysis
    }
    data_products {
        serial id PK
        varchar product_name
        integer source_dataflow_id "Neo4j 节点 ID"
        varchar target_schema
        varchar target_table
        varchar status
    }
    metadata_review_records {
        bigserial id PK
        bigint business_domain_id "Neo4j 节点 ID"
        varchar record_type
        varchar status
        jsonb new_meta
        jsonb old_meta
        jsonb resolution_payload
    }
    metadata_version_history {
        bigserial id PK
        bigint meta_id "Neo4j 节点 ID"
        jsonb before_snapshot
        jsonb after_snapshot
        varchar created_by
    }
    task_list {
        serial task_id PK
        varchar task_name
        varchar status
        varchar create_by
    }
    datasource_credentials {
        uuid id PK
        uuid data_source_uid
        integer credential_version
        bytea encrypted_payload
        bytea nonce
        varchar key_version
        varchar status
    }
    datasource_credential_audit_events {
        bigserial id PK
        uuid data_source_uid
        integer credential_version
        varchar event_type
        varchar actor_uid
        text safe_detail
    }
    data_orders }o--o| data_products : "result_product_id（当前无 FK）"
    datasource_credentials ||--o{ datasource_credential_audit_events : "data_source_uid / credential_version"
```

当前脚本没有为跨表逻辑引用建立外键；跨 Neo4j 引用使用内部节点 ID，存在节点重建后失效风险。下一阶段必须引入稳定业务 UUID，内部节点 ID 仅用于查询加速，不作为长期契约。

## 2. Neo4j 当前治理图

```mermaid
flowchart LR
    BD["BusinessDomain"] -->|"COME_FROM"| DS["DataSource"]
    BD -->|"INCLUDES"| META["DataMeta"]
    BD -->|"LABEL"| LABEL["DataLabel"]
    META -->|"LABEL"| LABEL
    META -->|"ALIAS"| PRIMARY["DataMeta 主对象"]
    BD -->|"INPUT"| DF["DataFlow"]
    DF -->|"OUTPUT"| TARGET["BusinessDomain"]
```

唯一方向约定：

- `BusinessDomain-[:COME_FROM]->DataSource`
- `BusinessDomain-[:INCLUDES]->DataMeta`
- `BusinessDomain-[:INPUT]->DataFlow`
- `DataFlow-[:OUTPUT]->BusinessDomain`
- 治理对象 `-[:LABEL]->DataLabel`
- 别名 `alias DataMeta-[:ALIAS]->primary DataMeta`

遗留查询和注释中若出现反方向假设，应在下一阶段以自动化图模型契约测试消除。

### DataSource 安全字段约定

Neo4j `DataSource` 节点保存 `uid`、类型、主机、端口、数据库、schema、
TLS 白名单选项、连接池覆盖项、`credential_ref` 和 `credential_version`。
节点不允许保存 `username`、`password`、`conn_str`、`connection_string`
或 `connection_url`。`credential_ref` 指向平台 PostgreSQL 中相同
`data_source_uid` 的当前不可变凭据版本：

```mermaid
flowchart LR
    DS["Neo4j DataSource\nuid + credential_version"] -->|"逻辑引用"| CRED["PostgreSQL datasource_credentials\nAES-256-GCM 密文"]
    CRED --> AUDIT["datasource_credential_audit_events\n不含密钥的审计明细"]
    DS --> POOL["Worker 本地池键\nuid + version + fingerprint"]
```

数据库约束保证同一数据源每个 `credential_version` 唯一，且同一数据源最多
一个 `active` 版本。密文使用数据源 UID 和版本号作为认证附加数据，不能复制到
另一个数据源或版本后解密。删除生产凭据表不属于本轮范围。

## 3. 已实施的 PostgreSQL 增量表

下表均已由 `migrations/` 中的 Alembic 版本链创建，不再只是设计目标。

| 表 | 核心字段 | 约束/用途 |
|---|---|---|
| `users` | `id UUID`, `username`, `password_hash`, `status` | 替换旧明文/可逆密码字段 |
| `roles` | `id`, `code` | 固定 `admin/editor/viewer`，即管理员、编辑者、查看者 |
| `user_roles` | `user_id`, `role_id` | 用户与角色映射 |
| `dataflow_workflow_versions` | `id`, `dataflow_uid`, `environment`, `version_no`, `n8n_workflow_id`, `status` | 一个 DataFlow 对多个 n8n Workflow 版本 |
| `governance_documents` | `object_type`, `object_uid`, `object_version`, `content_hash` | 治理对象文本快照 |
| `governance_chunks` | `document_id`, `chunk_no`, `content`, `embedding vector` | Qwen Embedding 结果 |
| `governance_sync_jobs` | `mode`, `cursor`, `status`, `error` | 增量同步和每日全量一致性巡检 |
| `workbench_layouts` | `user_id`, `layout_version`, `widgets jsonb` | 按用户保存有限标准组件布局 |
| `outbox_events` | `event_id`, `aggregate_type`, `aggregate_id`, `payload`, `published_at` | 跨存储最终一致性 |
| `datasource_credentials` | `data_source_uid`, `credential_version`, `encrypted_payload`, `nonce`, `key_version`, `status` | 外部数据源不可变加密凭据 |
| `datasource_credential_audit_events` | `data_source_uid`, `credential_version`, `event_type`, `actor_uid`, `safe_detail` | 不含秘密的凭据及连接池审计 |

环境级唯一生效约束：`UNIQUE (dataflow_uid, environment) WHERE status = 'active'`，保证同一环境只允许一个当前生效版本。

## 4. 数据治理知识库映射

| 治理对象 | 来源 | 文档标识 | 触发方式 |
|---|---|---|---|
| 业务域定义 | Neo4j `BusinessDomain` | `business_domain:{uid}` | 变更后增量同步 |
| 数据流程定义 | Neo4j `DataFlow` + 版本映射 | `dataflow:{uid}:{version}` | 变更/激活后增量同步 |
| 元数据定义 | Neo4j `DataMeta` | `metadata:{uid}` | 审核落库后增量同步 |
| 数据标准/标签 | Neo4j | `standard/label:{uid}` | 变更后增量同步 |
| 全量校验 | Neo4j + PostgreSQL | 内容哈希 | 每日全量一致性巡检 |

向量由 Qwen 的 embedding 模型生成；DeepSeek 只负责生成式问答。召回结果必须携带对象类型、业务域、版本、更新时间和访问范围，回答必须返回来源对象。

## 5. 所有权与删除规则

- PostgreSQL 是身份、权限、映射、任务状态、布局和一致性事件的源真相。
- Neo4j 是治理对象结构和血缘的源真相。
- MinIO 是附件原件的源真相；PostgreSQL 只保存对象键和元数据。
- n8n 是 Workflow 定义与执行记录的源真相；平台保存治理映射和生效状态。
- 本轮只清理代码和建库脚本。生产表必须在数据核查、备份和依赖确认后以独立变更单下线。
