-- 043: EDL projects — the intake half of the editor-v2 assemble feature. -- -- edl_projects stores a validated editor timeline (the EdlProject shape from -- apps/api/src/media-control/edl.ts) as jsonb. The api validates strictly -- (closed enums, integer ms, unknown keys rejected, filtergraph metacharacters -- blocked in card text) before anything is written; the media-worker -- re-validates the job's input_json on the assemble lane (044). -- -- video_processing_jobs gains kind 'assemble' (044's claim already admits it) -- and video_asset_id becomes nullable: an assemble job is queued from an EDL -- project, not a single source asset, so there is no asset to point at yet — -- the produced output is a derived video_assets row like compose/mix. -- -- RLS / NULLIF / reject_workspace_change / sp_app grants follow the -- 001/008/021/026/029 conventions: no app.workspace_id => NULL => no rows; -- FORCE binds sp_app too. The jsonb column is content, not a schema facet: -- the authoritative typed validation is app-side (edl.ts). BEGIN; CREATE TABLE edl_projects ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE ON UPDATE RESTRICT, group_id uuid NULL, project jsonb NOT NULL, created_by uuid NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE (workspace_id, id) ); -- Tenant-pinned reference target (029 style): the composite UNIQUE lets child -- rows pin (id, workspace_id) so an EDL project can never point across tenants. CREATE INDEX edl_projects_ws_updated_idx ON edl_projects (workspace_id, updated_at DESC); CREATE TRIGGER trg_edl_projects_ws_immutable BEFORE UPDATE ON edl_projects FOR EACH ROW EXECUTE FUNCTION reject_workspace_change(); ALTER TABLE edl_projects ENABLE ROW LEVEL SECURITY; ALTER TABLE edl_projects FORCE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation ON edl_projects USING (workspace_id = NULLIF(current_setting('app.workspace_id', true), '')::uuid) WITH CHECK (workspace_id = NULLIF(current_setting('app.workspace_id', true), '')::uuid); GRANT SELECT, INSERT, UPDATE, DELETE ON edl_projects TO sp_app; -- The assemble lane: widen the 039 kind CHECK so an undecodable row cannot -- exist, and let an assemble job carry no source asset yet. ALTER TABLE video_processing_jobs DROP CONSTRAINT video_processing_jobs_kind_check; ALTER TABLE video_processing_jobs ADD CONSTRAINT video_processing_jobs_kind_check CHECK (kind IN ('probe', 'compose', 'mix', 'assemble')); ALTER TABLE video_processing_jobs ALTER COLUMN video_asset_id DROP NOT NULL; COMMIT;