167 lines
5.0 KiB
JavaScript
167 lines
5.0 KiB
JavaScript
import pg from 'pg'
|
|
|
|
const { Pool } = pg
|
|
let pool
|
|
|
|
export function getPool() {
|
|
if (!pool) {
|
|
if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is required')
|
|
pool = new Pool({
|
|
connectionString: process.env.DATABASE_URL,
|
|
max: 10,
|
|
ssl: process.env.DATABASE_SSL === 'true' ? { rejectUnauthorized: false } : undefined
|
|
})
|
|
}
|
|
return pool
|
|
}
|
|
|
|
export async function initDb() {
|
|
const db = getPool()
|
|
await db.query(`
|
|
CREATE TABLE IF NOT EXISTS templates (
|
|
id text PRIMARY KEY,
|
|
tenant_id text NOT NULL,
|
|
template_key text,
|
|
name text NOT NULL,
|
|
type text NOT NULL CHECK (type IN ('email', 'report')),
|
|
status text NOT NULL DEFAULT 'draft',
|
|
draft_document jsonb NOT NULL,
|
|
sample_data jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
published_version integer,
|
|
created_by text,
|
|
updated_by text,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
)
|
|
`)
|
|
await db.query(`ALTER TABLE templates ADD COLUMN IF NOT EXISTS template_key text`)
|
|
await db.query(`
|
|
UPDATE templates
|
|
SET template_key = 'template-' || substr(replace(id, '-', ''), 1, 12)
|
|
WHERE template_key IS NULL
|
|
`)
|
|
await db.query(`ALTER TABLE templates ALTER COLUMN template_key SET NOT NULL`)
|
|
|
|
await db.query(`
|
|
CREATE TABLE IF NOT EXISTS folders (
|
|
id text PRIMARY KEY,
|
|
tenant_id text NOT NULL,
|
|
name text NOT NULL,
|
|
parent_id text REFERENCES folders(id) ON DELETE CASCADE,
|
|
created_by text,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
)
|
|
`)
|
|
await db.query(`ALTER TABLE templates ADD COLUMN IF NOT EXISTS folder_id text REFERENCES folders(id) ON DELETE SET NULL`)
|
|
|
|
await db.query(`
|
|
CREATE TABLE IF NOT EXISTS template_versions (
|
|
id text PRIMARY KEY,
|
|
template_id text NOT NULL REFERENCES templates(id) ON DELETE CASCADE,
|
|
version integer NOT NULL,
|
|
document jsonb NOT NULL,
|
|
sample_data jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
created_by text,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
UNIQUE(template_id, version)
|
|
)
|
|
`)
|
|
|
|
await db.query(`
|
|
CREATE TABLE IF NOT EXISTS template_assets (
|
|
id text PRIMARY KEY,
|
|
tenant_id text NOT NULL,
|
|
template_id text NOT NULL REFERENCES templates(id) ON DELETE CASCADE,
|
|
asset_key text NOT NULL,
|
|
filename text NOT NULL,
|
|
mime_type text NOT NULL,
|
|
byte_size integer NOT NULL,
|
|
public_token text NOT NULL UNIQUE,
|
|
data bytea NOT NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
UNIQUE(template_id, asset_key)
|
|
)
|
|
`)
|
|
|
|
await db.query(`
|
|
CREATE TABLE IF NOT EXISTS themes (
|
|
id text PRIMARY KEY,
|
|
tenant_id text NOT NULL,
|
|
name text NOT NULL,
|
|
applies_to text NOT NULL DEFAULT 'all' CHECK (applies_to IN ('all', 'report', 'email')),
|
|
theme jsonb NOT NULL,
|
|
created_by text,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
)
|
|
`)
|
|
|
|
await db.query(`
|
|
CREATE TABLE IF NOT EXISTS theme_assets (
|
|
id text PRIMARY KEY,
|
|
tenant_id text NOT NULL,
|
|
theme_id text NOT NULL REFERENCES themes(id) ON DELETE CASCADE,
|
|
asset_key text NOT NULL,
|
|
filename text NOT NULL,
|
|
mime_type text NOT NULL,
|
|
byte_size integer NOT NULL,
|
|
public_token text NOT NULL UNIQUE,
|
|
data bytea NOT NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
UNIQUE(theme_id, asset_key)
|
|
)
|
|
`)
|
|
|
|
await db.query(`
|
|
CREATE TABLE IF NOT EXISTS api_keys (
|
|
id text PRIMARY KEY,
|
|
tenant_id text NOT NULL,
|
|
name text NOT NULL,
|
|
key_prefix text NOT NULL,
|
|
key_hash text NOT NULL UNIQUE,
|
|
created_by text,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
last_used_at timestamptz,
|
|
revoked_at timestamptz
|
|
)
|
|
`)
|
|
|
|
await db.query(`
|
|
CREATE INDEX IF NOT EXISTS templates_tenant_updated_idx
|
|
ON templates (tenant_id, updated_at DESC)
|
|
`)
|
|
await db.query(`
|
|
CREATE INDEX IF NOT EXISTS templates_folder_idx
|
|
ON templates (tenant_id, folder_id, updated_at DESC)
|
|
`)
|
|
await db.query(`
|
|
CREATE INDEX IF NOT EXISTS folders_parent_idx
|
|
ON folders (tenant_id, parent_id, name)
|
|
`)
|
|
await db.query(`
|
|
CREATE UNIQUE INDEX IF NOT EXISTS folders_unique_sibling_name_idx
|
|
ON folders (tenant_id, COALESCE(parent_id, ''), lower(name))
|
|
`)
|
|
await db.query(`
|
|
CREATE UNIQUE INDEX IF NOT EXISTS templates_tenant_key_idx
|
|
ON templates (tenant_id, template_key)
|
|
`)
|
|
await db.query(`
|
|
CREATE INDEX IF NOT EXISTS api_keys_tenant_created_idx
|
|
ON api_keys (tenant_id, created_at DESC)
|
|
`)
|
|
await db.query(`
|
|
CREATE INDEX IF NOT EXISTS template_assets_template_idx
|
|
ON template_assets (template_id)
|
|
`)
|
|
await db.query(`
|
|
CREATE INDEX IF NOT EXISTS themes_tenant_created_idx
|
|
ON themes (tenant_id, created_at DESC)
|
|
`)
|
|
await db.query(`
|
|
CREATE INDEX IF NOT EXISTS theme_assets_theme_idx
|
|
ON theme_assets (theme_id)
|
|
`)
|
|
}
|