first commit
All checks were successful
CI / backend (push) Successful in 13m19s
CI / frontend (push) Successful in 11m3s
CI / docker (push) Successful in 1m58s

This commit is contained in:
Cauê Faleiros
2026-06-03 16:31:42 -03:00
commit 8c7e5fbbe4
92 changed files with 18226 additions and 0 deletions

View File

@@ -0,0 +1,114 @@
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);

View File

@@ -0,0 +1,6 @@
ALTER TABLE clients
ADD COLUMN IF NOT EXISTS website_url TEXT NOT NULL DEFAULT '',
ADD COLUMN IF NOT EXISTS instagram_url TEXT NOT NULL DEFAULT '',
ADD COLUMN IF NOT EXISTS facebook_url TEXT NOT NULL DEFAULT '',
ADD COLUMN IF NOT EXISTS linkedin_url TEXT NOT NULL DEFAULT '',
ADD COLUMN IF NOT EXISTS notes TEXT NOT NULL DEFAULT '';

View File

@@ -0,0 +1,3 @@
CREATE UNIQUE INDEX IF NOT EXISTS idx_commemorative_dates_global_unique
ON commemorative_dates (date, name, category)
WHERE client_id IS NULL;

View File

@@ -0,0 +1,2 @@
ALTER TABLE clients
ADD COLUMN IF NOT EXISTS color TEXT NOT NULL DEFAULT '#f97316';