5eef13b615
方案A:所有对象写入经 loopback 网关,持久计划/grant/intent/逐版本 receipt 与 attempt→grant delivery 落在治理 PG;scope 由 provider+endpoint+bucket 决定, 同一物理桶只允许一个写域。版本 append 不等于 CAS,未锚定计划在首笔业务写前拒绝。 本提交只含网关与其适配层接线、协议文档;生产独占、凭据切换与桶设置未改动。
75 lines
3.5 KiB
PL/PgSQL
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 $$;
|