90ac0b81d1
Add full V2 architecture: identity, content, studio (.NET 10) and file, render, notification, gateway (Go) services with vendored deps, plus DB migrations, event/API contracts, and an init-db script. Wire the Next.js frontend to the gateway: server-side JWT auth routes (login/register/refresh/logout/me), gateway fetch helper, and session/ cookie/jwt helpers under src/lib. Containerize the stack via docker-compose.v2.yml and per-service Dockerfiles. Base images resolve through a Nexus mirror (Docker Hub) and MCR directly; npm/NuGet pull from Nexus groups. Self-host fonts via next/font/local to avoid Google Fonts (geo-blocked). Add CI workflow and ignore .env.v2, *.stackdump, and .NET bin/obj. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
144 lines
6.1 KiB
SQL
144 lines
6.1 KiB
SQL
-- =====================================================================
|
|
-- CONTENT SCHEMA — Part 2: Project Containers & Projects (Templates)
|
|
-- =====================================================================
|
|
|
|
SET search_path TO content, public;
|
|
|
|
-- Tenants can mark projects as private (only their users see them)
|
|
-- or use the global FlatRender catalog.
|
|
|
|
CREATE TYPE resolution_kind AS ENUM ('HD','FullHD','TwoK','FourK');
|
|
|
|
-- ---------------------------------------------------------------------
|
|
-- project_containers — the "product" (template pack)
|
|
-- ---------------------------------------------------------------------
|
|
CREATE TABLE project_containers (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID, -- NULL = global
|
|
-- FK to identity.tenants is enforced via service code (cross-schema FK kept loose)
|
|
|
|
slug CITEXT NOT NULL UNIQUE,
|
|
name TEXT NOT NULL,
|
|
description TEXT,
|
|
keywords TEXT,
|
|
news_text TEXT,
|
|
|
|
-- Media
|
|
image TEXT,
|
|
demo TEXT,
|
|
full_demo TEXT,
|
|
mini_demo TEXT,
|
|
demo_script_tag TEXT,
|
|
|
|
-- Modes & classifications
|
|
is_published BOOLEAN NOT NULL DEFAULT FALSE,
|
|
is_premium BOOLEAN NOT NULL DEFAULT FALSE,
|
|
is_mockup BOOLEAN NOT NULL DEFAULT FALSE,
|
|
primary_mode choose_mode NOT NULL DEFAULT 'FLEXIBLE',
|
|
|
|
-- Stats (denormalized for speed)
|
|
rate_avg NUMERIC(3,2),
|
|
rate_count INT NOT NULL DEFAULT 0,
|
|
view_count BIGINT NOT NULL DEFAULT 0,
|
|
use_count BIGINT NOT NULL DEFAULT 0,
|
|
|
|
sort INT NOT NULL DEFAULT 0,
|
|
sort_date TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX idx_containers_published ON project_containers(is_published, sort_date DESC) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_containers_tenant ON project_containers(tenant_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_containers_name_trgm ON project_containers USING gin (name gin_trgm_ops);
|
|
|
|
CREATE TRIGGER tg_containers_updated_at
|
|
BEFORE UPDATE ON project_containers FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at();
|
|
|
|
-- ---------------------------------------------------------------------
|
|
-- M2M: container ↔ categories
|
|
-- ---------------------------------------------------------------------
|
|
CREATE TABLE container_categories (
|
|
container_id UUID NOT NULL REFERENCES project_containers(id) ON DELETE CASCADE,
|
|
category_id UUID NOT NULL REFERENCES categories(id) ON DELETE CASCADE,
|
|
sort INT NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (container_id, category_id)
|
|
);
|
|
|
|
CREATE INDEX idx_cc_category ON container_categories(category_id);
|
|
|
|
-- ---------------------------------------------------------------------
|
|
-- M2M: container ↔ tags
|
|
-- ---------------------------------------------------------------------
|
|
CREATE TABLE container_tags (
|
|
container_id UUID NOT NULL REFERENCES project_containers(id) ON DELETE CASCADE,
|
|
tag_id UUID NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
|
|
PRIMARY KEY (container_id, tag_id)
|
|
);
|
|
|
|
CREATE INDEX idx_ct_tag ON container_tags(tag_id);
|
|
|
|
-- ---------------------------------------------------------------------
|
|
-- projects — one aspect-ratio variant of a container
|
|
-- ---------------------------------------------------------------------
|
|
CREATE TABLE projects (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
container_id UUID NOT NULL REFERENCES project_containers(id) ON DELETE CASCADE,
|
|
project_server_id UUID REFERENCES project_servers(id),
|
|
|
|
name TEXT NOT NULL,
|
|
description TEXT,
|
|
image TEXT,
|
|
full_demo TEXT,
|
|
demo_script_tag TEXT,
|
|
download_link TEXT,
|
|
|
|
-- AEP file storage
|
|
aep_minio_bucket TEXT,
|
|
aep_minio_key TEXT,
|
|
aep_file_url TEXT,
|
|
aep_file_md5 TEXT, -- for node cache check
|
|
aep_file_size_bytes BIGINT,
|
|
aep_uploaded_at TIMESTAMPTZ,
|
|
folder TEXT, -- legacy path on server
|
|
|
|
-- Geometry
|
|
original_width INT NOT NULL,
|
|
original_height INT NOT NULL,
|
|
aspect TEXT, -- '16:9','9:16','1:1','4:5',...
|
|
|
|
-- Timing
|
|
project_duration_sec NUMERIC(8,2) NOT NULL,
|
|
min_duration_sec NUMERIC(8,2),
|
|
max_duration_sec NUMERIC(8,2),
|
|
free_fps INT NOT NULL DEFAULT 30,
|
|
|
|
-- Mode
|
|
choose_mode choose_mode NOT NULL,
|
|
resolution resolution_kind NOT NULL DEFAULT 'FullHD',
|
|
vip_factor NUMERIC(4,2) NOT NULL DEFAULT 1.0,
|
|
render_aep_comp TEXT NOT NULL DEFAULT 'flatrender', -- main comp name
|
|
|
|
-- Misc (legacy artifacts to preserve)
|
|
shared_layer_image TEXT,
|
|
shared_colors_svg TEXT,
|
|
shared_color_presets_svg TEXT,
|
|
|
|
-- Status
|
|
is_published 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_projects_container ON projects(container_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_projects_published ON projects(is_published) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_projects_aep_md5 ON projects(aep_file_md5) WHERE aep_file_md5 IS NOT NULL;
|
|
|
|
CREATE TRIGGER tg_projects_updated_at
|
|
BEFORE UPDATE ON projects FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at();
|