-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdatabase-setup.sql
More file actions
161 lines (149 loc) · 6.68 KB
/
Copy pathdatabase-setup.sql
File metadata and controls
161 lines (149 loc) · 6.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
-- ============================================================================
-- SPITE — Database setup script (Postgres / Neon)
-- Note: the camera_bag table (from removed Camera Bag feature) is no
-- longer created; if an existing database still has it, drop it with:
-- DROP TABLE IF EXISTS camera_bag;
-- ----------------------------------------------------------------------------
-- HOW TO USE:
-- 1. Open your Neon project at https://console.neon.tech
-- 2. In the left sidebar, click "SQL Editor"
-- 3. Paste this ENTIRE file into the editor
-- 4. Click "Run"
-- It is safe to run this more than once — it only creates things that are
-- missing and will not delete or overwrite your existing data.
-- ============================================================================
-- Projects: one row per film project on your dashboard.
-- scenes / active_scene_id: per-project scene timeline state. scenes is
-- a JSONB array of {id, name}; shots[] are derived from canvas_nodes
-- at read time and not persisted here.
CREATE TABLE IF NOT EXISTS projects (
id uuid PRIMARY KEY,
userid uuid NOT NULL,
name text NOT NULL DEFAULT 'Untitled Project',
description text DEFAULT '',
thumbnail text,
scenes jsonb,
active_scene_id text,
createdat timestamptz NOT NULL DEFAULT now(),
updatedat timestamptz NOT NULL DEFAULT now()
);
-- For projects tables that pre-date scene persistence: add the columns
-- if they aren't already there. CREATE TABLE IF NOT EXISTS above only
-- runs when the table is missing entirely.
ALTER TABLE projects ADD COLUMN IF NOT EXISTS scenes jsonb;
ALTER TABLE projects ADD COLUMN IF NOT EXISTS active_scene_id text;
-- Generation history: every AI image/video you generate, plus canvas uploads.
-- This is the "asset library" the left panel reads from. id is TEXT because the
-- app generates ids like 'asset-1700000000000-ab12cd34' as well as UUIDs.
CREATE TABLE IF NOT EXISTS generation_history (
id text PRIMARY KEY,
type text,
model text,
prompt text,
r2_url text,
used_in_canvas boolean DEFAULT false,
is_upload boolean DEFAULT false,
created_at timestamptz DEFAULT now(),
expires_at timestamptz,
project_id text
);
-- Assets: project file uploads with metadata + tags (separate from the AI
-- generation history above).
CREATE TABLE IF NOT EXISTS assets (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
projectid text NOT NULL,
name text,
category text,
url text,
tags text[],
metadata jsonb,
createdat timestamptz DEFAULT now(),
updatedat timestamptz DEFAULT now()
);
-- Canvas nodes: the boxes on the node canvas, saved per project.
-- Primary key on (projectid, nodeid) so the app's UPSERT/auto-save works.
CREATE TABLE IF NOT EXISTS canvas_nodes (
projectid text NOT NULL,
nodeid text NOT NULL,
type text,
position_x double precision,
position_y double precision,
data jsonb,
createdat timestamptz DEFAULT now(),
PRIMARY KEY (projectid, nodeid)
);
-- Canvas edges: the connections between nodes, saved per project.
CREATE TABLE IF NOT EXISTS canvas_edges (
projectid text NOT NULL,
edgeid text NOT NULL,
source text,
target text,
sourcehandle text,
targethandle text,
animated boolean,
data jsonb,
createdat timestamptz DEFAULT now(),
PRIMARY KEY (projectid, edgeid)
);
-- Asset folders: named groups (Characters / Props / Locations / General).
-- All columns are plain text so we never run into uuid-vs-text comparison
-- pitfalls with parameter binding (the prior schema had project_id end up
-- as uuid in some installs, which broke every WHERE filter).
CREATE TABLE IF NOT EXISTS asset_folders (
id text PRIMARY KEY,
project_id text NOT NULL,
type text NOT NULL,
name text NOT NULL,
description text,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
-- Asset folder items: composite key on (folder_id, asset_id) — same asset
-- can't be added twice to the same folder.
CREATE TABLE IF NOT EXISTS asset_folder_items (
folder_id text NOT NULL REFERENCES asset_folders(id) ON DELETE CASCADE,
asset_id text NOT NULL,
added_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (folder_id, asset_id)
);
-- Sessions: opaque tokens issued at login, validated on every request.
-- Replaces the previous static cookie value so a captured cookie can
-- be revoked server-side by logout / expiry.
CREATE TABLE IF NOT EXISTS sessions (
token text PRIMARY KEY,
created_at timestamptz NOT NULL DEFAULT now(),
expires_at timestamptz NOT NULL DEFAULT (now() + interval '30 days')
);
-- Auth attempts: per-IP failed-login log feeding the rate limiter on
-- the verify endpoint (5 attempts per IP per 60 s).
CREATE TABLE IF NOT EXISTS auth_attempts (
ip text NOT NULL,
attempted_at timestamptz NOT NULL DEFAULT now()
);
-- Spend ledger: server-side record of every accepted fal.ai submission.
-- Drives the per-hour USD ceiling enforced in /api/generate/submit.
CREATE TABLE IF NOT EXISTS spend_ledger (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
model_id text NOT NULL,
estimated_usd numeric(10,4) NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
-- Voice ID cache: maps an audio asset's SPITE proxy URL to the
-- fal-issued voice_id created from it (Kling 2.6 voice cloning).
-- Each unique audio file costs one fal create-voice call; everything
-- after that hits the cache and is instant.
CREATE TABLE IF NOT EXISTS voice_id_cache (
audio_url text PRIMARY KEY,
voice_id text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
-- Helpful indexes for the most common lookups.
CREATE INDEX IF NOT EXISTS idx_generation_history_project ON generation_history (project_id);
CREATE INDEX IF NOT EXISTS idx_assets_project ON assets (projectid);
CREATE INDEX IF NOT EXISTS idx_canvas_nodes_project ON canvas_nodes (projectid);
CREATE INDEX IF NOT EXISTS idx_canvas_edges_project ON canvas_edges (projectid);
CREATE INDEX IF NOT EXISTS idx_asset_folders_project ON asset_folders (project_id);
CREATE INDEX IF NOT EXISTS idx_folder_items_folder ON asset_folder_items (folder_id);
CREATE INDEX IF NOT EXISTS idx_sessions_expires ON sessions (expires_at);
CREATE INDEX IF NOT EXISTS idx_auth_attempts_ip_time ON auth_attempts (ip, attempted_at);
CREATE INDEX IF NOT EXISTS idx_spend_ledger_time ON spend_ledger (created_at);