Files
knowledge-governance/internal/objectgateway/schema.sql
T
姚章浩 5eef13b615 feat(object-gateway): 统一对象写网关与不可变治理日志
方案A:所有对象写入经 loopback 网关,持久计划/grant/intent/逐版本 receipt 与
attempt→grant delivery 落在治理 PG;scope 由 provider+endpoint+bucket 决定,
同一物理桶只允许一个写域。版本 append 不等于 CAS,未锚定计划在首笔业务写前拒绝。

本提交只含网关与其适配层接线、协议文档;生产独占、凭据切换与桶设置未改动。
2026-11-01 11:35:05 +08:00

75 lines
3.5 KiB
PL/PgSQL

-- Independent governance journal; never install in a WeKnora business schema.
CREATE TABLE IF NOT EXISTS kg_object_gateway_plans (
scope text NOT NULL,
plan text NOT NULL,
body bytea NOT NULL,
PRIMARY KEY(scope,plan)
);
CREATE TABLE IF NOT EXISTS kg_object_gateway_scopes (
scope text PRIMARY KEY,
epoch bigint NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS kg_object_gateway_grants (
scope text NOT NULL REFERENCES kg_object_gateway_scopes(scope),
epoch bigint NOT NULL CHECK (epoch > 0),
owner text NOT NULL,
plan text NOT NULL,
PRIMARY KEY(scope,epoch)
);
CREATE TABLE IF NOT EXISTS kg_object_gateway_intents (
scope text NOT NULL REFERENCES kg_object_gateway_scopes(scope),
operation text NOT NULL,
key text NOT NULL,
request bytea NOT NULL,
recorded_at timestamptz NOT NULL DEFAULT clock_timestamp(),
PRIMARY KEY(scope,operation)
);
CREATE INDEX IF NOT EXISTS kg_object_gateway_key ON kg_object_gateway_intents(scope,key);
CREATE TABLE IF NOT EXISTS kg_object_gateway_receipts (
scope text NOT NULL,
operation text NOT NULL,
receipt bytea NOT NULL,
recorded_at timestamptz NOT NULL DEFAULT clock_timestamp(),
PRIMARY KEY(scope,operation),
FOREIGN KEY(scope,operation) REFERENCES kg_object_gateway_intents(scope,operation)
);
CREATE TABLE IF NOT EXISTS kg_object_gateway_deliveries (
scope text NOT NULL,
job text NOT NULL,
attempt_epoch bigint NOT NULL CHECK(attempt_epoch>0),
claim bytea NOT NULL,
grant_epoch bigint NOT NULL,
grant_body bytea NOT NULL,
PRIMARY KEY(scope,job,attempt_epoch),
FOREIGN KEY(scope,grant_epoch) REFERENCES kg_object_gateway_grants(scope,epoch)
);
CREATE OR REPLACE FUNCTION kg_object_gateway_immutable() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
RAISE EXCEPTION 'object gateway evidence is immutable';
END;
$$;
DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname='kg_object_gateway_deliveries_immutable') THEN
CREATE TRIGGER kg_object_gateway_deliveries_immutable BEFORE UPDATE OR DELETE ON kg_object_gateway_deliveries FOR EACH ROW EXECUTE FUNCTION kg_object_gateway_immutable();
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname='kg_object_gateway_plans_immutable') THEN
CREATE TRIGGER kg_object_gateway_plans_immutable BEFORE UPDATE OR DELETE ON kg_object_gateway_plans FOR EACH ROW EXECUTE FUNCTION kg_object_gateway_immutable();
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname='kg_object_gateway_intents_immutable') THEN
CREATE TRIGGER kg_object_gateway_intents_immutable BEFORE UPDATE OR DELETE ON kg_object_gateway_intents FOR EACH ROW EXECUTE FUNCTION kg_object_gateway_immutable();
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname='kg_object_gateway_receipts_immutable') THEN
CREATE TRIGGER kg_object_gateway_receipts_immutable BEFORE UPDATE OR DELETE ON kg_object_gateway_receipts FOR EACH ROW EXECUTE FUNCTION kg_object_gateway_immutable();
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname='kg_object_gateway_grants_immutable') THEN
CREATE TRIGGER kg_object_gateway_grants_immutable BEFORE UPDATE OR DELETE ON kg_object_gateway_grants FOR EACH ROW EXECUTE FUNCTION kg_object_gateway_immutable();
END IF;
END $$;
DO $$ DECLARE t text; BEGIN
FOREACH t IN ARRAY ARRAY['plans','grants','intents','receipts','deliveries'] LOOP
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname='kg_object_gateway_'||t||'_no_truncate') THEN
EXECUTE format('CREATE TRIGGER %I BEFORE TRUNCATE ON %I FOR EACH STATEMENT EXECUTE FUNCTION kg_object_gateway_immutable()', 'kg_object_gateway_'||t||'_no_truncate', 'kg_object_gateway_'||t);
END IF;
END LOOP;
END $$;