db: core-db schema

This commit is contained in:
2026-05-06 15:41:10 +00:00
parent ea52ab307a
commit 0e29b20d52
+14 -32
View File
@@ -1,14 +1,10 @@
-- manar-core-db: Registry layer -- manar-core-db: Registry layer
-- Shared across all brands. No tenant data here.
-- Extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto"; CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- ── Brands ───────────────────────────────────────────────
CREATE TABLE brands ( CREATE TABLE brands (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
slug TEXT UNIQUE NOT NULL, -- e.g. 'alsalama', 'asktam' slug TEXT UNIQUE NOT NULL,
name TEXT NOT NULL, name TEXT NOT NULL,
logo_url TEXT, logo_url TEXT,
timezone TEXT NOT NULL DEFAULT 'Asia/Riyadh', timezone TEXT NOT NULL DEFAULT 'Asia/Riyadh',
@@ -18,7 +14,6 @@ CREATE TABLE brands (
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
); );
-- ── Users ────────────────────────────────────────────────
CREATE TABLE users ( CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
email TEXT UNIQUE NOT NULL, email TEXT UNIQUE NOT NULL,
@@ -31,33 +26,27 @@ CREATE TABLE users (
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
); );
-- ── Brand Memberships ────────────────────────────────────
CREATE TABLE brand_memberships ( CREATE TABLE brand_memberships (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
brand_id UUID NOT NULL REFERENCES brands(id) ON DELETE CASCADE, brand_id UUID NOT NULL REFERENCES brands(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role TEXT NOT NULL DEFAULT 'viewer' CHECK (role IN ('viewer', 'analyst', 'manager', 'admin')), role TEXT NOT NULL DEFAULT 'viewer' CHECK (role IN ('viewer','analyst','manager','admin')),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(brand_id, user_id) UNIQUE(brand_id, user_id)
); );
-- ── Platforms ────────────────────────────────────────────
CREATE TABLE platforms ( CREATE TABLE platforms (
id SMALLSERIAL PRIMARY KEY, id SMALLSERIAL PRIMARY KEY,
slug TEXT UNIQUE NOT NULL, -- 'google_ads', 'meta', 'tiktok' slug TEXT UNIQUE NOT NULL,
name TEXT NOT NULL, name TEXT NOT NULL,
is_live BOOLEAN NOT NULL DEFAULT false is_live BOOLEAN NOT NULL DEFAULT false
); );
INSERT INTO platforms (slug, name, is_live) VALUES INSERT INTO platforms (slug, name, is_live) VALUES
('google_ads', 'Google Ads', true), ('google_ads','Google Ads',true),('meta','Meta Ads',false),
('meta', 'Meta Ads', false), ('tiktok','TikTok Ads',false),('snapchat','Snapchat Ads',false),
('tiktok', 'TikTok Ads', false), ('twitter','X Ads',false),('linkedin','LinkedIn Ads',false);
('snapchat', 'Snapchat Ads', false),
('twitter', 'X Ads', false),
('linkedin', 'LinkedIn Ads', false);
-- ── Audit Log (global) ───────────────────────────────────
CREATE TABLE audit_log_global ( CREATE TABLE audit_log_global (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
user_id UUID REFERENCES users(id), user_id UUID REFERENCES users(id),
@@ -72,7 +61,6 @@ CREATE TABLE audit_log_global (
CREATE INDEX idx_audit_global_brand ON audit_log_global(brand_id); CREATE INDEX idx_audit_global_brand ON audit_log_global(brand_id);
CREATE INDEX idx_audit_global_created ON audit_log_global(created_at DESC); CREATE INDEX idx_audit_global_created ON audit_log_global(created_at DESC);
-- ── Super Admin Actions ──────────────────────────────────
CREATE TABLE super_admin_actions ( CREATE TABLE super_admin_actions (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id), user_id UUID NOT NULL REFERENCES users(id),
@@ -84,22 +72,16 @@ CREATE TABLE super_admin_actions (
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
); );
-- ── Seed: Brands ───────────────────────────────────────── -- Seed
INSERT INTO brands (slug, name, timezone, trust_level) VALUES INSERT INTO brands (slug, name, timezone, trust_level) VALUES
('alsalama', 'Al Salama Medical', 'Asia/Riyadh', 0), ('alsalama','Al Salama Medical','Asia/Riyadh',0),
('asktam', 'Ask Tam', 'Asia/Riyadh', 0); ('asktam','Ask Tam','Asia/Riyadh',0);
-- ── Seed: Super Admin ────────────────────────────────────
INSERT INTO users (email, name, is_super_admin) VALUES INSERT INTO users (email, name, is_super_admin) VALUES
('tam@asktam.net', 'Tam', true); ('tam@asktam.net','Tam',true);
-- Updated_at trigger -- updated_at trigger
CREATE OR REPLACE FUNCTION update_updated_at() CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$ RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql;
BEGIN NEW.updated_at = NOW(); RETURN NEW; END; CREATE TRIGGER trg_brands_updated BEFORE UPDATE ON brands FOR EACH ROW EXECUTE FUNCTION update_updated_at();
$$ LANGUAGE plpgsql; CREATE TRIGGER trg_users_updated BEFORE UPDATE ON users FOR EACH ROW EXECUTE FUNCTION update_updated_at();
CREATE TRIGGER trg_brands_updated BEFORE UPDATE ON brands
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
CREATE TRIGGER trg_users_updated BEFORE UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION update_updated_at();