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
-- Shared across all brands. No tenant data here.
-- Extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- ── Brands ───────────────────────────────────────────────
CREATE TABLE brands (
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,
logo_url TEXT,
timezone TEXT NOT NULL DEFAULT 'Asia/Riyadh',
@@ -18,7 +14,6 @@ CREATE TABLE brands (
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ── Users ────────────────────────────────────────────────
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
email TEXT UNIQUE NOT NULL,
@@ -31,33 +26,27 @@ CREATE TABLE users (
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ── Brand Memberships ────────────────────────────────────
CREATE TABLE brand_memberships (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
brand_id UUID NOT NULL REFERENCES brands(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(),
UNIQUE(brand_id, user_id)
);
-- ── Platforms ────────────────────────────────────────────
CREATE TABLE platforms (
id SMALLSERIAL PRIMARY KEY,
slug TEXT UNIQUE NOT NULL, -- 'google_ads', 'meta', 'tiktok'
slug TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
is_live BOOLEAN NOT NULL DEFAULT false
);
INSERT INTO platforms (slug, name, is_live) VALUES
('google_ads', 'Google Ads', true),
('meta', 'Meta Ads', false),
('tiktok', 'TikTok Ads', false),
('snapchat', 'Snapchat Ads', false),
('twitter', 'X Ads', false),
('linkedin', 'LinkedIn Ads', false);
('google_ads','Google Ads',true),('meta','Meta Ads',false),
('tiktok','TikTok Ads',false),('snapchat','Snapchat Ads',false),
('twitter','X Ads',false),('linkedin','LinkedIn Ads',false);
-- ── Audit Log (global) ───────────────────────────────────
CREATE TABLE audit_log_global (
id BIGSERIAL PRIMARY KEY,
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_created ON audit_log_global(created_at DESC);
-- ── Super Admin Actions ──────────────────────────────────
CREATE TABLE super_admin_actions (
id BIGSERIAL PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id),
@@ -84,22 +72,16 @@ CREATE TABLE super_admin_actions (
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ── Seed: Brands ─────────────────────────────────────────
-- Seed
INSERT INTO brands (slug, name, timezone, trust_level) VALUES
('alsalama', 'Al Salama Medical', 'Asia/Riyadh', 0),
('asktam', 'Ask Tam', 'Asia/Riyadh', 0);
('alsalama','Al Salama Medical','Asia/Riyadh',0),
('asktam','Ask Tam','Asia/Riyadh',0);
-- ── Seed: Super Admin ────────────────────────────────────
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()
RETURNS TRIGGER AS $$
BEGIN NEW.updated_at = NOW(); RETURN NEW; END;
$$ LANGUAGE plpgsql;
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();
RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql;
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();