-- Phase 3: group-inherited config — the `vars` table + an app environment -- marker. See docs/design/groups-and-project-tool.md §3, §5.1. -- -- `vars` is the net-new, env-scoped configuration layer (greenfield — there -- is no env-agnostic config today, only `secrets`). A var is owned by -- exactly one group OR one app, optionally scoped to an environment, and -- resolved down the tree (§3): env-filter first, then nearest level wins. -- -- "An environment is an app": each env is already a distinct app row. To -- env-filter group-level `@E` values, the resolver must know which env an -- app represents — recorded here on `apps.environment` (NULL = env-agnostic, -- set at app-create from the CLI's known env). ALTER TABLE apps ADD COLUMN environment TEXT; CREATE TABLE vars ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- Polymorphic owner: exactly one of the two FKs is set. Real FKs (not a -- bare owner_id) so ON DELETE CASCADE works per owner kind and a dangling -- owner is impossible. group_id UUID REFERENCES groups(id) ON DELETE CASCADE, app_id UUID REFERENCES apps(id) ON DELETE CASCADE, CONSTRAINT vars_owner_exactly_one CHECK ((group_id IS NULL) <> (app_id IS NULL)), -- '*' = env-agnostic; otherwise an env name matched against -- apps.environment. NOT NULL with a '*' sentinel so the uniqueness -- indexes are total (a NULL scope would break UNIQUE). environment_scope TEXT NOT NULL DEFAULT '*', key TEXT NOT NULL, -- JSONB per the v1.1 data-plane convention. A tombstone (deletion of an -- inherited key, §3) is the explicit boolean below, NOT value = 'null' -- — JSON null is a legitimate value and must stay distinguishable. value JSONB NOT NULL, is_tombstone BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- One row per (owner, scope, key). Partial unique indexes because the owner -- is split across two nullable columns. CREATE UNIQUE INDEX vars_group_uidx ON vars (group_id, environment_scope, key) WHERE group_id IS NOT NULL; CREATE UNIQUE INDEX vars_app_uidx ON vars (app_id, environment_scope, key) WHERE app_id IS NOT NULL; CREATE INDEX vars_group_id_idx ON vars (group_id) WHERE group_id IS NOT NULL; CREATE INDEX vars_app_id_idx ON vars (app_id) WHERE app_id IS NOT NULL;