跳至正文
Wener Notes

Schema Wode Practice

约 4 分钟阅读
标签:设计
sql
create table res(
  id          text        not null default '<tag>_' || public.gen_ulid() primary key,
  uid         uuid        not null default gen_random_uuid() unique,
  created_at  timestamptz not null default current_timestamp,
  updated_at  timestamptz not null default current_timestamp,
  deleted_at  timestamptz,
  tid         text        not null default public.current_tenant_id() references public.tenant (tid),
  eid         text,

  attributes  jsonb       not null default '{}',
  properties  jsonb       not null default '{}',
  extensions  jsonb       not null default '{}',
  unique (tid, eid)
);

实践特征:

  • type-prefixed ID:usr_、team_、lead_、file_。
  • uid uuid 作为额外全局 UUID。
  • tid 作为租户隔离字段,默认来自 current_tenant_id()。
  • eid 作为外部/导入关联 ID。
  • created_at/updated_at/deleted_at 作为基础审计时间。
  • attributes/properties/extensions 三层扩展字段大量使用。

Resource 相关实践

示例:users.sql、account.sql、lead.sql、file.sql。

资源表通常包含:

text
id / uid / tid / eid
created_at / updated_at / deleted_at
业务唯一字段:code、name、login_name、email 等
state / status
owner_id / owner_type
created_by_id / updated_by_id / deleted_by_id
attributes / properties / extensions
sql
sid bigint not null default public.next_entity_sid('Lead')

作为面向用户/业务的序列号。

Ownership 相关实践

典型模式:

sql
create table has_owner(
  owner_id      text,
  owner_type    text,
  owner_user_id text generated always as (
    case owner_type when 'User' then owner_id end
  ) stored,
  owner_team_id text generated always as (
    case owner_type when 'Team' then owner_id end
  ) stored,

  created_by_id text default public.current_user_id() references users (id),
  updated_by_id text default public.current_user_id() references users (id),
  deleted_by_id text references users (id)
);
  • owner_type + owner_id 支持多态 owner。
  • owner_user_id / owner_team_id generated column 让外键和索引可落地。
  • auditor 字段与 owner 字段分离。

Status

sql
create table if not exists lead(
  -- System State
  state                text not null default 'Open' references lead_state_type (value),
  -- Bussiness Status
  status               text not null default 'New',
  --
  status_reason        text,
  status_updated_at    timestamptz,
  status_updated_by_id text references users (id) on update cascade on delete set null,
  -- usesing fk as constraint
  foreign key (tid, status) references lead_status_type (tid, value)
);
  • state 更偏系统/全局枚举。
  • status 更偏租户可配置业务阶段。
  • status_reason/status_updated_at/status_updated_by_id 用于解释业务状态变化。
  • 状态类型表可拆成系统字典和租户字典。

Dictionary / Enum 实践

sql
create table if not exists tpl_sys_dict (
  value text not null primary key,
  label text,
  display_order bigint default nextval('seq_display_order'),
  attributes jsonb not null default '{}'::jsonb,
  properties jsonb not null default '{}'::jsonb,
  extensions jsonb not null default '{}'::jsonb
);
sql
create table if not exists tpl_dict_type (
  id text not null default 'dictv_' || public.gen_ulid() primary key,
  uid uuid not null default gen_random_uuid() unique,
  tid text not null default public.current_tenant_id() references public.tenant (tid),
  value text not null,
  label text not null,
  display_order bigint not null default nextval('seq_display_order'),
  active bool not null default true,
  metadata jsonb not null default '{}',
  unique (tid, value)
);

实践要点:

  • 系统枚举:不带租户,主键 value。
  • 租户字典:带 tid,unique(tid, value)。
  • extensions 可承载映射,例如 status -> state。

多态关联实践

entity_label

sql
entity_id   text not null,
entity_type text,
account_id  text generated always as (
  case when entity_type = 'Account' then entity_id end
) stored,
foreign key (account_id) references account (id) on delete cascade

entity_connection

表达两个任意实体的连接:

sql
entity1_id      text not null,
entity1_type    text not null,
entity1_role    text,
entity2_id      text not null,
entity2_type    text not null,
entity2_role    text,
connection_type text not null default 'Connection'

并通过:

sql
create unique index ... on entity_connection (
  tid,
  least(entity1_id, entity2_id),
  greatest(entity1_id, entity2_id)
) where connection_type = 'Connection';

避免无向连接重复。

文件/对象实践

text
filename / ext / mime_type
tags text[]
md5 / sha256 / size
hash generated as coalesce(sha256, md5)
data / text / markdown
width / height / length / duration
origin_url / object_url / ref_url
entity_type / entity_id

实践要点:

  • 文件内容、对象元数据、业务附件可以拆表。
  • hash 可用于去重。
  • entity_type/entity_id 支持附件绑定任意业务对象。

Logging 实践

http_request_log.sql 历史设计包含:

sql
create table http_request_log(
  method text not null,
  origin text not null,
  pathname text not null,
  url text not null,
  query jsonb default '{}',
  request_headers jsonb default '{}',
  request_payload jsonb,
  request_body bytea,
  response_headers jsonb default '{}',
  response_payload jsonb,
  response_body bytea,
  content_type text,
  content_length int,
  ok boolean,
  status_code int,
  status_text text,
  duration int,
  hit int not null default 0
);
  • request/response summary 分离。
  • duration、status_code、pathname 建索引。
  • 默认不应保存完整 header/body,容易泄露 token/secret。
  • 新设计应使用 redacted flat fields,例如 url_path、url_query、duration_ms。
  • request log 与 audit log 应分离。

可反哺到新 schema 文档的要点

  1. type-prefixed ID + uid + tid + eid 的资源表模式。
  2. attributes/properties/extensions 三层扩展语义。
  3. owner_type/owner_id + generated owner_user_id/owner_team_id 模式。
  4. created_by_id/updated_by_id/deleted_by_id auditor 字段。
  5. state/status/status_reason/status_updated_at/status_updated_by_id 模式,并推荐新命名 status_changed_at。
  6. 系统字典 vs 租户字典两类模板。
  7. 多态关联 generated column + FK 的技巧。
  8. logging 模式,避免完整 header/body 和 secret 泄露。

关联信息

反向链接、本文链接的其他页面和外部资料。

反向链接

  • Schema Design
    笔记 · Wode Practice

    Resource - 资源表、基础字段、扩展字段、来源字段。 · State - / / / reason / 软删除。 · Ownership - 、、、visibility、共享授权。 · Auth - AuthN、AuthZ、access token、permission grant、RBAC 边界。

  • Schema Logging
    笔记 · Schema Wode Practice

    Logging 表用于记录请求、审计、事件、指标事实。日志类数据通常是 append-only:写入一次,之后主要用于查询、分析、审计、报表和排障。 · | 类型 | 说明 | 示例 | · | Request Log | 每次 HTTP/RPC 请求完成记录 | 、 |

  • Schema Ownership
    笔记 · Schema Wode Practice

    Ownership 描述“资源归谁管理、谁可以默认访问、谁创建/修改/删除了资源”。它是资源权限、分享、孤儿对象处理、审计的基础。 · | column | 语义 | 是否用于权限 | · | | 谁创建了资源 | | · | | 谁最后修改 | 审计 |

  • Schema Resource
    笔记 · Schema Wode Practice

    资源表是系统里“可以被引用、展示、管理、授权、审计”的核心对象表,例如 user、team、datasource、mcpserver、order、document、workflow。 · 资源表的重点不是“字段越全越好”,而是让对象具备稳定身份、可追踪来源、可扩展元数据、可软删除、可做权限和审计。

  • Schema State
    笔记 · Schema Wode Practice

    状态字段用于描述资源当前处于什么阶段、是否可用、为什么变成这样,以及状态变化发生在什么时候。 · 推荐区分: · | column | 语义 | 特点 | · | | 系统状态 | 少量固定值,系统内部控制,不鼓励用户自定义 | · | | 业务状态 | 面向业务流程,可扩展,可展示给用户 |

最近更新commit c8fc727编辑