-- ===================================================================== -- CONTENT SCHEMA — Part 1: Taxonomy & Assets (categories, tags, fonts, music) -- ===================================================================== SET search_path TO content, public; -- --------------------------------------------------------------------- -- categories — hierarchical -- --------------------------------------------------------------------- CREATE TABLE categories ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), parent_id UUID REFERENCES categories(id) ON DELETE SET NULL, name TEXT NOT NULL, slug CITEXT NOT NULL UNIQUE, description TEXT, image_url TEXT, icon TEXT, -- SEO meta_title TEXT, meta_description TEXT, meta_keywords TEXT, bot_follow BOOLEAN NOT NULL DEFAULT TRUE, sort INT NOT NULL DEFAULT 0, is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE INDEX idx_categories_parent ON categories(parent_id); CREATE INDEX idx_categories_active ON categories(is_active) WHERE deleted_at IS NULL; CREATE TRIGGER tg_categories_updated_at BEFORE UPDATE ON categories FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); -- --------------------------------------------------------------------- -- container_categories — many-to-many -- --------------------------------------------------------------------- -- Will be created after project_containers table -- --------------------------------------------------------------------- -- tags -- --------------------------------------------------------------------- CREATE TYPE choose_mode AS ENUM ('FIX','FLEXIBLE','MockUp','MusicVisualizer','VoiceOver'); CREATE TABLE tags ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, latin_name TEXT, slug CITEXT NOT NULL UNIQUE, applies_to_mode choose_mode, is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE INDEX idx_tags_active ON tags(is_active) WHERE deleted_at IS NULL; CREATE TRIGGER tg_tags_updated_at BEFORE UPDATE ON tags FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); -- --------------------------------------------------------------------- -- fonts -- --------------------------------------------------------------------- CREATE TABLE fonts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, -- display name original_name TEXT, -- as registered in AE system_name TEXT, -- exact OS family name family TEXT, weight INT, -- 100-900 style TEXT, -- 'normal' | 'italic' direction TEXT NOT NULL DEFAULT 'LTR', -- LTR/RTL/Auto file_url TEXT, -- .ttf/.otf URL sample_image_url TEXT, is_premium BOOLEAN NOT NULL DEFAULT FALSE, is_active BOOLEAN NOT NULL DEFAULT TRUE, installed_on_nodes BOOLEAN NOT NULL DEFAULT FALSE, sort INT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE INDEX idx_fonts_active ON fonts(is_active) WHERE deleted_at IS NULL; CREATE TRIGGER tg_fonts_updated_at BEFORE UPDATE ON fonts FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); -- --------------------------------------------------------------------- -- music_tracks -- --------------------------------------------------------------------- CREATE TABLE music_tracks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, caption TEXT, keywords TEXT, url TEXT NOT NULL, waveform_data JSONB, -- precomputed visualization duration_sec NUMERIC(8,2) NOT NULL, bpm INT, genre TEXT, mood TEXT, is_premium BOOLEAN NOT NULL DEFAULT FALSE, is_active BOOLEAN NOT NULL DEFAULT TRUE, sort INT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE INDEX idx_music_active ON music_tracks(is_active) WHERE deleted_at IS NULL; CREATE INDEX idx_music_genre ON music_tracks(genre); CREATE TRIGGER tg_music_updated_at BEFORE UPDATE ON music_tracks FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); -- --------------------------------------------------------------------- -- project_servers — render server configs (multi-region) -- --------------------------------------------------------------------- CREATE TABLE project_servers ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, region TEXT NOT NULL, -- 'tehran','frankfurt',... ip INET, physical_path_output TEXT, default_project_address TEXT, render_output_location TEXT, pre_need_folder_address TEXT, minio_endpoint TEXT, minio_bucket_templates TEXT, minio_bucket_outputs TEXT, is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_project_servers_region ON project_servers(region) WHERE is_active = TRUE; CREATE TRIGGER tg_project_servers_updated_at BEFORE UPDATE ON project_servers FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); -- --------------------------------------------------------------------- -- admin_files — admin-uploaded resources -- --------------------------------------------------------------------- CREATE TABLE admin_files ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT, url TEXT NOT NULL, thumbnail_url TEXT, file_type TEXT, size_bytes BIGINT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() );