-- Separate schema: never imports/migrates the historical schema.sql or SQLite. CREATE SCHEMA IF NOT EXISTS dtf_local; CREATE TABLE IF NOT EXISTS dtf_local.uploads ( id uuid PRIMARY KEY, owner uuid NOT NULL, name text NOT NULL, size bigint NOT NULL, object_key text UNIQUE NOT NULL, multipart_id text NOT NULL, complete boolean NOT NULL DEFAULT false, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS dtf_local.quotes ( id uuid PRIMARY KEY, owner uuid NOT NULL, request_key uuid NOT NULL, request_hash text NOT NULL, draft jsonb NOT NULL, approved jsonb, reviewed_by text, approved_at timestamptz, created_at timestamptz NOT NULL DEFAULT now(), UNIQUE(owner, request_key) ); CREATE TABLE IF NOT EXISTS dtf_local.orders ( id uuid PRIMARY KEY, number bigint GENERATED ALWAYS AS IDENTITY UNIQUE, quote_id uuid NOT NULL UNIQUE REFERENCES dtf_local.quotes(id), owner uuid NOT NULL, snapshot jsonb NOT NULL, payment jsonb NOT NULL, state text NOT NULL DEFAULT 'rec', version integer NOT NULL DEFAULT 0, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS dtf_local.movements ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, order_id uuid NOT NULL REFERENCES dtf_local.orders(id), from_state text NOT NULL, to_state text NOT NULL, operator text NOT NULL, reason text NOT NULL, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS dtf_local.outbox ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, event_key text NOT NULL UNIQUE, provider text NOT NULL, payload jsonb NOT NULL, attempts integer NOT NULL DEFAULT 0, available_at timestamptz NOT NULL DEFAULT now(), delivered_at timestamptz, last_error text, receipt jsonb ); CREATE TABLE IF NOT EXISTS dtf_local.accounts ( id uuid PRIMARY KEY, email text UNIQUE NOT NULL, password_hash text NOT NULL, profile jsonb NOT NULL, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS dtf_local.sessions ( id uuid PRIMARY KEY, owner uuid NOT NULL, expires_at timestamptz NOT NULL DEFAULT now() + interval '7 days' ); CREATE TABLE IF NOT EXISTS dtf_local.migrations (name text PRIMARY KEY); -- Preserve pre-account guest sessions once, without resurrecting logged-out sessions. DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM dtf_local.migrations WHERE name='customer-sessions-v1') THEN INSERT INTO dtf_local.sessions(id,owner) SELECT owner,owner FROM ( SELECT owner FROM dtf_local.orders UNION SELECT owner FROM dtf_local.quotes UNION SELECT owner FROM dtf_local.uploads ) legacy ON CONFLICT DO NOTHING; INSERT INTO dtf_local.migrations VALUES('customer-sessions-v1'); END IF; END $$; CREATE TABLE IF NOT EXISTS dtf_local.login_attempts ( key text PRIMARY KEY, attempts integer NOT NULL DEFAULT 0, started_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS dtf_local.operator_sessions ( token_hash text PRIMARY KEY, username text NOT NULL, expires_at timestamptz NOT NULL DEFAULT now() + interval '8 hours' ); CREATE TABLE IF NOT EXISTS dtf_local.security_events ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, event text NOT NULL, details jsonb NOT NULL, created_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS uploads_owner ON dtf_local.uploads(owner); ALTER TABLE dtf_local.uploads ADD COLUMN IF NOT EXISTS expires_at timestamptz; ALTER TABLE dtf_local.uploads ADD COLUMN IF NOT EXISTS purged_at timestamptz; ALTER TABLE dtf_local.uploads ADD COLUMN IF NOT EXISTS scan_state text NOT NULL DEFAULT 'pending'; ALTER TABLE dtf_local.uploads ADD COLUMN IF NOT EXISTS scan_reason text; ALTER TABLE dtf_local.uploads ADD COLUMN IF NOT EXISTS scanned_at timestamptz; ALTER TABLE dtf_local.uploads ADD COLUMN IF NOT EXISTS scan_after timestamptz NOT NULL DEFAULT now(); UPDATE dtf_local.uploads SET expires_at=created_at + interval '30 days' WHERE expires_at IS NULL; ALTER TABLE dtf_local.uploads ALTER COLUMN expires_at SET DEFAULT now() + interval '30 days'; CREATE TABLE IF NOT EXISTS dtf_local.order_files ( id uuid PRIMARY KEY, order_id uuid NOT NULL REFERENCES dtf_local.orders(id), upload_id uuid NOT NULL REFERENCES dtf_local.uploads(id), item_index integer NOT NULL, kind text NOT NULL CHECK(kind IN ('final','correction')), active boolean NOT NULL DEFAULT true, note text NOT NULL, created_by text NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), UNIQUE(order_id,upload_id,kind) );