Skip to content

Commit 74288d8

Browse files
authored
feat: Supabase migration SQL for 6 config tables (#606)
Creates 6 singleton config tables: pipeline_config, remotion_config, content_config, sponsor_config, distribution_config, gcs_config. Each table has CHECK(id=1) singleton constraint, RLS (service_role only), auto updated_at trigger, seeded defaults, and table comments. JSONB defaults match TypeScript interfaces in lib/types/config.ts.
1 parent 89434c0 commit 74288d8

File tree

1 file changed

+244
-0
lines changed

1 file changed

+244
-0
lines changed
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
-- =============================================================================
2+
-- 003_config_tables.sql
3+
-- Six singleton config tables for the CodingCat.dev Automated Content Engine.
4+
-- Each table enforces a single row via CHECK (id = 1).
5+
-- RLS: service_role can SELECT/UPDATE; anon and authenticated are blocked.
6+
-- =============================================================================
7+
8+
-- ---------------------------------------------------------------------------
9+
-- Shared trigger function: auto-update updated_at on any row change
10+
-- ---------------------------------------------------------------------------
11+
CREATE OR REPLACE FUNCTION update_updated_at()
12+
RETURNS trigger AS $$
13+
BEGIN
14+
NEW.updated_at = now();
15+
RETURN NEW;
16+
END;
17+
$$ LANGUAGE plpgsql;
18+
19+
-- =========================================================================
20+
-- 1. pipeline_config
21+
-- =========================================================================
22+
CREATE TABLE IF NOT EXISTS pipeline_config (
23+
id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1),
24+
gemini_model text NOT NULL DEFAULT 'gemini-2.0-flash',
25+
elevenlabs_voice_id text NOT NULL DEFAULT 'pNInz6obpgDQGcFmaJgB',
26+
youtube_upload_visibility text NOT NULL DEFAULT 'private',
27+
youtube_channel_id text NOT NULL DEFAULT '',
28+
enable_notebooklm_research boolean NOT NULL DEFAULT false,
29+
quality_threshold integer NOT NULL DEFAULT 50,
30+
stuck_timeout_minutes integer NOT NULL DEFAULT 30,
31+
max_ideas_per_run integer NOT NULL DEFAULT 1,
32+
updated_at timestamptz NOT NULL DEFAULT now()
33+
);
34+
35+
ALTER TABLE pipeline_config ENABLE ROW LEVEL SECURITY;
36+
37+
CREATE POLICY "service_role can read pipeline_config"
38+
ON pipeline_config FOR SELECT
39+
TO service_role
40+
USING (true);
41+
42+
CREATE POLICY "service_role can update pipeline_config"
43+
ON pipeline_config FOR UPDATE
44+
TO service_role
45+
USING (true)
46+
WITH CHECK (true);
47+
48+
INSERT INTO pipeline_config (id) VALUES (1) ON CONFLICT (id) DO NOTHING;
49+
50+
CREATE TRIGGER trg_pipeline_config_updated_at
51+
BEFORE UPDATE ON pipeline_config
52+
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
53+
54+
COMMENT ON TABLE pipeline_config IS 'Core video pipeline settings: Gemini model, voice, YouTube visibility, quality thresholds';
55+
56+
-- =========================================================================
57+
-- 2. remotion_config
58+
-- =========================================================================
59+
CREATE TABLE IF NOT EXISTS remotion_config (
60+
id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1),
61+
aws_region text NOT NULL DEFAULT 'us-east-1',
62+
function_name text NOT NULL DEFAULT '',
63+
serve_url text NOT NULL DEFAULT '',
64+
max_render_timeout_sec integer NOT NULL DEFAULT 240,
65+
memory_mb integer NOT NULL DEFAULT 2048,
66+
disk_mb integer NOT NULL DEFAULT 2048,
67+
updated_at timestamptz NOT NULL DEFAULT now()
68+
);
69+
70+
ALTER TABLE remotion_config ENABLE ROW LEVEL SECURITY;
71+
72+
CREATE POLICY "service_role can read remotion_config"
73+
ON remotion_config FOR SELECT
74+
TO service_role
75+
USING (true);
76+
77+
CREATE POLICY "service_role can update remotion_config"
78+
ON remotion_config FOR UPDATE
79+
TO service_role
80+
USING (true)
81+
WITH CHECK (true);
82+
83+
INSERT INTO remotion_config (id) VALUES (1) ON CONFLICT (id) DO NOTHING;
84+
85+
CREATE TRIGGER trg_remotion_config_updated_at
86+
BEFORE UPDATE ON remotion_config
87+
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
88+
89+
COMMENT ON TABLE remotion_config IS 'Remotion Lambda rendering: AWS region, function name, serve URL, resource limits';
90+
91+
-- =========================================================================
92+
-- 3. content_config
93+
-- =========================================================================
94+
CREATE TABLE IF NOT EXISTS content_config (
95+
id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1),
96+
rss_feeds jsonb NOT NULL DEFAULT '[{"name":"HN Top","url":"https://hnrss.org/newest?points=100&count=20"},{"name":"Dev.to JavaScript","url":"https://dev.to/feed/tag/javascript"},{"name":"Dev.to WebDev","url":"https://dev.to/feed/tag/webdev"},{"name":"CSS-Tricks","url":"https://css-tricks.com/feed/"},{"name":"Chromium Blog","url":"https://blog.chromium.org/feeds/posts/default"},{"name":"web.dev","url":"https://web.dev/feed.xml"},{"name":"Smashing Magazine","url":"https://www.smashingmagazine.com/feed/"},{"name":"JavaScript Weekly","url":"https://javascriptweekly.com/rss/"}]'::jsonb,
97+
trend_sources_enabled jsonb NOT NULL DEFAULT '{"hn":true,"devto":true,"blogs":true,"youtube":true,"github":true}'::jsonb,
98+
system_instruction text NOT NULL DEFAULT 'You are a content strategist and scriptwriter for CodingCat.dev, a web development education channel run by Alex Patterson.
99+
100+
Your style is inspired by Cleo Abram''s "Huge If True" — you make complex technical topics feel exciting, accessible, and important. Key principles:
101+
- Start with a BOLD claim or surprising fact that makes people stop scrolling
102+
- Use analogies and real-world comparisons to explain technical concepts
103+
- Build tension: "Here''s the problem... here''s why it matters... here''s the breakthrough"
104+
- Keep energy HIGH — short sentences, active voice, conversational tone
105+
- End with a clear takeaway that makes the viewer feel smarter
106+
- Target audience: developers who want to stay current but don''t have time to read everything
107+
108+
Script format: 60-90 second explainer videos. Think TikTok/YouTube Shorts energy with real educational depth.
109+
110+
CodingCat.dev covers: React, Next.js, TypeScript, Svelte, web APIs, CSS, Node.js, cloud services, AI/ML for developers, and web platform updates.',
111+
target_video_duration_sec integer NOT NULL DEFAULT 90,
112+
scene_count_min integer NOT NULL DEFAULT 3,
113+
scene_count_max integer NOT NULL DEFAULT 5,
114+
updated_at timestamptz NOT NULL DEFAULT now()
115+
);
116+
117+
ALTER TABLE content_config ENABLE ROW LEVEL SECURITY;
118+
119+
CREATE POLICY "service_role can read content_config"
120+
ON content_config FOR SELECT
121+
TO service_role
122+
USING (true);
123+
124+
CREATE POLICY "service_role can update content_config"
125+
ON content_config FOR UPDATE
126+
TO service_role
127+
USING (true)
128+
WITH CHECK (true);
129+
130+
INSERT INTO content_config (id) VALUES (1) ON CONFLICT (id) DO NOTHING;
131+
132+
CREATE TRIGGER trg_content_config_updated_at
133+
BEFORE UPDATE ON content_config
134+
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
135+
136+
COMMENT ON TABLE content_config IS 'Content discovery and generation: RSS feeds, trend sources, system prompt, video duration';
137+
138+
-- =========================================================================
139+
-- 4. sponsor_config
140+
-- =========================================================================
141+
CREATE TABLE IF NOT EXISTS sponsor_config (
142+
id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1),
143+
cooldown_days integer NOT NULL DEFAULT 14,
144+
rate_card_tiers jsonb NOT NULL DEFAULT '[{"name":"starter","description":"5k-10k impressions","price":500},{"name":"growth","description":"10k-50k impressions","price":1500},{"name":"premium","description":"50k+ impressions","price":3000}]'::jsonb,
145+
outreach_email_template text NOT NULL DEFAULT 'Hi {{companyName}},
146+
147+
I run CodingCat.dev, a web development education channel. We''d love to explore a sponsorship opportunity with you.
148+
149+
Best,
150+
Alex Patterson',
151+
max_outreach_per_run integer NOT NULL DEFAULT 10,
152+
updated_at timestamptz NOT NULL DEFAULT now()
153+
);
154+
155+
ALTER TABLE sponsor_config ENABLE ROW LEVEL SECURITY;
156+
157+
CREATE POLICY "service_role can read sponsor_config"
158+
ON sponsor_config FOR SELECT
159+
TO service_role
160+
USING (true);
161+
162+
CREATE POLICY "service_role can update sponsor_config"
163+
ON sponsor_config FOR UPDATE
164+
TO service_role
165+
USING (true)
166+
WITH CHECK (true);
167+
168+
INSERT INTO sponsor_config (id) VALUES (1) ON CONFLICT (id) DO NOTHING;
169+
170+
CREATE TRIGGER trg_sponsor_config_updated_at
171+
BEFORE UPDATE ON sponsor_config
172+
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
173+
174+
COMMENT ON TABLE sponsor_config IS 'Sponsor pipeline: cooldown periods, rate card tiers, outreach templates';
175+
176+
-- =========================================================================
177+
-- 5. distribution_config
178+
-- =========================================================================
179+
CREATE TABLE IF NOT EXISTS distribution_config (
180+
id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1),
181+
notification_emails jsonb NOT NULL DEFAULT '["alex@codingcat.dev"]'::jsonb,
182+
youtube_description_template text NOT NULL DEFAULT '{{title}}
183+
184+
{{summary}}
185+
186+
🔗 Learn more at https://codingcat.dev
187+
188+
#webdev #coding #programming',
189+
youtube_default_tags jsonb NOT NULL DEFAULT '["web development","coding","programming","tutorial","codingcat"]'::jsonb,
190+
resend_from_email text NOT NULL DEFAULT 'content@codingcat.dev',
191+
updated_at timestamptz NOT NULL DEFAULT now()
192+
);
193+
194+
ALTER TABLE distribution_config ENABLE ROW LEVEL SECURITY;
195+
196+
CREATE POLICY "service_role can read distribution_config"
197+
ON distribution_config FOR SELECT
198+
TO service_role
199+
USING (true);
200+
201+
CREATE POLICY "service_role can update distribution_config"
202+
ON distribution_config FOR UPDATE
203+
TO service_role
204+
USING (true)
205+
WITH CHECK (true);
206+
207+
INSERT INTO distribution_config (id) VALUES (1) ON CONFLICT (id) DO NOTHING;
208+
209+
CREATE TRIGGER trg_distribution_config_updated_at
210+
BEFORE UPDATE ON distribution_config
211+
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
212+
213+
COMMENT ON TABLE distribution_config IS 'Distribution: notification emails, YouTube templates, default tags';
214+
215+
-- =========================================================================
216+
-- 6. gcs_config
217+
-- =========================================================================
218+
CREATE TABLE IF NOT EXISTS gcs_config (
219+
id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1),
220+
bucket_name text NOT NULL DEFAULT 'codingcatdev-content-engine',
221+
project_id text NOT NULL DEFAULT 'codingcatdev',
222+
updated_at timestamptz NOT NULL DEFAULT now()
223+
);
224+
225+
ALTER TABLE gcs_config ENABLE ROW LEVEL SECURITY;
226+
227+
CREATE POLICY "service_role can read gcs_config"
228+
ON gcs_config FOR SELECT
229+
TO service_role
230+
USING (true);
231+
232+
CREATE POLICY "service_role can update gcs_config"
233+
ON gcs_config FOR UPDATE
234+
TO service_role
235+
USING (true)
236+
WITH CHECK (true);
237+
238+
INSERT INTO gcs_config (id) VALUES (1) ON CONFLICT (id) DO NOTHING;
239+
240+
CREATE TRIGGER trg_gcs_config_updated_at
241+
BEFORE UPDATE ON gcs_config
242+
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
243+
244+
COMMENT ON TABLE gcs_config IS 'Google Cloud Storage: bucket name and project ID';

0 commit comments

Comments
 (0)