Initial commit
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
CREATE TABLE osint.levels (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
subtitle TEXT NOT NULL DEFAULT '',
|
||||
status TEXT NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'published', 'archived')),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE osint.widgets (
|
||||
id TEXT PRIMARY KEY,
|
||||
level_id TEXT NOT NULL REFERENCES osint.levels(id) ON DELETE CASCADE,
|
||||
widget_type TEXT NOT NULL CHECK (widget_type IN ('document', 'evidence', 'note', 'event')),
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL DEFAULT '',
|
||||
config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
source_widget_id TEXT REFERENCES osint.widgets(id) ON DELETE SET NULL,
|
||||
source_region_key TEXT,
|
||||
event_date DATE,
|
||||
x DOUBLE PRECISION,
|
||||
y DOUBLE PRECISION,
|
||||
width DOUBLE PRECISION,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (level_id, id)
|
||||
);
|
||||
|
||||
CREATE INDEX widgets_level_type_idx ON osint.widgets(level_id, widget_type, sort_order);
|
||||
|
||||
CREATE TABLE osint.widget_regions (
|
||||
id TEXT PRIMARY KEY,
|
||||
document_widget_id TEXT NOT NULL REFERENCES osint.widgets(id) ON DELETE CASCADE,
|
||||
region_key TEXT NOT NULL,
|
||||
label TEXT NOT NULL,
|
||||
excerpt TEXT NOT NULL,
|
||||
event_date DATE,
|
||||
config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
UNIQUE (document_widget_id, region_key)
|
||||
);
|
||||
|
||||
CREATE TABLE osint.level_connections (
|
||||
id TEXT PRIMARY KEY,
|
||||
level_id TEXT NOT NULL REFERENCES osint.levels(id) ON DELETE CASCADE,
|
||||
from_widget_id TEXT NOT NULL REFERENCES osint.widgets(id) ON DELETE CASCADE,
|
||||
to_widget_id TEXT NOT NULL REFERENCES osint.widgets(id) ON DELETE CASCADE,
|
||||
config JSONB NOT NULL DEFAULT '{}'::jsonb
|
||||
);
|
||||
|
||||
CREATE TABLE osint.playthroughs (
|
||||
id TEXT PRIMARY KEY,
|
||||
level_id TEXT NOT NULL REFERENCES osint.levels(id) ON DELETE CASCADE,
|
||||
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'completed', 'abandoned')),
|
||||
viewport JSONB NOT NULL DEFAULT '{"x":0,"y":28,"zoom":0.7}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE osint.playthrough_widget_state (
|
||||
playthrough_id TEXT NOT NULL REFERENCES osint.playthroughs(id) ON DELETE CASCADE,
|
||||
widget_id TEXT NOT NULL REFERENCES osint.widgets(id) ON DELETE CASCADE,
|
||||
x DOUBLE PRECISION NOT NULL,
|
||||
y DOUBLE PRECISION NOT NULL,
|
||||
width DOUBLE PRECISION NOT NULL,
|
||||
hidden BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
annotation TEXT,
|
||||
PRIMARY KEY (playthrough_id, widget_id)
|
||||
);
|
||||
|
||||
CREATE TABLE osint.playthrough_widgets (
|
||||
id TEXT PRIMARY KEY,
|
||||
playthrough_id TEXT NOT NULL REFERENCES osint.playthroughs(id) ON DELETE CASCADE,
|
||||
widget_type TEXT NOT NULL CHECK (widget_type IN ('evidence', 'note', 'event')),
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL DEFAULT '',
|
||||
source_widget_id TEXT REFERENCES osint.widgets(id) ON DELETE SET NULL,
|
||||
source_region_key TEXT,
|
||||
event_date DATE,
|
||||
x DOUBLE PRECISION NOT NULL,
|
||||
y DOUBLE PRECISION NOT NULL,
|
||||
width DOUBLE PRECISION NOT NULL,
|
||||
config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE osint.playthrough_connections (
|
||||
id TEXT PRIMARY KEY,
|
||||
playthrough_id TEXT NOT NULL REFERENCES osint.playthroughs(id) ON DELETE CASCADE,
|
||||
from_widget_id TEXT NOT NULL,
|
||||
to_widget_id TEXT NOT NULL,
|
||||
config JSONB NOT NULL DEFAULT '{}'::jsonb
|
||||
);
|
||||
|
||||
-- Preserve levels saved by the pre-widget architecture, if any exist.
|
||||
INSERT INTO osint.levels (id, title, subtitle, status, created_at, updated_at)
|
||||
SELECT id, state_json->>'title', COALESCE(state_json->>'subtitle', ''), 'draft', created_at, updated_at
|
||||
FROM osint.cases;
|
||||
|
||||
INSERT INTO osint.widgets (id, level_id, widget_type, title, content, config, event_date, sort_order)
|
||||
SELECT doc->>'id', c.id, 'document', doc->>'title', '',
|
||||
jsonb_build_object('kind', doc->>'kind', 'date', doc->>'date', 'body', COALESCE(doc->'body', '[]'::jsonb)),
|
||||
NULLIF(doc->>'date', '')::date, ordinality::integer
|
||||
FROM osint.cases c
|
||||
CROSS JOIN LATERAL jsonb_array_elements(c.state_json->'documents') WITH ORDINALITY AS item(doc, ordinality);
|
||||
|
||||
INSERT INTO osint.widget_regions (id, document_widget_id, region_key, label, excerpt, event_date, sort_order)
|
||||
SELECT (doc->>'id') || ':' || (region->>'id'), doc->>'id', region->>'id', region->>'label', region->>'excerpt',
|
||||
NULLIF(region->>'date', '')::date, region_ordinality::integer
|
||||
FROM osint.cases c
|
||||
CROSS JOIN LATERAL jsonb_array_elements(c.state_json->'documents') AS docs(doc)
|
||||
CROSS JOIN LATERAL jsonb_array_elements(doc->'regions') WITH ORDINALITY AS regions(region, region_ordinality);
|
||||
|
||||
INSERT INTO osint.widgets (id, level_id, widget_type, title, content, source_widget_id, source_region_key, event_date, x, y, width, sort_order)
|
||||
SELECT ev->>'id', c.id, ev->>'type', ev->>'title', ev->>'content', NULLIF(ev->>'sourceDocumentId', ''),
|
||||
NULLIF(ev->>'sourceRegionId', ''), NULLIF(ev->>'eventDate', '')::date,
|
||||
(ev->>'x')::double precision, (ev->>'y')::double precision, (ev->>'width')::double precision, ordinality::integer
|
||||
FROM osint.cases c
|
||||
CROSS JOIN LATERAL jsonb_array_elements(c.state_json->'evidence') WITH ORDINALITY AS item(ev, ordinality);
|
||||
|
||||
INSERT INTO osint.level_connections (id, level_id, from_widget_id, to_widget_id)
|
||||
SELECT conn->>'id', c.id, conn->>'fromEvidenceId', conn->>'toEvidenceId'
|
||||
FROM osint.cases c
|
||||
CROSS JOIN LATERAL jsonb_array_elements(c.state_json->'connections') AS connections(conn);
|
||||
|
||||
INSERT INTO osint.playthroughs (id, level_id, viewport)
|
||||
SELECT 'default:' || id, id, COALESCE(state_json->'viewport', '{"x":0,"y":28,"zoom":0.7}'::jsonb)
|
||||
FROM osint.cases;
|
||||
|
||||
DROP TABLE osint.cases;
|
||||
Reference in New Issue
Block a user