CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE TABLE IF NOT EXISTS users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email TEXT NOT NULL UNIQUE, name TEXT NOT NULL, password_hash TEXT NOT NULL, role TEXT NOT NULL CHECK (role IN ('super_admin', 'agency_user', 'client_viewer')), status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'invited', 'disabled')), created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS clients ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, slug TEXT NOT NULL UNIQUE, status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'archived')), created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS client_users ( client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (client_id, user_id) ); CREATE TABLE IF NOT EXISTS invitations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email TEXT NOT NULL, role TEXT NOT NULL CHECK (role IN ('agency_user', 'client_viewer')), client_id UUID REFERENCES clients(id) ON DELETE CASCADE, token_hash TEXT NOT NULL UNIQUE, expires_at TIMESTAMPTZ NOT NULL, accepted_at TIMESTAMPTZ, created_by UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS holidays ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), date DATE NOT NULL, name TEXT NOT NULL, type TEXT NOT NULL DEFAULT 'official_holiday', source TEXT NOT NULL DEFAULT 'brasilapi', raw_payload JSONB NOT NULL DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE (date, source, name) ); CREATE TABLE IF NOT EXISTS commemorative_dates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), client_id UUID REFERENCES clients(id) ON DELETE CASCADE, name TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', date DATE NOT NULL, recurs_annually BOOLEAN NOT NULL DEFAULT false, visibility TEXT NOT NULL DEFAULT 'agency' CHECK (visibility IN ('agency', 'client')), category TEXT NOT NULL DEFAULT 'custom', created_by UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS calendar_items ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE, title TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', content_type TEXT NOT NULL DEFAULT 'post', status TEXT NOT NULL DEFAULT 'rascunho' CHECK ( status IN ('rascunho', 'planejado', 'em_producao', 'em_revisao', 'aprovado', 'publicado', 'cancelado') ), owner_id UUID REFERENCES users(id) ON DELETE SET NULL, scheduled_date DATE NOT NULL, scheduled_at TIMESTAMPTZ, copy_text TEXT NOT NULL DEFAULT '', internal_notes TEXT NOT NULL DEFAULT '', client_notes TEXT NOT NULL DEFAULT '', created_by UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS calendar_item_attachments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), calendar_item_id UUID NOT NULL REFERENCES calendar_items(id) ON DELETE CASCADE, original_filename TEXT NOT NULL, stored_filename TEXT NOT NULL, mime_type TEXT NOT NULL, size_bytes BIGINT NOT NULL CHECK (size_bytes >= 0), storage_driver TEXT NOT NULL, storage_path TEXT NOT NULL, created_by UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS audit_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), actor_user_id UUID REFERENCES users(id) ON DELETE SET NULL, action TEXT NOT NULL, entity_type TEXT NOT NULL, entity_id UUID, metadata JSONB NOT NULL DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_users_email ON users (email); CREATE INDEX IF NOT EXISTS idx_calendar_items_client_date ON calendar_items (client_id, scheduled_date); CREATE INDEX IF NOT EXISTS idx_holidays_date ON holidays (date); CREATE INDEX IF NOT EXISTS idx_commemorative_dates_client_date ON commemorative_dates (client_id, date);