-- v1.1.1: Key-value store — see blueprint §8.1 + docs/sdk-shape.md. -- -- Identity tuple `(app_id, collection, key)`. `app_id` is first in the -- primary key so the implicit index is always per-app; cross-app reads -- cannot happen even with a buggy query. Collections are a required -- namespace inside an app — the same key can live in different -- collections without collision. -- -- `value` is JSONB so scripts can store nested structures without -- a separate serialization step. No TTL column in v1.1.1; deferred -- until a concrete need surfaces (the blueprint reserved one but the -- v1.1.1 SDK surface — get/set/has/delete/list — doesn't expose TTL). CREATE TABLE kv_entries ( app_id UUID NOT NULL REFERENCES apps(id) ON DELETE CASCADE, collection TEXT NOT NULL, key TEXT NOT NULL, value JSONB NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (app_id, collection, key) ); -- Supports list-by-collection (keyset pagination) and per-collection -- triggers' fan-out scans. The PK already covers (app_id, collection) -- as a prefix but spelling out the explicit index makes intent clear -- for the planner. CREATE INDEX idx_kv_entries_app_collection ON kv_entries (app_id, collection);