-- 001_core_tables.sql -- Core tables for Performance West API: subscribers, tickets, quotes, orders. -- Run: psql $DATABASE_URL < migrations/001_core_tables.sql BEGIN; -- Mailing list subscribers CREATE TABLE IF NOT EXISTS subscribers ( id SERIAL PRIMARY KEY, email TEXT NOT NULL UNIQUE, name TEXT, company TEXT, consent_text TEXT NOT NULL, consent_at TIMESTAMPTZ NOT NULL DEFAULT now(), ip_address TEXT, confirmed BOOLEAN DEFAULT FALSE, unsubscribed BOOLEAN DEFAULT FALSE, source TEXT DEFAULT 'website', created_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_subscribers_email ON subscribers(email); CREATE INDEX IF NOT EXISTS idx_subscribers_created ON subscribers(created_at DESC); -- Support tickets (local fallback when Zammad is unavailable) CREATE TABLE IF NOT EXISTS tickets ( id SERIAL PRIMARY KEY, category TEXT NOT NULL CHECK (category IN ( 'question', 'support', 'issue', 'service_request', 'quote' )), subject TEXT NOT NULL, message TEXT NOT NULL, email TEXT, name TEXT, page TEXT, ip_address TEXT, zammad_ticket_id TEXT, created_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_tickets_category ON tickets(category); CREATE INDEX IF NOT EXISTS idx_tickets_created ON tickets(created_at DESC); -- Quote requests (for custom-priced services) CREATE TABLE IF NOT EXISTS quotes ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, email TEXT NOT NULL, company TEXT, phone TEXT, service_slug TEXT NOT NULL, details TEXT, status TEXT DEFAULT 'pending' CHECK (status IN ( 'pending', 'sent', 'accepted', 'declined', 'expired' )), created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_quotes_status ON quotes(status); CREATE INDEX IF NOT EXISTS idx_quotes_email ON quotes(email); -- Service orders (fixed-price and accepted quotes) CREATE TABLE IF NOT EXISTS orders ( id SERIAL PRIMARY KEY, order_number TEXT UNIQUE NOT NULL, quote_id INTEGER REFERENCES quotes(id), service_slug TEXT NOT NULL, name TEXT NOT NULL, email TEXT NOT NULL, company TEXT, status TEXT DEFAULT 'received' CHECK (status IN ( 'received', 'processing', 'review', 'delivered', 'cancelled' )), amount_cents INTEGER, created_at TIMESTAMPTZ DEFAULT now(), delivered_at TIMESTAMPTZ ); CREATE INDEX IF NOT EXISTS idx_orders_status ON orders(status); CREATE INDEX IF NOT EXISTS idx_orders_number ON orders(order_number); CREATE INDEX IF NOT EXISTS idx_orders_email ON orders(email); COMMIT;