Schema Wode Practice
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。
资源表通常包含:
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 / extensionssid bigint not null default public.next_entity_sid('Lead')作为面向用户/业务的序列号。
Ownership 相关实践
典型模式:
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_idgenerated column 让外键和索引可落地。- auditor 字段与 owner 字段分离。
Status
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 实践
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
);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
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 cascadeentity_connection
表达两个任意实体的连接:
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'并通过:
create unique index ... on entity_connection (
tid,
least(entity1_id, entity2_id),
greatest(entity1_id, entity2_id)
) where connection_type = 'Connection';避免无向连接重复。
文件/对象实践
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 历史设计包含:
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 文档的要点
- type-prefixed ID +
uid+tid+eid的资源表模式。 attributes/properties/extensions三层扩展语义。owner_type/owner_id+ generatedowner_user_id/owner_team_id模式。created_by_id/updated_by_id/deleted_by_idauditor 字段。state/status/status_reason/status_updated_at/status_updated_by_id模式,并推荐新命名status_changed_at。- 系统字典 vs 租户字典两类模板。
- 多态关联 generated column + FK 的技巧。
- 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 | 语义 | 特点 | · | | 系统状态 | 少量固定值,系统内部控制,不鼓励用户自定义 | · | | 业务状态 | 面向业务流程,可扩展,可展示给用户 |