--
-- PostgreSQL database dump
--


-- Dumped from database version 16.14
-- Dumped by pg_dump version 16.14

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

--
-- Name: citext; Type: EXTENSION; Schema: -; Owner: -
--

CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public;


--
-- Name: EXTENSION citext; Type: COMMENT; Schema: -; Owner: -
--

COMMENT ON EXTENSION citext IS 'data type for case-insensitive character strings';


--
-- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: -
--

CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA public;


--
-- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner: -
--

COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions';


--
-- Name: set_updated_at(); Type: FUNCTION; Schema: public; Owner: -
--

CREATE FUNCTION public.set_updated_at() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$;


SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- Name: admin_audit_logs; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.admin_audit_logs (
    id bigint NOT NULL,
    admin_id uuid,
    admin_username text NOT NULL,
    action character varying(64) NOT NULL,
    resource_type character varying(64) NOT NULL,
    resource_id text,
    reason text,
    detail jsonb DEFAULT '{}'::jsonb NOT NULL,
    ip_address inet,
    trace_id character varying(64),
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);


--
-- Name: admin_audit_logs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--

CREATE SEQUENCE public.admin_audit_logs_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


--
-- Name: admin_audit_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--

ALTER SEQUENCE public.admin_audit_logs_id_seq OWNED BY public.admin_audit_logs.id;


--
-- Name: admin_refresh_tokens; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.admin_refresh_tokens (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    admin_id uuid NOT NULL,
    token_hash character(64) NOT NULL,
    expires_at timestamp with time zone NOT NULL,
    revoked_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);


--
-- Name: admin_users; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.admin_users (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    username public.citext NOT NULL,
    password_hash text NOT NULL,
    enabled boolean DEFAULT true NOT NULL,
    last_login_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone
);


--
-- Name: announcements; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.announcements (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    title character varying(200) NOT NULL,
    content text NOT NULL,
    status character varying(16) DEFAULT 'draft'::character varying NOT NULL,
    pinned boolean DEFAULT false NOT NULL,
    publish_at timestamp with time zone,
    offline_at timestamp with time zone,
    published_by uuid,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    CONSTRAINT announcements_check CHECK (((publish_at IS NULL) OR (offline_at IS NULL) OR (offline_at > publish_at))),
    CONSTRAINT announcements_status_check CHECK (((status)::text = ANY ((ARRAY['draft'::character varying, 'published'::character varying, 'offline'::character varying])::text[])))
);


--
-- Name: canvas_projects; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.canvas_projects (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    user_id uuid NOT NULL,
    name public.citext NOT NULL,
    schema_version smallint DEFAULT 1 NOT NULL,
    document jsonb NOT NULL,
    revision bigint DEFAULT 1 NOT NULL,
    node_count integer DEFAULT 0 NOT NULL,
    cover_url text,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    CONSTRAINT canvas_projects_document_check CHECK ((jsonb_typeof(document) = 'object'::text)),
    CONSTRAINT canvas_projects_node_count_check CHECK ((node_count >= 0)),
    CONSTRAINT canvas_projects_revision_check CHECK ((revision > 0)),
    CONSTRAINT canvas_projects_schema_version_check CHECK ((schema_version = 1))
);


--
-- Name: channel_asset_cache; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.channel_asset_cache (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    channel_id uuid NOT NULL,
    media_asset_id uuid NOT NULL,
    object_sha256 character(64),
    upstream_url text NOT NULL,
    expires_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);


--
-- Name: channel_balance_snapshots; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.channel_balance_snapshots (
    id bigint NOT NULL,
    channel_id uuid NOT NULL,
    balance numeric(18,4) NOT NULL,
    currency character varying(16) NOT NULL,
    synced_at timestamp with time zone NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);


--
-- Name: channel_balance_snapshots_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--

CREATE SEQUENCE public.channel_balance_snapshots_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


--
-- Name: channel_balance_snapshots_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--

ALTER SEQUENCE public.channel_balance_snapshots_id_seq OWNED BY public.channel_balance_snapshots.id;


--
-- Name: channels; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.channels (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    name public.citext NOT NULL,
    channel_type character varying(20) NOT NULL,
    base_url text NOT NULL,
    api_key_ciphertext text,
    api_key_last4 character varying(4),
    encryption_key_version character varying(32),
    warning_threshold numeric(18,2) DEFAULT 500 NOT NULL,
    enabled boolean DEFAULT true NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    max_concurrency integer DEFAULT 500 NOT NULL,
    max_user_concurrency integer DEFAULT 10 NOT NULL,
    channel_points_per_cny numeric(18,6),
    CONSTRAINT channels_channel_type_check CHECK (((channel_type)::text = ANY ((ARRAY['relay'::character varying, 'official'::character varying])::text[]))),
    CONSTRAINT channels_max_concurrency_check CHECK (((max_concurrency >= 1) AND (max_concurrency <= 5000))),
    CONSTRAINT channels_max_user_concurrency_check CHECK (((max_user_concurrency >= 1) AND (max_user_concurrency <= 500))),
    CONSTRAINT channels_warning_threshold_check CHECK ((warning_threshold >= (0)::numeric)),
    CONSTRAINT chk_channels_points_per_cny CHECK (((channel_points_per_cny IS NULL) OR (channel_points_per_cny > (0)::numeric))),
    CONSTRAINT chk_channels_user_concurrency CHECK ((max_user_concurrency <= max_concurrency))
);


--
-- Name: creative_projects; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.creative_projects (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    user_id uuid NOT NULL,
    project_type character varying(24) DEFAULT 'video_redraw'::character varying NOT NULL,
    name public.citext NOT NULL,
    cover_asset_id uuid,
    style_id uuid NOT NULL,
    era_type character varying(32) NOT NULL,
    custom_era character varying(100),
    aspect_ratio character varying(8) NOT NULL,
    localization character varying(16),
    source_video_asset_id uuid,
    subtitle_asset_id uuid,
    audio_source character varying(24) DEFAULT 'video_audio'::character varying NOT NULL,
    source_language character varying(16),
    redraw_status character varying(32) DEFAULT 'draft'::character varying NOT NULL,
    analysis_message text,
    redraw_script text,
    short_drama_type character varying(100),
    play_count character varying(100),
    audience_profile text,
    producer character varying(200),
    cast_members jsonb DEFAULT '[]'::jsonb NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    video_resolution character varying(8) DEFAULT '720p'::character varying NOT NULL,
    CONSTRAINT creative_projects_aspect_ratio_check CHECK (((aspect_ratio)::text = ANY ((ARRAY['9:16'::character varying, '16:9'::character varying])::text[]))),
    CONSTRAINT creative_projects_audio_source_check CHECK (((audio_source)::text = ANY ((ARRAY['video_audio'::character varying, 'subtitle_file'::character varying])::text[]))),
    CONSTRAINT creative_projects_check CHECK (((((era_type)::text = 'other'::text) AND (NULLIF(TRIM(BOTH FROM custom_era), ''::text) IS NOT NULL)) OR (((era_type)::text <> 'other'::text) AND (custom_era IS NULL)))),
    CONSTRAINT creative_projects_check1 CHECK (((((project_type)::text = 'video_redraw'::text) AND ((localization)::text = ANY ((ARRAY['china'::character varying, 'uk_us'::character varying, 'korea'::character varying, 'japan'::character varying, 'france'::character varying, 'russia'::character varying, 'vietnam'::character varying, 'thailand'::character varying, 'india'::character varying])::text[]))) OR (((project_type)::text = 'premium_drama'::text) AND (localization IS NULL)))),
    CONSTRAINT creative_projects_era_type_check CHECK (((era_type)::text = ANY ((ARRAY['modern_city'::character varying, 'ancient_history'::character varying, 'ancient_fantasy'::character varying, 'ancient_xianxia'::character varying, 'future_scifi'::character varying, 'other'::character varying])::text[]))),
    CONSTRAINT creative_projects_project_type_check CHECK (((project_type)::text = ANY ((ARRAY['premium_drama'::character varying, 'video_redraw'::character varying])::text[]))),
    CONSTRAINT creative_projects_redraw_status_check CHECK (((redraw_status)::text = ANY ((ARRAY['draft'::character varying, 'uploaded'::character varying, 'analyzing'::character varying, 'review'::character varying, 'generating'::character varying, 'failed'::character varying])::text[]))),
    CONSTRAINT creative_projects_cast_members_check CHECK ((jsonb_typeof(cast_members) = 'array'::text)),
    CONSTRAINT creative_projects_video_resolution_check CHECK (((video_resolution)::text = ANY ((ARRAY['480p'::character varying, '720p'::character varying, '1080p'::character varying])::text[])))
);

COMMENT ON COLUMN public.creative_projects.cast_members IS 'JSON array of cast members; follower_count is stored as text when present.';


--
-- Name: drama_import_sessions; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.drama_import_sessions (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    user_id uuid NOT NULL,
    project_id uuid NOT NULL,
    source_type character varying(24) NOT NULL,
    source_filename character varying(255),
    raw_content text NOT NULL,
    content_sha256 character(64) NOT NULL,
    preview_data jsonb DEFAULT '{}'::jsonb NOT NULL,
    expires_at timestamp with time zone NOT NULL,
    consumed_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT drama_import_sessions_source_type_check CHECK (((source_type)::text = ANY ((ARRAY['pasted_text'::character varying, 'txt'::character varying, 'doc'::character varying, 'docx'::character varying])::text[])))
);


--
-- Name: drama_parse_batches; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.drama_parse_batches (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    project_id uuid NOT NULL,
    user_id uuid NOT NULL,
    mode character varying(16) NOT NULL,
    status character varying(24) DEFAULT 'queued'::character varying NOT NULL,
    total_count integer DEFAULT 0 NOT NULL,
    completed_count integer DEFAULT 0 NOT NULL,
    failed_count integer DEFAULT 0 NOT NULL,
    current_episode_id uuid,
    cancel_requested_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    finished_at timestamp with time zone,
    CONSTRAINT drama_parse_batches_completed_count_check CHECK ((completed_count >= 0)),
    CONSTRAINT drama_parse_batches_failed_count_check CHECK ((failed_count >= 0)),
    CONSTRAINT drama_parse_batches_mode_check CHECK (((mode)::text = ANY ((ARRAY['all'::character varying, 'unparsed'::character varying, 'from_episode'::character varying])::text[]))),
    CONSTRAINT drama_parse_batches_status_check CHECK (((status)::text = ANY ((ARRAY['queued'::character varying, 'running'::character varying, 'cancel_requested'::character varying, 'succeeded'::character varying, 'failed'::character varying, 'cancelled'::character varying])::text[]))),
    CONSTRAINT drama_parse_batches_total_count_check CHECK ((total_count >= 0))
);


--
-- Name: drama_parse_tasks; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.drama_parse_tasks (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    request_id character varying(100) NOT NULL,
    batch_id uuid,
    user_id uuid NOT NULL,
    project_id uuid NOT NULL,
    episode_id uuid NOT NULL,
    channel_id uuid NOT NULL,
    model_id uuid NOT NULL,
    source_sha256 character(64) NOT NULL,
    status character varying(24) DEFAULT 'queued'::character varying NOT NULL,
    attempt_count integer DEFAULT 0 NOT NULL,
    model_snapshot jsonb DEFAULT '{}'::jsonb NOT NULL,
    prompt_snapshot text NOT NULL,
    context_snapshot jsonb DEFAULT '{}'::jsonb NOT NULL,
    normalized_result jsonb,
    input_tokens bigint,
    output_tokens bigint,
    total_tokens bigint,
    token_count_source character varying(16),
    usage_raw jsonb,
    billing_snapshot jsonb DEFAULT '{}'::jsonb NOT NULL,
    estimated_points numeric(20,2) DEFAULT 0 NOT NULL,
    prepaid_points numeric(20,2) DEFAULT 0 NOT NULL,
    actual_points numeric(20,2),
    cost_refunded boolean DEFAULT false NOT NULL,
    request_char_count bigint DEFAULT 0 NOT NULL,
    response_char_count bigint DEFAULT 0 NOT NULL,
    lease_owner character varying(120),
    lease_until timestamp with time zone,
    cancel_requested_at timestamp with time zone,
    error_code character varying(100),
    error_message text,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    started_at timestamp with time zone,
    finished_at timestamp with time zone,
    CONSTRAINT drama_parse_tasks_attempt_count_check CHECK ((attempt_count >= 0)),
    CONSTRAINT drama_parse_tasks_actual_points_check CHECK ((actual_points >= (0)::numeric)),
    CONSTRAINT drama_parse_tasks_estimated_points_check CHECK ((estimated_points >= (0)::numeric)),
    CONSTRAINT drama_parse_tasks_prepaid_points_check CHECK ((prepaid_points >= (0)::numeric)),
    CONSTRAINT drama_parse_tasks_status_check CHECK (((status)::text = ANY ((ARRAY['queued'::character varying, 'running'::character varying, 'retry_wait'::character varying, 'succeeded'::character varying, 'failed'::character varying, 'cancel_requested'::character varying, 'cancelled'::character varying])::text[]))),
    CONSTRAINT drama_parse_tasks_token_count_source_check CHECK (((token_count_source)::text = ANY ((ARRAY['upstream'::character varying, 'local'::character varying, 'mixed'::character varying])::text[])))
);


--
-- Name: episode_continuity_contexts; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.episode_continuity_contexts (
    episode_id uuid NOT NULL,
    parse_task_id uuid NOT NULL,
    source_sha256 character(64) NOT NULL,
    summary jsonb DEFAULT '{}'::jsonb NOT NULL,
    stale boolean DEFAULT false NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);


--
-- Name: episode_sources; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.episode_sources (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    episode_id uuid NOT NULL,
    title character varying(200),
    raw_content text NOT NULL,
    char_count integer NOT NULL,
    source_type character varying(24) NOT NULL,
    source_filename character varying(255),
    content_sha256 character(64) NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT episode_sources_char_count_check CHECK ((char_count > 0)),
    CONSTRAINT episode_sources_source_type_check CHECK (((source_type)::text = ANY ((ARRAY['pasted_text'::character varying, 'txt'::character varying, 'doc'::character varying, 'docx'::character varying])::text[])))
);


--
-- Name: episode_storyboards; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.episode_storyboards (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    episode_id uuid,
    project_id uuid,
    sequence_no integer NOT NULL,
    stable_key character varying(80) NOT NULL,
    start_ms bigint NOT NULL,
    end_ms bigint NOT NULL,
    duration_seconds integer NOT NULL,
    title character varying(160),
    thumbnail_asset_id uuid,
    prompt_content text,
    image_prompt text,
    dialogue jsonb DEFAULT '[]'::jsonb NOT NULL,
    asset_refs jsonb DEFAULT '[]'::jsonb NOT NULL,
    locked boolean DEFAULT false NOT NULL,
    active_output_id uuid,
    status character varying(32) DEFAULT 'idle'::character varying NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    script_content text,
    source_excerpt text,
    source_parse_task_id uuid,
    user_edited boolean DEFAULT false NOT NULL,
    CONSTRAINT episode_storyboards_check CHECK ((end_ms > start_ms)),
    CONSTRAINT episode_storyboards_parent_check CHECK (((episode_id IS NOT NULL)::integer + (project_id IS NOT NULL)::integer = 1)),
    CONSTRAINT episode_storyboards_duration_seconds_check CHECK (((duration_seconds >= 5) AND (duration_seconds <= 15))),
    CONSTRAINT episode_storyboards_sequence_no_check CHECK ((sequence_no > 0)),
    CONSTRAINT episode_storyboards_start_ms_check CHECK ((start_ms >= 0)),
    CONSTRAINT episode_storyboards_status_check CHECK (((status)::text = ANY ((ARRAY['idle'::character varying, 'queued'::character varying, 'generating'::character varying, 'completed'::character varying, 'failed'::character varying])::text[])))
);


--
-- Name: generation_outputs; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.generation_outputs (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    task_id uuid NOT NULL,
    media_asset_id uuid NOT NULL,
    output_type character varying(16) NOT NULL,
    sequence_no integer DEFAULT 1 NOT NULL,
    metadata jsonb DEFAULT '{}'::jsonb NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT generation_outputs_output_type_check CHECK (((output_type)::text = ANY ((ARRAY['image'::character varying, 'video'::character varying, 'subtitle'::character varying, 'text'::character varying])::text[])))
);


--
-- Name: generation_tasks; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.generation_tasks (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    request_id character varying(100) NOT NULL,
    user_id uuid NOT NULL,
    channel_id uuid,
    model_id uuid,
    project_id uuid,
    episode_id uuid,
    storyboard_id uuid,
    script_analysis_id uuid,
    task_type character varying(32) NOT NULL,
    status character varying(32) DEFAULT 'pending_submission'::character varying NOT NULL,
    upstream_task_id character varying(200),
    input_data jsonb DEFAULT '{}'::jsonb NOT NULL,
    prompt_snapshot text,
    billing_snapshot jsonb DEFAULT '{}'::jsonb NOT NULL,
    input_tokens bigint,
    output_tokens bigint,
    total_tokens bigint,
    token_count_source character varying(16),
    usage_raw jsonb,
    estimated_points numeric(20,2) DEFAULT 0 NOT NULL,
    actual_points numeric(20,2),
    prepaid_points numeric(20,2) DEFAULT 0 NOT NULL,
    cost_refunded boolean DEFAULT false NOT NULL,
    slot_reserved boolean DEFAULT false NOT NULL,
    slot_reserved_at timestamp with time zone,
    slot_released_at timestamp with time zone,
    submit_attempts integer DEFAULT 0 NOT NULL,
    poll_attempts integer DEFAULT 0 NOT NULL,
    download_attempts integer DEFAULT 0 NOT NULL,
    next_submit_at timestamp with time zone,
    next_poll_at timestamp with time zone,
    lease_owner character varying(120),
    lease_until timestamp with time zone,
    upstream_result_url text,
    error_code character varying(100),
    error_message text,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    submitted_at timestamp with time zone,
    finished_at timestamp with time zone,
    result_data jsonb DEFAULT '{}'::jsonb NOT NULL,
    canvas_project_id uuid,
    CONSTRAINT generation_tasks_actual_points_check CHECK ((actual_points >= (0)::numeric)),
    CONSTRAINT generation_tasks_estimated_points_check CHECK ((estimated_points >= (0)::numeric)),
    CONSTRAINT generation_tasks_prepaid_points_check CHECK ((prepaid_points >= (0)::numeric)),
    CONSTRAINT generation_tasks_token_count_source_check CHECK (((token_count_source)::text = ANY ((ARRAY['upstream'::character varying, 'local'::character varying, 'mixed'::character varying])::text[]))),
    CONSTRAINT generation_tasks_status_check CHECK (((status)::text = ANY ((ARRAY['pending_submission'::character varying, 'submitting'::character varying, 'submitted'::character varying, 'processing'::character varying, 'result_ready'::character varying, 'downloading'::character varying, 'succeeded'::character varying, 'failed'::character varying, 'cancel_requested'::character varying, 'cancelled'::character varying])::text[]))),
    CONSTRAINT generation_tasks_task_type_check CHECK (((task_type)::text = ANY ((ARRAY['prompt_reverse'::character varying, 'image_generation'::character varying, 'video_generation'::character varying, 'script_analysis'::character varying])::text[])))
);


--
-- Name: media_assets; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.media_assets (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    owner_user_id uuid,
    storage_provider character varying(16) DEFAULT 'cos'::character varying NOT NULL,
    object_key text NOT NULL,
    public_url text NOT NULL,
    original_name text,
    display_name text,
    mime_type character varying(120) NOT NULL,
    size_bytes bigint NOT NULL,
    sha256 character(64),
    width integer,
    height integer,
    duration_ms bigint,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    CONSTRAINT media_assets_size_bytes_check CHECK ((size_bytes >= 0)),
    CONSTRAINT media_assets_storage_provider_check CHECK (((storage_provider)::text = 'cos'::text))
);


--
-- Name: model_prices; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.model_prices (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    model_id uuid NOT NULL,
    price_key character varying(20) NOT NULL,
    unit character varying(20) NOT NULL,
    price numeric(18,4) NOT NULL,
    CONSTRAINT model_prices_price_check CHECK ((price >= (0)::numeric))
);


--
-- Name: models; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.models (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    channel_id uuid NOT NULL,
    name public.citext NOT NULL,
    model_type character varying(16) NOT NULL,
    multimodal boolean,
    text_billing_mode character varying(16),
    enabled boolean DEFAULT true NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    CONSTRAINT models_model_type_check CHECK (((model_type)::text = ANY ((ARRAY['text'::character varying, 'image'::character varying, 'video'::character varying])::text[]))),
    CONSTRAINT models_text_billing_mode_check CHECK (((((model_type)::text = 'text'::text) AND ((text_billing_mode)::text = ANY ((ARRAY['per_request'::character varying, 'per_token'::character varying])::text[]))) OR (((model_type)::text <> 'text'::text) AND (text_billing_mode IS NULL))))
);


--
-- Name: payment_configs; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.payment_configs (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    name public.citext NOT NULL,
    payment_type character varying(32) NOT NULL,
    provider_code character varying(64) NOT NULL,
    merchant_no text,
    app_id text,
    gateway_url text,
    callback_url text,
    secret_ciphertext text,
    encryption_key_version character varying(32),
    enabled boolean DEFAULT true NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    CONSTRAINT payment_configs_payment_type_check CHECK (((payment_type)::text = ANY ((ARRAY['wechat'::character varying, 'alipay'::character varying, 'aggregate'::character varying])::text[])))
);


--
-- Name: point_exchange_rate_settings; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.point_exchange_rate_settings (
    id smallint DEFAULT 1 NOT NULL,
    points_per_cny numeric(12,4) NOT NULL,
    updated_by uuid,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT point_exchange_rate_settings_id_check CHECK ((id = 1)),
    CONSTRAINT point_exchange_rate_settings_points_per_cny_check CHECK (((points_per_cny > (0)::numeric) AND (points_per_cny <= (1000000)::numeric)))
);


--
-- Name: point_ledger; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.point_ledger (
    id bigint NOT NULL,
    user_id uuid NOT NULL,
    change_amount numeric(18,2) NOT NULL,
    balance_after numeric(18,2) NOT NULL,
    business_type character varying(32) NOT NULL,
    business_id text,
    remark text,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    idempotency_key character varying(160)
);


--
-- Name: point_ledger_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--

CREATE SEQUENCE public.point_ledger_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


--
-- Name: point_ledger_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--

ALTER SEQUENCE public.point_ledger_id_seq OWNED BY public.point_ledger.id;


--
-- Name: point_packages; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.point_packages (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    original_amount numeric(12,2) NOT NULL,
    points numeric(18,2) NOT NULL,
    discount_rate numeric(4,2) DEFAULT 1 NOT NULL,
    discount_starts_at timestamp with time zone,
    discount_ends_at timestamp with time zone,
    enabled boolean DEFAULT true NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    CONSTRAINT point_packages_check CHECK (((discount_starts_at IS NULL) OR (discount_ends_at IS NULL) OR (discount_ends_at > discount_starts_at))),
    CONSTRAINT point_packages_discount_rate_check CHECK (((discount_rate >= 0.01) AND (discount_rate <= (1)::numeric))),
    CONSTRAINT point_packages_original_amount_check CHECK ((original_amount > (0)::numeric)),
    CONSTRAINT point_packages_points_check CHECK ((points > (0)::numeric))
);


--
-- Name: project_assets; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.project_assets (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    project_id uuid NOT NULL,
    source_episode_id uuid,
    asset_type character varying(20) NOT NULL,
    name character varying(200) NOT NULL,
    description text,
    image_prompt text,
    appearances jsonb DEFAULT '[]'::jsonb NOT NULL,
    image_asset_id uuid,
    audio_asset_id uuid,
    user_edited boolean DEFAULT false NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    aliases jsonb DEFAULT '[]'::jsonb NOT NULL,
    attributes jsonb DEFAULT '{}'::jsonb NOT NULL,
    ai_description text,
    source_parse_task_id uuid,
    CONSTRAINT project_assets_asset_type_check CHECK (((asset_type)::text = ANY ((ARRAY['character'::character varying, 'scene'::character varying, 'prop'::character varying, 'custom'::character varying])::text[])))
);


--
-- Name: project_episodes; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.project_episodes (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    project_id uuid NOT NULL,
    episode_no integer NOT NULL,
    name character varying(160) NOT NULL,
    cover_asset_id uuid,
    source_video_asset_id uuid,
    subtitle_asset_id uuid,
    audio_source character varying(24) DEFAULT 'video_audio'::character varying NOT NULL,
    source_language character varying(16),
    status character varying(32) DEFAULT 'draft'::character varying NOT NULL,
    analysis_message text,
    redraw_script text,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    CONSTRAINT project_episodes_audio_source_check CHECK (((audio_source)::text = ANY ((ARRAY['video_audio'::character varying, 'subtitle_file'::character varying])::text[]))),
    CONSTRAINT project_episodes_episode_no_check CHECK ((episode_no > 0)),
    CONSTRAINT project_episodes_status_check CHECK (((status)::text = ANY ((ARRAY['draft'::character varying, 'uploaded'::character varying, 'analyzing'::character varying, 'review'::character varying, 'generating'::character varying, 'failed'::character varying])::text[])))
);


--
-- Name: project_model_configs; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.project_model_configs (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    project_id uuid NOT NULL,
    purpose character varying(32) NOT NULL,
    model_id uuid NOT NULL,
    prompt_id uuid,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    settings jsonb DEFAULT '{}'::jsonb NOT NULL,
    model_type character varying(16) NOT NULL,
    CONSTRAINT project_model_configs_model_type_check CHECK (((model_type)::text = ANY ((ARRAY['text'::character varying, 'image'::character varying, 'video'::character varying])::text[]))),
    CONSTRAINT project_model_configs_purpose_check CHECK (((purpose)::text = ANY ((ARRAY['prompt_reverse'::character varying, 'image_generation'::character varying, 'video_generation'::character varying])::text[])))
);


--
-- Name: project_styles; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.project_styles (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    name public.citext NOT NULL,
    image_key text NOT NULL,
    image_url text,
    image_mime character varying(100),
    image_size bigint,
    image_width integer,
    image_height integer,
    deleted_at timestamp with time zone,
    sort_order integer DEFAULT 0 NOT NULL
);

--
-- Name: inspiration_gallery_items; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.inspiration_gallery_items (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    media_type character varying(16) NOT NULL,
    media_key text NOT NULL,
    media_url text NOT NULL,
    cover_key text NOT NULL,
    cover_url text NOT NULL,
    media_mime character varying(100) NOT NULL,
    media_size bigint NOT NULL,
    media_width integer NOT NULL,
    media_height integer NOT NULL,
    prompt text NOT NULL,
    status character varying(16) DEFAULT 'draft'::character varying NOT NULL,
    sort_order integer DEFAULT 0 NOT NULL,
    published_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    CONSTRAINT inspiration_gallery_items_media_height_check CHECK ((media_height > 0)),
    CONSTRAINT inspiration_gallery_items_media_size_check CHECK ((media_size > 0)),
    CONSTRAINT inspiration_gallery_items_media_type_check CHECK (((media_type)::text = ANY ((ARRAY['image'::character varying, 'video'::character varying])::text[]))),
    CONSTRAINT inspiration_gallery_items_media_width_check CHECK ((media_width > 0)),
    CONSTRAINT inspiration_gallery_items_prompt_check CHECK ((length(TRIM(BOTH FROM prompt)) > 0)),
    CONSTRAINT inspiration_gallery_items_status_check CHECK (((status)::text = ANY ((ARRAY['draft'::character varying, 'published'::character varying])::text[])))
);

ALTER TABLE ONLY public.inspiration_gallery_items
    ADD CONSTRAINT inspiration_gallery_items_pkey PRIMARY KEY (id);

CREATE INDEX idx_inspiration_gallery_public ON public.inspiration_gallery_items USING btree (status, sort_order, published_at DESC) WHERE (deleted_at IS NULL);

CREATE TRIGGER inspiration_gallery_items_updated_at BEFORE UPDATE ON public.inspiration_gallery_items FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();

--
-- Name: inspiration_gallery_references; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.inspiration_gallery_references (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    inspiration_id uuid NOT NULL,
    image_key text NOT NULL,
    image_url text NOT NULL,
    image_mime character varying(100) NOT NULL,
    image_size bigint NOT NULL,
    image_width integer NOT NULL,
    image_height integer NOT NULL,
    sort_order integer NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT inspiration_gallery_references_image_mime_check CHECK (((image_mime)::text ~~ 'image/%'::text)),
    CONSTRAINT inspiration_gallery_references_image_size_check CHECK (((image_size > 0) AND (image_size <= 3145728))),
    CONSTRAINT inspiration_gallery_references_image_width_check CHECK ((image_width > 0)),
    CONSTRAINT inspiration_gallery_references_image_height_check CHECK ((image_height > 0)),
    CONSTRAINT inspiration_gallery_references_sort_order_check CHECK (((sort_order >= 0) AND (sort_order < 3)))
);

ALTER TABLE ONLY public.inspiration_gallery_references
    ADD CONSTRAINT inspiration_gallery_references_pkey PRIMARY KEY (id);

ALTER TABLE ONLY public.inspiration_gallery_references
    ADD CONSTRAINT inspiration_gallery_references_item_sort_key UNIQUE (inspiration_id, sort_order);

ALTER TABLE ONLY public.inspiration_gallery_references
    ADD CONSTRAINT inspiration_gallery_references_item_fkey FOREIGN KEY (inspiration_id) REFERENCES public.inspiration_gallery_items(id) ON DELETE CASCADE;

CREATE INDEX idx_inspiration_gallery_references_item ON public.inspiration_gallery_references USING btree (inspiration_id, sort_order);

CREATE TRIGGER inspiration_gallery_references_updated_at BEFORE UPDATE ON public.inspiration_gallery_references FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: prompts; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.prompts (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    name public.citext NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    type character varying(50) NOT NULL,
    content text NOT NULL,
    scope character varying(20) DEFAULT 'system'::character varying NOT NULL,
    owner_user_id uuid,
    CONSTRAINT prompts_scope_owner_check CHECK (((((scope)::text = 'system'::text) AND (owner_user_id IS NULL)) OR (((scope)::text = 'user'::text) AND (owner_user_id IS NOT NULL))))
);

--
-- Name: recharge_orders; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.recharge_orders (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    order_no character varying(40) NOT NULL,
    user_id uuid NOT NULL,
    user_uid character(8) NOT NULL,
    package_id uuid,
    payment_config_id uuid,
    recharge_amount numeric(12,2) NOT NULL,
    received_points numeric(18,2) NOT NULL,
    status character varying(20) NOT NULL,
    third_party_trade_no text,
    original_amount_snapshot numeric(12,2),
    discount_rate_snapshot numeric(4,2),
    actual_amount_snapshot numeric(12,2),
    points_snapshot numeric(18,2),
    paid_at timestamp with time zone,
    remark text,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT recharge_orders_received_points_check CHECK ((received_points >= (0)::numeric)),
    CONSTRAINT recharge_orders_recharge_amount_check CHECK ((recharge_amount >= (0)::numeric)),
    CONSTRAINT recharge_orders_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'paid'::character varying, 'closed'::character varying, 'failed'::character varying, 'refunded'::character varying])::text[])))
);


--
-- Name: redemption_batches; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.redemption_batches (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    name public.citext NOT NULL,
    points numeric(18,2) NOT NULL,
    quantity integer NOT NULL,
    expires_at timestamp with time zone,
    created_by uuid NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT redemption_batches_points_check CHECK (((points >= (1)::numeric) AND (points <= (100)::numeric))),
    CONSTRAINT redemption_batches_quantity_check CHECK (((quantity >= 1) AND (quantity <= 10)))
);


--
-- Name: redemption_codes; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.redemption_codes (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    batch_id uuid NOT NULL,
    code_hash character(64) NOT NULL,
    code_mask character varying(32) NOT NULL,
    code character varying(40),
    points numeric(18,2) NOT NULL,
    status character varying(16) DEFAULT 'unused'::character varying NOT NULL,
    redeemed_by uuid,
    redeemed_at timestamp with time zone,
    expires_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT redemption_codes_points_check CHECK (((points >= (1)::numeric) AND (points <= (100)::numeric))),
    CONSTRAINT redemption_codes_status_check CHECK (((status)::text = ANY ((ARRAY['unused'::character varying, 'used'::character varying, 'expired'::character varying])::text[])))
);


--
-- Name: user_model_configs; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.user_model_configs (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    user_id uuid NOT NULL,
    purpose character varying(32) NOT NULL,
    model_id uuid NOT NULL,
    prompt_id uuid,
    settings jsonb DEFAULT '{}'::jsonb NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    project_type character varying(24) DEFAULT 'video_redraw'::character varying NOT NULL,
    model_type character varying(16) NOT NULL,
    CONSTRAINT user_model_configs_model_type_check CHECK (((model_type)::text = ANY ((ARRAY['text'::character varying, 'image'::character varying, 'video'::character varying])::text[]))),
    CONSTRAINT user_model_configs_project_type_check CHECK (((project_type)::text = ANY ((ARRAY['premium_drama'::character varying, 'video_redraw'::character varying, 'script_analysis'::character varying])::text[]))),
    CONSTRAINT user_model_configs_purpose_check CHECK (((purpose)::text = ANY ((ARRAY['prompt_reverse'::character varying, 'image_generation'::character varying, 'video_generation'::character varying])::text[])))
);


--
-- Name: user_prompt_preferences; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.user_prompt_preferences (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    user_id uuid NOT NULL,
    prompt_id uuid NOT NULL,
    prompt_type character varying(64) NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);


--
-- Name: web_refresh_tokens; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.web_refresh_tokens (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    user_id uuid NOT NULL,
    token_hash character(64) NOT NULL,
    session_version bigint NOT NULL,
    expires_at timestamp with time zone NOT NULL,
    revoked_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);


--
-- Name: web_users; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.web_users (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    uid character(8) NOT NULL,
    username public.citext NOT NULL,
    password_hash text NOT NULL,
    point_balance numeric(18,2) DEFAULT 0 NOT NULL,
    daily_limit numeric(18,2) DEFAULT 9999 NOT NULL,
    enabled boolean DEFAULT true NOT NULL,
    session_version bigint DEFAULT 1 NOT NULL,
    last_online_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    account public.citext NOT NULL,
    avatar_url text,
    avatar_key text,
    CONSTRAINT web_users_daily_limit_check CHECK ((daily_limit >= (0)::numeric)),
    CONSTRAINT web_users_point_balance_check CHECK ((point_balance >= (0)::numeric)),
    CONSTRAINT web_users_uid_check CHECK ((uid ~ '^[1-9][0-9]{7}$'::text))
);


--
-- Name: admin_audit_logs id; Type: DEFAULT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.admin_audit_logs ALTER COLUMN id SET DEFAULT nextval('public.admin_audit_logs_id_seq'::regclass);


--
-- Name: channel_balance_snapshots id; Type: DEFAULT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.channel_balance_snapshots ALTER COLUMN id SET DEFAULT nextval('public.channel_balance_snapshots_id_seq'::regclass);


--
-- Name: point_ledger id; Type: DEFAULT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.point_ledger ALTER COLUMN id SET DEFAULT nextval('public.point_ledger_id_seq'::regclass);


--
-- Name: admin_audit_logs admin_audit_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.admin_audit_logs
    ADD CONSTRAINT admin_audit_logs_pkey PRIMARY KEY (id);


--
-- Name: admin_refresh_tokens admin_refresh_tokens_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.admin_refresh_tokens
    ADD CONSTRAINT admin_refresh_tokens_pkey PRIMARY KEY (id);


--
-- Name: admin_refresh_tokens admin_refresh_tokens_token_hash_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.admin_refresh_tokens
    ADD CONSTRAINT admin_refresh_tokens_token_hash_key UNIQUE (token_hash);


--
-- Name: admin_users admin_users_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.admin_users
    ADD CONSTRAINT admin_users_pkey PRIMARY KEY (id);


--
-- Name: admin_users admin_users_username_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.admin_users
    ADD CONSTRAINT admin_users_username_key UNIQUE (username);


--
-- Name: announcements announcements_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.announcements
    ADD CONSTRAINT announcements_pkey PRIMARY KEY (id);


--
-- Name: canvas_projects canvas_projects_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.canvas_projects
    ADD CONSTRAINT canvas_projects_pkey PRIMARY KEY (id);


--
-- Name: channel_asset_cache channel_asset_cache_channel_id_media_asset_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.channel_asset_cache
    ADD CONSTRAINT channel_asset_cache_channel_id_media_asset_id_key UNIQUE (channel_id, media_asset_id);


--
-- Name: channel_asset_cache channel_asset_cache_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.channel_asset_cache
    ADD CONSTRAINT channel_asset_cache_pkey PRIMARY KEY (id);


--
-- Name: channel_balance_snapshots channel_balance_snapshots_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.channel_balance_snapshots
    ADD CONSTRAINT channel_balance_snapshots_pkey PRIMARY KEY (id);


--
-- Name: channels channels_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.channels
    ADD CONSTRAINT channels_name_key UNIQUE (name);


--
-- Name: channels channels_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.channels
    ADD CONSTRAINT channels_pkey PRIMARY KEY (id);


--
-- Name: creative_projects creative_projects_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.creative_projects
    ADD CONSTRAINT creative_projects_pkey PRIMARY KEY (id);


--
-- Name: drama_import_sessions drama_import_sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_import_sessions
    ADD CONSTRAINT drama_import_sessions_pkey PRIMARY KEY (id);


--
-- Name: drama_parse_batches drama_parse_batches_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_batches
    ADD CONSTRAINT drama_parse_batches_pkey PRIMARY KEY (id);


--
-- Name: drama_parse_tasks drama_parse_tasks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_tasks
    ADD CONSTRAINT drama_parse_tasks_pkey PRIMARY KEY (id);


--
-- Name: drama_parse_tasks drama_parse_tasks_request_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_tasks
    ADD CONSTRAINT drama_parse_tasks_request_id_key UNIQUE (request_id);


--
-- Name: episode_continuity_contexts episode_continuity_contexts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_continuity_contexts
    ADD CONSTRAINT episode_continuity_contexts_pkey PRIMARY KEY (episode_id);


--
-- Name: episode_sources episode_sources_episode_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_sources
    ADD CONSTRAINT episode_sources_episode_id_key UNIQUE (episode_id);


--
-- Name: episode_sources episode_sources_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_sources
    ADD CONSTRAINT episode_sources_pkey PRIMARY KEY (id);


--
-- Name: episode_storyboards episode_storyboards_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_storyboards
    ADD CONSTRAINT episode_storyboards_pkey PRIMARY KEY (id);


--
-- Name: generation_outputs generation_outputs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_outputs
    ADD CONSTRAINT generation_outputs_pkey PRIMARY KEY (id);


--
-- Name: generation_outputs generation_outputs_task_id_sequence_no_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_outputs
    ADD CONSTRAINT generation_outputs_task_id_sequence_no_key UNIQUE (task_id, sequence_no);


--
-- Name: generation_tasks generation_tasks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_tasks
    ADD CONSTRAINT generation_tasks_pkey PRIMARY KEY (id);


--
-- Name: generation_tasks generation_tasks_request_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_tasks
    ADD CONSTRAINT generation_tasks_request_id_key UNIQUE (request_id);


--
-- Name: media_assets media_assets_object_key_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.media_assets
    ADD CONSTRAINT media_assets_object_key_key UNIQUE (object_key);


--
-- Name: media_assets media_assets_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.media_assets
    ADD CONSTRAINT media_assets_pkey PRIMARY KEY (id);


--
-- Name: model_prices model_prices_model_id_price_key_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.model_prices
    ADD CONSTRAINT model_prices_model_id_price_key_key UNIQUE (model_id, price_key);


--
-- Name: model_prices model_prices_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.model_prices
    ADD CONSTRAINT model_prices_pkey PRIMARY KEY (id);


--
-- Name: models models_channel_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.models
    ADD CONSTRAINT models_channel_id_name_key UNIQUE (channel_id, name);


--
-- Name: models models_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.models
    ADD CONSTRAINT models_pkey PRIMARY KEY (id);


--
-- Name: payment_configs payment_configs_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.payment_configs
    ADD CONSTRAINT payment_configs_name_key UNIQUE (name);


--
-- Name: payment_configs payment_configs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.payment_configs
    ADD CONSTRAINT payment_configs_pkey PRIMARY KEY (id);


--
-- Name: point_exchange_rate_settings point_exchange_rate_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.point_exchange_rate_settings
    ADD CONSTRAINT point_exchange_rate_settings_pkey PRIMARY KEY (id);


--
-- Name: point_ledger point_ledger_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.point_ledger
    ADD CONSTRAINT point_ledger_pkey PRIMARY KEY (id);


--
-- Name: point_packages point_packages_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.point_packages
    ADD CONSTRAINT point_packages_pkey PRIMARY KEY (id);


--
-- Name: project_assets project_assets_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_assets
    ADD CONSTRAINT project_assets_pkey PRIMARY KEY (id);


--
-- Name: project_episodes project_episodes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_episodes
    ADD CONSTRAINT project_episodes_pkey PRIMARY KEY (id);


--
-- Name: project_model_configs project_model_configs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_model_configs
    ADD CONSTRAINT project_model_configs_pkey PRIMARY KEY (id);


--
-- Name: project_model_configs project_model_configs_project_id_purpose_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_model_configs
    ADD CONSTRAINT project_model_configs_project_id_purpose_key UNIQUE (project_id, purpose);


--
-- Name: project_styles project_styles_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_styles
    ADD CONSTRAINT project_styles_name_key UNIQUE (name);


--
-- Name: project_styles project_styles_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_styles
    ADD CONSTRAINT project_styles_pkey PRIMARY KEY (id);


--
-- Name: prompts prompts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.prompts
    ADD CONSTRAINT prompts_pkey PRIMARY KEY (id);


--
-- Name: recharge_orders recharge_orders_order_no_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.recharge_orders
    ADD CONSTRAINT recharge_orders_order_no_key UNIQUE (order_no);


--
-- Name: recharge_orders recharge_orders_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.recharge_orders
    ADD CONSTRAINT recharge_orders_pkey PRIMARY KEY (id);


--
-- Name: redemption_batches redemption_batches_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.redemption_batches
    ADD CONSTRAINT redemption_batches_name_key UNIQUE (name);


--
-- Name: redemption_batches redemption_batches_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.redemption_batches
    ADD CONSTRAINT redemption_batches_pkey PRIMARY KEY (id);


--
-- Name: redemption_codes redemption_codes_code_hash_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.redemption_codes
    ADD CONSTRAINT redemption_codes_code_hash_key UNIQUE (code_hash);


--
-- Name: redemption_codes redemption_codes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.redemption_codes
    ADD CONSTRAINT redemption_codes_pkey PRIMARY KEY (id);


--
-- Name: user_model_configs user_model_configs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.user_model_configs
    ADD CONSTRAINT user_model_configs_pkey PRIMARY KEY (id);


--
-- Name: user_prompt_preferences user_prompt_preferences_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.user_prompt_preferences
    ADD CONSTRAINT user_prompt_preferences_pkey PRIMARY KEY (id);


--
-- Name: user_prompt_preferences user_prompt_preferences_user_id_prompt_type_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.user_prompt_preferences
    ADD CONSTRAINT user_prompt_preferences_user_id_prompt_type_key UNIQUE (user_id, prompt_type);


--
-- Name: web_refresh_tokens web_refresh_tokens_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.web_refresh_tokens
    ADD CONSTRAINT web_refresh_tokens_pkey PRIMARY KEY (id);


--
-- Name: web_refresh_tokens web_refresh_tokens_token_hash_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.web_refresh_tokens
    ADD CONSTRAINT web_refresh_tokens_token_hash_key UNIQUE (token_hash);


--
-- Name: web_users web_users_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.web_users
    ADD CONSTRAINT web_users_pkey PRIMARY KEY (id);


--
-- Name: web_users web_users_uid_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.web_users
    ADD CONSTRAINT web_users_uid_key UNIQUE (uid);


--
-- Name: web_users web_users_username_key; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.web_users
    ADD CONSTRAINT web_users_username_key UNIQUE (username);


--
-- Name: idx_admin_audit_logs_created_at; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_admin_audit_logs_created_at ON public.admin_audit_logs USING btree (created_at DESC);


--
-- Name: idx_canvas_projects_user_updated; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_canvas_projects_user_updated ON public.canvas_projects USING btree (user_id, updated_at DESC) WHERE (deleted_at IS NULL);


--
-- Name: idx_channel_balance_latest; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_channel_balance_latest ON public.channel_balance_snapshots USING btree (channel_id, synced_at DESC);


--
-- Name: idx_creative_projects_user_updated; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_creative_projects_user_updated ON public.creative_projects USING btree (user_id, updated_at DESC) WHERE (deleted_at IS NULL);


--
-- Name: idx_drama_import_sessions_expiry; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_drama_import_sessions_expiry ON public.drama_import_sessions USING btree (expires_at) WHERE (consumed_at IS NULL);


--
-- Name: idx_drama_parse_tasks_recovery; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_drama_parse_tasks_recovery ON public.drama_parse_tasks USING btree (status, lease_until) WHERE ((status)::text = ANY ((ARRAY['queued'::character varying, 'running'::character varying, 'retry_wait'::character varying])::text[]));


--
-- Name: idx_drama_parse_tasks_user_time; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_drama_parse_tasks_user_time ON public.drama_parse_tasks USING btree (user_id, created_at DESC);


--
-- Name: idx_generation_tasks_active_capacity; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_generation_tasks_active_capacity ON public.generation_tasks USING btree (channel_id, user_id) WHERE (slot_reserved AND (slot_released_at IS NULL));


--
-- Name: idx_generation_tasks_canvas_history; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_generation_tasks_canvas_history ON public.generation_tasks USING btree (user_id, canvas_project_id, task_type, created_at DESC) WHERE (canvas_project_id IS NOT NULL);


--
-- Name: idx_generation_tasks_dispatch; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_generation_tasks_dispatch ON public.generation_tasks USING btree (channel_id, status, next_submit_at, created_at) WHERE ((status)::text = 'pending_submission'::text);


--
-- Name: idx_generation_tasks_episode_time; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_generation_tasks_episode_time ON public.generation_tasks USING btree (episode_id, created_at DESC) WHERE (episode_id IS NOT NULL);


--
-- Name: idx_generation_tasks_poll; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_generation_tasks_poll ON public.generation_tasks USING btree (status, next_poll_at) WHERE ((status)::text = ANY ((ARRAY['submitted'::character varying, 'processing'::character varying, 'cancel_requested'::character varying])::text[]));


--
-- Name: idx_generation_tasks_user_time; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_generation_tasks_user_time ON public.generation_tasks USING btree (user_id, created_at DESC);


--
-- Name: idx_media_assets_owner_time; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_media_assets_owner_time ON public.media_assets USING btree (owner_user_id, created_at DESC);


--
-- Name: idx_point_ledger_user_time; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_point_ledger_user_time ON public.point_ledger USING btree (user_id, created_at DESC);


--
-- Name: idx_project_assets_project_type; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_project_assets_project_type ON public.project_assets USING btree (project_id, asset_type) WHERE (deleted_at IS NULL);


--
-- Name: idx_project_episodes_project_updated; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_project_episodes_project_updated ON public.project_episodes USING btree (project_id, updated_at DESC) WHERE (deleted_at IS NULL);


--
-- Name: idx_prompts_owner; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_prompts_owner ON public.prompts USING btree (owner_user_id) WHERE (owner_user_id IS NOT NULL);


--
-- Name: idx_prompts_type_scope; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_prompts_type_scope ON public.prompts USING btree (type, scope);


--
-- Name: idx_recharge_orders_created_at; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_recharge_orders_created_at ON public.recharge_orders USING btree (created_at DESC);


--
-- Name: idx_user_model_configs_user; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_user_model_configs_user ON public.user_model_configs USING btree (user_id);


--
-- Name: idx_user_prompt_preferences_user; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_user_prompt_preferences_user ON public.user_prompt_preferences USING btree (user_id);


--
-- Name: idx_web_refresh_tokens_user_active; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_web_refresh_tokens_user_active ON public.web_refresh_tokens USING btree (user_id, expires_at) WHERE (revoked_at IS NULL);


--
-- Name: idx_web_users_account; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX idx_web_users_account ON public.web_users USING btree (account);


--
-- Name: idx_web_users_active; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX idx_web_users_active ON public.web_users USING btree (created_at DESC) WHERE (deleted_at IS NULL);


--
-- Name: uq_canvas_projects_user_name; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX uq_canvas_projects_user_name ON public.canvas_projects USING btree (user_id, lower((name)::text)) WHERE (deleted_at IS NULL);


--
-- Name: uq_creative_projects_user_type_name; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX uq_creative_projects_user_type_name ON public.creative_projects USING btree (user_id, project_type, lower((name)::text)) WHERE (deleted_at IS NULL);


--
-- Name: uq_drama_episode_active_parse; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX uq_drama_episode_active_parse ON public.drama_parse_tasks USING btree (episode_id) WHERE ((status)::text = ANY ((ARRAY['queued'::character varying, 'running'::character varying, 'retry_wait'::character varying, 'cancel_requested'::character varying])::text[]));


--
-- Name: uq_episode_storyboards_sequence; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX uq_episode_storyboards_sequence ON public.episode_storyboards USING btree (episode_id, sequence_no) WHERE (deleted_at IS NULL);


--
-- Name: uq_episode_storyboards_stable_key; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX uq_episode_storyboards_stable_key ON public.episode_storyboards USING btree (episode_id, stable_key) WHERE (deleted_at IS NULL);

CREATE UNIQUE INDEX uq_episode_storyboards_project_sequence ON public.episode_storyboards USING btree (project_id, sequence_no) WHERE ((project_id IS NOT NULL) AND (deleted_at IS NULL));

CREATE UNIQUE INDEX uq_episode_storyboards_project_stable_key ON public.episode_storyboards USING btree (project_id, stable_key) WHERE ((project_id IS NOT NULL) AND (deleted_at IS NULL));

CREATE INDEX idx_episode_storyboards_project_updated ON public.episode_storyboards USING btree (project_id, updated_at DESC) WHERE ((project_id IS NOT NULL) AND (deleted_at IS NULL));


--
-- Name: uq_point_ledger_idempotency; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX uq_point_ledger_idempotency ON public.point_ledger USING btree (idempotency_key) WHERE (idempotency_key IS NOT NULL);


--
-- Name: uq_project_assets_name_type; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX uq_project_assets_name_type ON public.project_assets USING btree (project_id, asset_type, lower((name)::text)) WHERE (deleted_at IS NULL);


--
-- Name: uq_project_episodes_number; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX uq_project_episodes_number ON public.project_episodes USING btree (project_id, episode_no) WHERE (deleted_at IS NULL);


--
-- Name: uq_project_model_configs_type; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX uq_project_model_configs_type ON public.project_model_configs USING btree (project_id, model_type);


--
-- Name: uq_user_model_configs_project_type; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX uq_user_model_configs_project_type ON public.user_model_configs USING btree (user_id, project_type, model_type);


--
-- Name: admin_users trg_admin_users_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_admin_users_updated_at BEFORE UPDATE ON public.admin_users FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: announcements trg_announcements_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_announcements_updated_at BEFORE UPDATE ON public.announcements FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: canvas_projects trg_canvas_projects_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_canvas_projects_updated_at BEFORE UPDATE ON public.canvas_projects FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: channel_asset_cache trg_channel_asset_cache_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_channel_asset_cache_updated_at BEFORE UPDATE ON public.channel_asset_cache FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: channels trg_channels_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_channels_updated_at BEFORE UPDATE ON public.channels FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: creative_projects trg_creative_projects_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_creative_projects_updated_at BEFORE UPDATE ON public.creative_projects FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: episode_continuity_contexts trg_episode_continuity_contexts_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_episode_continuity_contexts_updated_at BEFORE UPDATE ON public.episode_continuity_contexts FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: episode_sources trg_episode_sources_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_episode_sources_updated_at BEFORE UPDATE ON public.episode_sources FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: episode_storyboards trg_episode_storyboards_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_episode_storyboards_updated_at BEFORE UPDATE ON public.episode_storyboards FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: models trg_models_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_models_updated_at BEFORE UPDATE ON public.models FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: payment_configs trg_payment_configs_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_payment_configs_updated_at BEFORE UPDATE ON public.payment_configs FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: point_packages trg_point_packages_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_point_packages_updated_at BEFORE UPDATE ON public.point_packages FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: project_assets trg_project_assets_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_project_assets_updated_at BEFORE UPDATE ON public.project_assets FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: project_episodes trg_project_episodes_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_project_episodes_updated_at BEFORE UPDATE ON public.project_episodes FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: project_model_configs trg_project_model_configs_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_project_model_configs_updated_at BEFORE UPDATE ON public.project_model_configs FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: prompts trg_prompts_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_prompts_updated_at BEFORE UPDATE ON public.prompts FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: recharge_orders trg_recharge_orders_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_recharge_orders_updated_at BEFORE UPDATE ON public.recharge_orders FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: web_users trg_web_users_updated_at; Type: TRIGGER; Schema: public; Owner: -
--

CREATE TRIGGER trg_web_users_updated_at BEFORE UPDATE ON public.web_users FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();


--
-- Name: admin_audit_logs admin_audit_logs_admin_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.admin_audit_logs
    ADD CONSTRAINT admin_audit_logs_admin_id_fkey FOREIGN KEY (admin_id) REFERENCES public.admin_users(id);


--
-- Name: admin_refresh_tokens admin_refresh_tokens_admin_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.admin_refresh_tokens
    ADD CONSTRAINT admin_refresh_tokens_admin_id_fkey FOREIGN KEY (admin_id) REFERENCES public.admin_users(id);


--
-- Name: announcements announcements_published_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.announcements
    ADD CONSTRAINT announcements_published_by_fkey FOREIGN KEY (published_by) REFERENCES public.admin_users(id);


--
-- Name: canvas_projects canvas_projects_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.canvas_projects
    ADD CONSTRAINT canvas_projects_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id) ON DELETE CASCADE;


--
-- Name: channel_asset_cache channel_asset_cache_channel_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.channel_asset_cache
    ADD CONSTRAINT channel_asset_cache_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES public.channels(id);


--
-- Name: channel_asset_cache channel_asset_cache_media_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.channel_asset_cache
    ADD CONSTRAINT channel_asset_cache_media_asset_id_fkey FOREIGN KEY (media_asset_id) REFERENCES public.media_assets(id);


--
-- Name: channel_balance_snapshots channel_balance_snapshots_channel_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.channel_balance_snapshots
    ADD CONSTRAINT channel_balance_snapshots_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES public.channels(id);


--
-- Name: creative_projects creative_projects_cover_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.creative_projects
    ADD CONSTRAINT creative_projects_cover_asset_id_fkey FOREIGN KEY (cover_asset_id) REFERENCES public.media_assets(id);


--
-- Name: creative_projects creative_projects_style_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.creative_projects
    ADD CONSTRAINT creative_projects_style_id_fkey FOREIGN KEY (style_id) REFERENCES public.project_styles(id);

ALTER TABLE ONLY public.creative_projects
    ADD CONSTRAINT creative_projects_source_video_asset_id_fkey FOREIGN KEY (source_video_asset_id) REFERENCES public.media_assets(id);

ALTER TABLE ONLY public.creative_projects
    ADD CONSTRAINT creative_projects_subtitle_asset_id_fkey FOREIGN KEY (subtitle_asset_id) REFERENCES public.media_assets(id);


--
-- Name: creative_projects creative_projects_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.creative_projects
    ADD CONSTRAINT creative_projects_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id);


--
-- Name: drama_import_sessions drama_import_sessions_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_import_sessions
    ADD CONSTRAINT drama_import_sessions_project_id_fkey FOREIGN KEY (project_id) REFERENCES public.creative_projects(id) ON DELETE CASCADE;


--
-- Name: drama_import_sessions drama_import_sessions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_import_sessions
    ADD CONSTRAINT drama_import_sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id);


--
-- Name: drama_parse_batches drama_parse_batches_current_episode_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_batches
    ADD CONSTRAINT drama_parse_batches_current_episode_id_fkey FOREIGN KEY (current_episode_id) REFERENCES public.project_episodes(id);


--
-- Name: drama_parse_batches drama_parse_batches_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_batches
    ADD CONSTRAINT drama_parse_batches_project_id_fkey FOREIGN KEY (project_id) REFERENCES public.creative_projects(id) ON DELETE CASCADE;


--
-- Name: drama_parse_batches drama_parse_batches_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_batches
    ADD CONSTRAINT drama_parse_batches_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id);


--
-- Name: drama_parse_tasks drama_parse_tasks_batch_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_tasks
    ADD CONSTRAINT drama_parse_tasks_batch_id_fkey FOREIGN KEY (batch_id) REFERENCES public.drama_parse_batches(id) ON DELETE SET NULL;


--
-- Name: drama_parse_tasks drama_parse_tasks_channel_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_tasks
    ADD CONSTRAINT drama_parse_tasks_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES public.channels(id);


--
-- Name: drama_parse_tasks drama_parse_tasks_episode_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_tasks
    ADD CONSTRAINT drama_parse_tasks_episode_id_fkey FOREIGN KEY (episode_id) REFERENCES public.project_episodes(id) ON DELETE CASCADE;


--
-- Name: drama_parse_tasks drama_parse_tasks_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_tasks
    ADD CONSTRAINT drama_parse_tasks_model_id_fkey FOREIGN KEY (model_id) REFERENCES public.models(id);


--
-- Name: drama_parse_tasks drama_parse_tasks_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_tasks
    ADD CONSTRAINT drama_parse_tasks_project_id_fkey FOREIGN KEY (project_id) REFERENCES public.creative_projects(id) ON DELETE CASCADE;


--
-- Name: drama_parse_tasks drama_parse_tasks_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.drama_parse_tasks
    ADD CONSTRAINT drama_parse_tasks_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id);


--
-- Name: episode_continuity_contexts episode_continuity_contexts_episode_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_continuity_contexts
    ADD CONSTRAINT episode_continuity_contexts_episode_id_fkey FOREIGN KEY (episode_id) REFERENCES public.project_episodes(id) ON DELETE CASCADE;


--
-- Name: episode_continuity_contexts episode_continuity_contexts_parse_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_continuity_contexts
    ADD CONSTRAINT episode_continuity_contexts_parse_task_id_fkey FOREIGN KEY (parse_task_id) REFERENCES public.drama_parse_tasks(id) ON DELETE CASCADE;


--
-- Name: episode_sources episode_sources_episode_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_sources
    ADD CONSTRAINT episode_sources_episode_id_fkey FOREIGN KEY (episode_id) REFERENCES public.project_episodes(id) ON DELETE CASCADE;


--
-- Name: episode_storyboards episode_storyboards_episode_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_storyboards
    ADD CONSTRAINT episode_storyboards_episode_id_fkey FOREIGN KEY (episode_id) REFERENCES public.project_episodes(id);

ALTER TABLE ONLY public.episode_storyboards
    ADD CONSTRAINT episode_storyboards_project_id_fkey FOREIGN KEY (project_id) REFERENCES public.creative_projects(id);


--
-- Name: episode_storyboards episode_storyboards_source_parse_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_storyboards
    ADD CONSTRAINT episode_storyboards_source_parse_task_id_fkey FOREIGN KEY (source_parse_task_id) REFERENCES public.drama_parse_tasks(id) ON DELETE SET NULL;


--
-- Name: episode_storyboards episode_storyboards_thumbnail_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_storyboards
    ADD CONSTRAINT episode_storyboards_thumbnail_asset_id_fkey FOREIGN KEY (thumbnail_asset_id) REFERENCES public.media_assets(id);


--
-- Name: episode_storyboards fk_storyboards_active_output; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.episode_storyboards
    ADD CONSTRAINT fk_storyboards_active_output FOREIGN KEY (active_output_id) REFERENCES public.generation_outputs(id);


--
-- Name: generation_outputs generation_outputs_media_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_outputs
    ADD CONSTRAINT generation_outputs_media_asset_id_fkey FOREIGN KEY (media_asset_id) REFERENCES public.media_assets(id);


--
-- Name: generation_outputs generation_outputs_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_outputs
    ADD CONSTRAINT generation_outputs_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.generation_tasks(id);


--
-- Name: generation_tasks generation_tasks_canvas_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_tasks
    ADD CONSTRAINT generation_tasks_canvas_project_id_fkey FOREIGN KEY (canvas_project_id) REFERENCES public.canvas_projects(id);


--
-- Name: generation_tasks generation_tasks_channel_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_tasks
    ADD CONSTRAINT generation_tasks_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES public.channels(id);


--
-- Name: generation_tasks generation_tasks_episode_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_tasks
    ADD CONSTRAINT generation_tasks_episode_id_fkey FOREIGN KEY (episode_id) REFERENCES public.project_episodes(id);


--
-- Name: generation_tasks generation_tasks_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_tasks
    ADD CONSTRAINT generation_tasks_model_id_fkey FOREIGN KEY (model_id) REFERENCES public.models(id);


--
-- Name: generation_tasks generation_tasks_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_tasks
    ADD CONSTRAINT generation_tasks_project_id_fkey FOREIGN KEY (project_id) REFERENCES public.creative_projects(id);


--
-- Name: generation_tasks generation_tasks_storyboard_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_tasks
    ADD CONSTRAINT generation_tasks_storyboard_id_fkey FOREIGN KEY (storyboard_id) REFERENCES public.episode_storyboards(id);


--
-- Name: generation_tasks generation_tasks_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.generation_tasks
    ADD CONSTRAINT generation_tasks_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id);


--
-- Name: media_assets media_assets_owner_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.media_assets
    ADD CONSTRAINT media_assets_owner_user_id_fkey FOREIGN KEY (owner_user_id) REFERENCES public.web_users(id);


--
-- Name: model_prices model_prices_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.model_prices
    ADD CONSTRAINT model_prices_model_id_fkey FOREIGN KEY (model_id) REFERENCES public.models(id) ON DELETE CASCADE;


--
-- Name: models models_channel_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.models
    ADD CONSTRAINT models_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES public.channels(id);


--
-- Name: point_exchange_rate_settings point_exchange_rate_settings_updated_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.point_exchange_rate_settings
    ADD CONSTRAINT point_exchange_rate_settings_updated_by_fkey FOREIGN KEY (updated_by) REFERENCES public.admin_users(id);


--
-- Name: point_ledger point_ledger_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.point_ledger
    ADD CONSTRAINT point_ledger_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id);


--
-- Name: project_assets project_assets_audio_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_assets
    ADD CONSTRAINT project_assets_audio_asset_id_fkey FOREIGN KEY (audio_asset_id) REFERENCES public.media_assets(id);


--
-- Name: project_assets project_assets_image_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_assets
    ADD CONSTRAINT project_assets_image_asset_id_fkey FOREIGN KEY (image_asset_id) REFERENCES public.media_assets(id);


--
-- Name: project_assets project_assets_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_assets
    ADD CONSTRAINT project_assets_project_id_fkey FOREIGN KEY (project_id) REFERENCES public.creative_projects(id);


--
-- Name: project_assets project_assets_source_episode_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_assets
    ADD CONSTRAINT project_assets_source_episode_id_fkey FOREIGN KEY (source_episode_id) REFERENCES public.project_episodes(id);


--
-- Name: project_assets project_assets_source_parse_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_assets
    ADD CONSTRAINT project_assets_source_parse_task_id_fkey FOREIGN KEY (source_parse_task_id) REFERENCES public.drama_parse_tasks(id) ON DELETE SET NULL;


--
-- Name: project_episodes project_episodes_cover_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_episodes
    ADD CONSTRAINT project_episodes_cover_asset_id_fkey FOREIGN KEY (cover_asset_id) REFERENCES public.media_assets(id);


--
-- Name: project_episodes project_episodes_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_episodes
    ADD CONSTRAINT project_episodes_project_id_fkey FOREIGN KEY (project_id) REFERENCES public.creative_projects(id);


--
-- Name: project_episodes project_episodes_source_video_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_episodes
    ADD CONSTRAINT project_episodes_source_video_asset_id_fkey FOREIGN KEY (source_video_asset_id) REFERENCES public.media_assets(id);


--
-- Name: project_episodes project_episodes_subtitle_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_episodes
    ADD CONSTRAINT project_episodes_subtitle_asset_id_fkey FOREIGN KEY (subtitle_asset_id) REFERENCES public.media_assets(id);


--
-- Name: project_model_configs project_model_configs_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_model_configs
    ADD CONSTRAINT project_model_configs_model_id_fkey FOREIGN KEY (model_id) REFERENCES public.models(id);


--
-- Name: project_model_configs project_model_configs_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_model_configs
    ADD CONSTRAINT project_model_configs_project_id_fkey FOREIGN KEY (project_id) REFERENCES public.creative_projects(id);


--
-- Name: project_model_configs project_model_configs_prompt_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.project_model_configs
    ADD CONSTRAINT project_model_configs_prompt_id_fkey FOREIGN KEY (prompt_id) REFERENCES public.prompts(id) ON DELETE SET NULL;


--
-- Name: prompts prompts_owner_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.prompts
    ADD CONSTRAINT prompts_owner_user_id_fkey FOREIGN KEY (owner_user_id) REFERENCES public.web_users(id);


--
-- Name: recharge_orders recharge_orders_package_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.recharge_orders
    ADD CONSTRAINT recharge_orders_package_id_fkey FOREIGN KEY (package_id) REFERENCES public.point_packages(id);


--
-- Name: recharge_orders recharge_orders_payment_config_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.recharge_orders
    ADD CONSTRAINT recharge_orders_payment_config_id_fkey FOREIGN KEY (payment_config_id) REFERENCES public.payment_configs(id);


--
-- Name: recharge_orders recharge_orders_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.recharge_orders
    ADD CONSTRAINT recharge_orders_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id);


--
-- Name: redemption_batches redemption_batches_created_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.redemption_batches
    ADD CONSTRAINT redemption_batches_created_by_fkey FOREIGN KEY (created_by) REFERENCES public.admin_users(id);


--
-- Name: redemption_codes redemption_codes_batch_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.redemption_codes
    ADD CONSTRAINT redemption_codes_batch_id_fkey FOREIGN KEY (batch_id) REFERENCES public.redemption_batches(id);


--
-- Name: redemption_codes redemption_codes_redeemed_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.redemption_codes
    ADD CONSTRAINT redemption_codes_redeemed_by_fkey FOREIGN KEY (redeemed_by) REFERENCES public.web_users(id);


--
-- Name: user_model_configs user_model_configs_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.user_model_configs
    ADD CONSTRAINT user_model_configs_model_id_fkey FOREIGN KEY (model_id) REFERENCES public.models(id);


--
-- Name: user_model_configs user_model_configs_prompt_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.user_model_configs
    ADD CONSTRAINT user_model_configs_prompt_id_fkey FOREIGN KEY (prompt_id) REFERENCES public.prompts(id);


--
-- Name: user_model_configs user_model_configs_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.user_model_configs
    ADD CONSTRAINT user_model_configs_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id);


--
-- Name: user_prompt_preferences user_prompt_preferences_prompt_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.user_prompt_preferences
    ADD CONSTRAINT user_prompt_preferences_prompt_id_fkey FOREIGN KEY (prompt_id) REFERENCES public.prompts(id) ON DELETE CASCADE;


--
-- Name: user_prompt_preferences user_prompt_preferences_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.user_prompt_preferences
    ADD CONSTRAINT user_prompt_preferences_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id) ON DELETE CASCADE;


--
-- Name: web_refresh_tokens web_refresh_tokens_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.web_refresh_tokens
    ADD CONSTRAINT web_refresh_tokens_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id);


--
CREATE TABLE public.point_grants (
    id uuid DEFAULT gen_random_uuid() NOT NULL PRIMARY KEY,
    user_id uuid NOT NULL REFERENCES public.web_users(id),
    source_type character varying(32) NOT NULL,
    source_id text NOT NULL,
    granted_amount numeric(18,2) NOT NULL CHECK (granted_amount > 0),
    available_amount numeric(18,2) NOT NULL CHECK (available_amount >= 0 AND available_amount <= granted_amount),
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    UNIQUE(source_type, source_id)
);

COMMENT ON TABLE public.point_grants IS '用户积分入账批次，用于支持永久积分的顺序扣减和原批次退款';
COMMENT ON COLUMN public.point_grants.id IS '积分批次唯一标识';
COMMENT ON COLUMN public.point_grants.user_id IS '积分所属用户标识';
COMMENT ON COLUMN public.point_grants.source_type IS '积分来源业务类型';
COMMENT ON COLUMN public.point_grants.source_id IS '积分来源业务记录标识，与来源类型共同保证幂等';
COMMENT ON COLUMN public.point_grants.granted_amount IS '批次初始入账积分，必须大于零';
COMMENT ON COLUMN public.point_grants.available_amount IS '批次当前可用积分，不得小于零或超过初始积分';
COMMENT ON COLUMN public.point_grants.created_at IS '积分批次创建时间，用于确定扣减顺序';

CREATE INDEX idx_point_grants_user_available
    ON public.point_grants(user_id, created_at, id)
    WHERE available_amount > 0;
COMMENT ON INDEX public.idx_point_grants_user_available IS '加速按用户和创建顺序锁定可用积分批次';

CREATE TABLE public.point_ledger_allocations (
    id bigserial PRIMARY KEY,
    ledger_id bigint NOT NULL REFERENCES public.point_ledger(id),
    grant_id uuid NOT NULL REFERENCES public.point_grants(id),
    allocation_type character varying(16) NOT NULL CHECK (allocation_type IN ('consume','refund')),
    amount numeric(18,2) NOT NULL CHECK (amount > 0),
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    UNIQUE(ledger_id, grant_id, allocation_type)
);

CREATE INDEX idx_point_ledger_allocations_grant
    ON public.point_ledger_allocations(grant_id, created_at DESC);

ALTER TABLE public.generation_tasks
    DROP CONSTRAINT IF EXISTS generation_tasks_canvas_project_id_fkey;
DROP INDEX IF EXISTS public.idx_generation_tasks_canvas_history;
ALTER TABLE public.generation_tasks
    DROP COLUMN IF EXISTS canvas_project_id;
DELETE FROM public.user_model_configs WHERE project_type = 'image_workbench';
ALTER TABLE public.user_model_configs
    DROP CONSTRAINT IF EXISTS user_model_configs_project_type_check;
ALTER TABLE public.user_model_configs
    ADD CONSTRAINT user_model_configs_project_type_check
    CHECK (project_type IN ('premium_drama', 'video_redraw', 'script_analysis'));
CREATE TABLE public.script_analyses (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    user_id uuid NOT NULL,
    name public.citext NOT NULL,
    source_content text DEFAULT ''::text NOT NULL,
    result_content text DEFAULT ''::text NOT NULL,
    analysis_result jsonb DEFAULT '{}'::jsonb NOT NULL,
    analysis_status character varying(20) DEFAULT 'idle'::character varying NOT NULL,
    analysis_message text,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    deleted_at timestamp with time zone,
    CONSTRAINT script_analyses_pkey PRIMARY KEY (id),
    CONSTRAINT script_analyses_status_check CHECK (((analysis_status)::text = ANY ((ARRAY['idle'::character varying, 'queued'::character varying, 'running'::character varying, 'succeeded'::character varying, 'failed'::character varying])::text[]))),
    CONSTRAINT script_analyses_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.web_users(id) ON DELETE CASCADE
);
CREATE INDEX idx_script_analyses_user_updated ON public.script_analyses USING btree (user_id, updated_at DESC) WHERE (deleted_at IS NULL);
CREATE TRIGGER script_analyses_updated_at BEFORE UPDATE ON public.script_analyses FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
CREATE TABLE public.script_analysis_characters (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    script_analysis_id uuid NOT NULL,
    name public.citext NOT NULL,
    faction character varying(20) NOT NULL,
    biography text DEFAULT ''::text NOT NULL,
    motivation text DEFAULT ''::text NOT NULL,
    relationship text DEFAULT ''::text NOT NULL,
    sort_order integer DEFAULT 0 NOT NULL,
    created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT script_analysis_characters_pkey PRIMARY KEY (id),
    CONSTRAINT script_analysis_characters_faction_check CHECK (((faction)::text = ANY ((ARRAY[U&'\6B63\6D3E'::character varying, U&'\53CD\6D3E'::character varying, U&'\4E2D\7ACB\6D3E'::character varying])::text[]))),
    CONSTRAINT script_analysis_characters_name_unique UNIQUE (script_analysis_id, name),
    CONSTRAINT script_analysis_characters_analysis_id_fkey FOREIGN KEY (script_analysis_id) REFERENCES public.script_analyses(id) ON DELETE CASCADE
);
CREATE INDEX idx_script_analysis_characters_analysis ON public.script_analysis_characters USING btree (script_analysis_id, sort_order);
CREATE TRIGGER script_analysis_characters_updated_at BEFORE UPDATE ON public.script_analysis_characters FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
ALTER TABLE ONLY public.generation_tasks
    ADD CONSTRAINT generation_tasks_script_analysis_id_fkey FOREIGN KEY (script_analysis_id) REFERENCES public.script_analyses(id) ON DELETE CASCADE;
CREATE INDEX idx_generation_tasks_script_analysis ON public.generation_tasks USING btree (script_analysis_id, created_at DESC) WHERE (script_analysis_id IS NOT NULL);
CREATE UNIQUE INDEX uq_script_analysis_active_task ON public.generation_tasks USING btree (script_analysis_id) WHERE ((script_analysis_id IS NOT NULL) AND ((status)::text = ANY ((ARRAY['pending_submission'::character varying, 'submitting'::character varying, 'submitted'::character varying, 'processing'::character varying, 'result_ready'::character varying, 'downloading'::character varying, 'cancel_requested'::character varying])::text[])));
DROP TABLE IF EXISTS public.inspiration_gallery_references;
DROP TABLE IF EXISTS public.inspiration_gallery_items;
DROP TABLE IF EXISTS public.canvas_projects;
DROP TABLE IF EXISTS public.announcements;
DROP TABLE IF EXISTS public.recharge_orders;
DROP TABLE IF EXISTS public.payment_configs;
DROP TABLE IF EXISTS public.point_packages;
DROP TABLE IF EXISTS public.point_exchange_rate_settings;

INSERT INTO public.prompts (id, name, type, content, scope, owner_user_id)
VALUES (
    '2eb481cf-4a8f-4da4-a70e-ea977739c8d1',
    '默认剧本分析提示词',
    '剧本分析',
    $prompt$你是一名资深短剧策划、编剧和商业化内容分析师。请严格依据用户提供的剧本原文进行结构化分析，不得把推测写成原文事实，不得编造原文不存在的关键人物、情节或台词。信息不足时使用空字符串或空数组。

分析目标：
1. 标签：分别提取短剧题材、风格、受众、情绪等短剧标签，以及适合山水景区、古镇景区、主题乐园、文博场馆、商业街区等文旅或商业落地场景的适用场景标签。只输出与剧本确实匹配的标签。
2. 核心看点与卖点：用一句话总结核心看点、卖点、爽点或痛点，并列出具体看点及其类型。
3. 剧情结构：输出短剧梗概、故事大纲、情绪大纲、分集大纲和人物小传。人物必须覆盖剧本中具有明确身份或剧情作用的正派、反派和中立人物；同一人物只返回一次。
4. 第一集黄金三秒：分别给出开篇第一个画面或场景、第一句台词，以及通过悬念前置、激烈冲突、视觉奇观等方式瞬间抓住观众的设计。若原稿开篇不够强，需要明确说明问题并给出不改变核心剧情的优化建议；第一句台词不得冒充原文台词，建议台词需明确标为建议。
5. 单集钩子：输出第1至第10集逐集钩子。原文无法识别某一集时保留该集编号并说明信息不足，不得虚构剧情。第10集除逐集钩子外，再提供3至5个付费卡点候选，每个候选需说明钩子类型、卡点内容和付费吸引力。$prompt$,
    'system',
    NULL
)
ON CONFLICT (id) DO NOTHING;

-- PostgreSQL database dump complete
--

CREATE TABLE IF NOT EXISTS public.jcf_schema_migrations (
    version character varying(128) PRIMARY KEY,
    applied_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP
);
