|
| 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 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); |
| 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 | +-- ========================================================================= |
| 55 | +-- 2. remotion_config |
| 56 | +-- ========================================================================= |
| 57 | +CREATE TABLE remotion_config ( |
| 58 | + id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1), |
| 59 | + aws_region text NOT NULL DEFAULT 'us-east-1', |
| 60 | + function_name text NOT NULL DEFAULT '', |
| 61 | + serve_url text NOT NULL DEFAULT '', |
| 62 | + max_render_timeout_sec integer NOT NULL DEFAULT 240, |
| 63 | + memory_mb integer NOT NULL DEFAULT 2048, |
| 64 | + disk_mb integer NOT NULL DEFAULT 2048, |
| 65 | + updated_at timestamptz NOT NULL DEFAULT now() |
| 66 | +); |
| 67 | + |
| 68 | +ALTER TABLE remotion_config ENABLE ROW LEVEL SECURITY; |
| 69 | + |
| 70 | +CREATE POLICY "service_role can read remotion_config" |
| 71 | + ON remotion_config FOR SELECT |
| 72 | + TO service_role |
| 73 | + USING (true); |
| 74 | + |
| 75 | +CREATE POLICY "service_role can update remotion_config" |
| 76 | + ON remotion_config FOR UPDATE |
| 77 | + TO service_role |
| 78 | + USING (true) |
| 79 | + WITH CHECK (true); |
| 80 | + |
| 81 | +INSERT INTO remotion_config (id) VALUES (1); |
| 82 | + |
| 83 | +CREATE TRIGGER trg_remotion_config_updated_at |
| 84 | + BEFORE UPDATE ON remotion_config |
| 85 | + FOR EACH ROW EXECUTE FUNCTION update_updated_at(); |
| 86 | + |
| 87 | +-- ========================================================================= |
| 88 | +-- 3. content_config |
| 89 | +-- ========================================================================= |
| 90 | +CREATE TABLE content_config ( |
| 91 | + id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1), |
| 92 | + rss_feeds jsonb NOT NULL DEFAULT '["https://hnrss.org/newest?points=100&count=20","https://dev.to/feed/tag/javascript","https://dev.to/feed/tag/webdev","https://css-tricks.com/feed/","https://blog.chromium.org/feeds/posts/default","https://web.dev/feed.xml","https://www.smashingmagazine.com/feed/","https://javascriptweekly.com/rss/"]'::jsonb, |
| 93 | + trend_sources_enabled jsonb NOT NULL DEFAULT '{"hn":true,"devto":true,"blogs":true,"youtube":true,"github":true}'::jsonb, |
| 94 | + 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. |
| 95 | +
|
| 96 | +Your style is inspired by Cleo Abram''s "Huge If True" — you make complex technical topics feel exciting, accessible, and important. Key principles: |
| 97 | +- Start with a BOLD claim or surprising fact that makes people stop scrolling |
| 98 | +- Use analogies and real-world comparisons to explain technical concepts |
| 99 | +- Build tension: "Here''s the problem... here''s why it matters... here''s the breakthrough" |
| 100 | +- Keep energy HIGH — short sentences, active voice, conversational tone |
| 101 | +- End with a clear takeaway that makes the viewer feel smarter |
| 102 | +- Target audience: developers who want to stay current but don''t have time to read everything |
| 103 | +
|
| 104 | +Script format: 60-90 second explainer videos. Think TikTok/YouTube Shorts energy with real educational depth. |
| 105 | +
|
| 106 | +CodingCat.dev covers: React, Next.js, TypeScript, Svelte, web APIs, CSS, Node.js, cloud services, AI/ML for developers, and web platform updates.', |
| 107 | + target_video_duration_sec integer NOT NULL DEFAULT 90, |
| 108 | + scene_count_min integer NOT NULL DEFAULT 3, |
| 109 | + scene_count_max integer NOT NULL DEFAULT 5, |
| 110 | + updated_at timestamptz NOT NULL DEFAULT now() |
| 111 | +); |
| 112 | + |
| 113 | +ALTER TABLE content_config ENABLE ROW LEVEL SECURITY; |
| 114 | + |
| 115 | +CREATE POLICY "service_role can read content_config" |
| 116 | + ON content_config FOR SELECT |
| 117 | + TO service_role |
| 118 | + USING (true); |
| 119 | + |
| 120 | +CREATE POLICY "service_role can update content_config" |
| 121 | + ON content_config FOR UPDATE |
| 122 | + TO service_role |
| 123 | + USING (true) |
| 124 | + WITH CHECK (true); |
| 125 | + |
| 126 | +INSERT INTO content_config (id) VALUES (1); |
| 127 | + |
| 128 | +CREATE TRIGGER trg_content_config_updated_at |
| 129 | + BEFORE UPDATE ON content_config |
| 130 | + FOR EACH ROW EXECUTE FUNCTION update_updated_at(); |
| 131 | + |
| 132 | +-- ========================================================================= |
| 133 | +-- 4. sponsor_config |
| 134 | +-- ========================================================================= |
| 135 | +CREATE TABLE sponsor_config ( |
| 136 | + id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1), |
| 137 | + cooldown_days integer NOT NULL DEFAULT 14, |
| 138 | + rate_card_tiers jsonb NOT NULL DEFAULT '[{"name":"starter","price":500,"impressions":"5k-10k"},{"name":"growth","price":1500,"impressions":"10k-50k"},{"name":"premium","price":3000,"impressions":"50k+"}]'::jsonb, |
| 139 | + outreach_email_template text NOT NULL DEFAULT 'Hi {{companyName}}, |
| 140 | +
|
| 141 | +I run CodingCat.dev, a web development education channel. We''d love to explore a sponsorship opportunity with you. |
| 142 | +
|
| 143 | +Best, |
| 144 | +Alex Patterson', |
| 145 | + max_outreach_per_run integer NOT NULL DEFAULT 10, |
| 146 | + updated_at timestamptz NOT NULL DEFAULT now() |
| 147 | +); |
| 148 | + |
| 149 | +ALTER TABLE sponsor_config ENABLE ROW LEVEL SECURITY; |
| 150 | + |
| 151 | +CREATE POLICY "service_role can read sponsor_config" |
| 152 | + ON sponsor_config FOR SELECT |
| 153 | + TO service_role |
| 154 | + USING (true); |
| 155 | + |
| 156 | +CREATE POLICY "service_role can update sponsor_config" |
| 157 | + ON sponsor_config FOR UPDATE |
| 158 | + TO service_role |
| 159 | + USING (true) |
| 160 | + WITH CHECK (true); |
| 161 | + |
| 162 | +INSERT INTO sponsor_config (id) VALUES (1); |
| 163 | + |
| 164 | +CREATE TRIGGER trg_sponsor_config_updated_at |
| 165 | + BEFORE UPDATE ON sponsor_config |
| 166 | + FOR EACH ROW EXECUTE FUNCTION update_updated_at(); |
| 167 | + |
| 168 | +-- ========================================================================= |
| 169 | +-- 5. distribution_config |
| 170 | +-- ========================================================================= |
| 171 | +CREATE TABLE distribution_config ( |
| 172 | + id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1), |
| 173 | + notification_emails jsonb NOT NULL DEFAULT '["alex@codingcat.dev"]'::jsonb, |
| 174 | + youtube_description_template text NOT NULL DEFAULT '{{title}} |
| 175 | +
|
| 176 | +{{summary}} |
| 177 | +
|
| 178 | +🔗 Learn more at https://codingcat.dev |
| 179 | +
|
| 180 | +#webdev #coding #programming', |
| 181 | + youtube_default_tags jsonb NOT NULL DEFAULT '["web development","coding","programming","tutorial","codingcat"]'::jsonb, |
| 182 | + resend_from_email text NOT NULL DEFAULT 'content@codingcat.dev', |
| 183 | + updated_at timestamptz NOT NULL DEFAULT now() |
| 184 | +); |
| 185 | + |
| 186 | +ALTER TABLE distribution_config ENABLE ROW LEVEL SECURITY; |
| 187 | + |
| 188 | +CREATE POLICY "service_role can read distribution_config" |
| 189 | + ON distribution_config FOR SELECT |
| 190 | + TO service_role |
| 191 | + USING (true); |
| 192 | + |
| 193 | +CREATE POLICY "service_role can update distribution_config" |
| 194 | + ON distribution_config FOR UPDATE |
| 195 | + TO service_role |
| 196 | + USING (true) |
| 197 | + WITH CHECK (true); |
| 198 | + |
| 199 | +INSERT INTO distribution_config (id) VALUES (1); |
| 200 | + |
| 201 | +CREATE TRIGGER trg_distribution_config_updated_at |
| 202 | + BEFORE UPDATE ON distribution_config |
| 203 | + FOR EACH ROW EXECUTE FUNCTION update_updated_at(); |
| 204 | + |
| 205 | +-- ========================================================================= |
| 206 | +-- 6. gcs_config |
| 207 | +-- ========================================================================= |
| 208 | +CREATE TABLE gcs_config ( |
| 209 | + id integer PRIMARY KEY DEFAULT 1 CHECK (id = 1), |
| 210 | + bucket_name text NOT NULL DEFAULT 'codingcatdev-content-engine', |
| 211 | + project_id text NOT NULL DEFAULT 'codingcatdev', |
| 212 | + updated_at timestamptz NOT NULL DEFAULT now() |
| 213 | +); |
| 214 | + |
| 215 | +ALTER TABLE gcs_config ENABLE ROW LEVEL SECURITY; |
| 216 | + |
| 217 | +CREATE POLICY "service_role can read gcs_config" |
| 218 | + ON gcs_config FOR SELECT |
| 219 | + TO service_role |
| 220 | + USING (true); |
| 221 | + |
| 222 | +CREATE POLICY "service_role can update gcs_config" |
| 223 | + ON gcs_config FOR UPDATE |
| 224 | + TO service_role |
| 225 | + USING (true) |
| 226 | + WITH CHECK (true); |
| 227 | + |
| 228 | +INSERT INTO gcs_config (id) VALUES (1); |
| 229 | + |
| 230 | +CREATE TRIGGER trg_gcs_config_updated_at |
| 231 | + BEFORE UPDATE ON gcs_config |
| 232 | + FOR EACH ROW EXECUTE FUNCTION update_updated_at(); |
0 commit comments