-- topology_api/migrations/006_presentation_styles.sql -- Database-driven presentation semantics for topology diagrams. CREATE TABLE IF NOT EXISTS topology.diagram_themes ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), base_id uuid NOT NULL REFERENCES topology.bases(id) ON DELETE CASCADE, theme_key text NOT NULL, name text NOT NULL, description text, tokens jsonb NOT NULL DEFAULT '{}'::jsonb, is_default boolean NOT NULL DEFAULT false, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT uq_diagram_themes_base_key UNIQUE (base_id, theme_key) ); CREATE UNIQUE INDEX IF NOT EXISTS uq_diagram_themes_default_per_base ON topology.diagram_themes(base_id) WHERE is_default; CREATE TABLE IF NOT EXISTS topology.diagram_node_styles ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), theme_id uuid NOT NULL REFERENCES topology.diagram_themes(id) ON DELETE CASCADE, style_key text NOT NULL, display_name text NOT NULL, fill_color text NOT NULL, stroke_color text NOT NULL, stroke_width numeric NOT NULL, corner_radius numeric NOT NULL DEFAULT 16, title_color text, meta_color text, hint_color text, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT uq_diagram_node_styles_theme_key UNIQUE (theme_id, style_key), CONSTRAINT ck_diagram_node_stroke_width CHECK (stroke_width >= 0), CONSTRAINT ck_diagram_node_corner_radius CHECK (corner_radius >= 0) ); CREATE TABLE IF NOT EXISTS topology.diagram_edge_styles ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), theme_id uuid NOT NULL REFERENCES topology.diagram_themes(id) ON DELETE CASCADE, connection_type text NOT NULL, display_name text NOT NULL, stroke_color text NOT NULL, stroke_width numeric NOT NULL, dash_array text, line_cap text NOT NULL DEFAULT 'square', legend_group text, legend_order integer NOT NULL DEFAULT 0, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT uq_diagram_edge_styles_theme_type UNIQUE (theme_id, connection_type), CONSTRAINT ck_diagram_edge_stroke_width CHECK (stroke_width >= 0), CONSTRAINT ck_diagram_edge_line_cap CHECK (line_cap IN ('butt', 'round', 'square')), CONSTRAINT ck_diagram_edge_dash_array CHECK ( dash_array IS NULL OR dash_array ~ '^[0-9]+( [0-9]+)*$' ) ); CREATE TABLE IF NOT EXISTS topology.diagram_decoration_styles ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), theme_id uuid NOT NULL REFERENCES topology.diagram_themes(id) ON DELETE CASCADE, decoration_key text NOT NULL, display_name text NOT NULL, fill_color text NOT NULL, stroke_color text NOT NULL, stroke_width numeric NOT NULL, label text, label_color text, render_params jsonb NOT NULL DEFAULT '{}'::jsonb, legend_order integer NOT NULL DEFAULT 0, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT uq_diagram_decoration_styles_theme_key UNIQUE (theme_id, decoration_key), CONSTRAINT ck_diagram_decoration_stroke_width CHECK (stroke_width >= 0) ); CREATE TABLE IF NOT EXISTS topology.diagram_legend_items ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), theme_id uuid NOT NULL REFERENCES topology.diagram_themes(id) ON DELETE CASCADE, legend_key text NOT NULL, label text NOT NULL, item_type text NOT NULL, style_ref text NOT NULL, display_order integer NOT NULL DEFAULT 0, is_visible boolean NOT NULL DEFAULT true, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT uq_diagram_legend_items_theme_key UNIQUE (theme_id, legend_key), CONSTRAINT ck_diagram_legend_item_type CHECK (item_type IN ('edge', 'decoration', 'node')) ); ALTER TABLE topology.diagram_layouts ADD COLUMN IF NOT EXISTS theme_id uuid REFERENCES topology.diagram_themes(id);