From c3742e9cdb609501f2aa2688324dcacf054189f7 Mon Sep 17 00:00:00 2001 From: Mao Nakamoto <41178744+maonakamoto@users.noreply.github.com> Date: Fri, 28 Aug 2026 10:05:40 +0200 Subject: [PATCH] docs(db): point this repo at its own database, and gate the way back MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The schema fix landed in #138, but the repo still told you to operate a Supabase we do not have. docs/SUPABASE_SETUP.md opened with "Completed Setup" for a hosted project jkjmhtirxwhljpkcfxqe.supabase.co and said to apply migrations by pasting SQL into a supabase.com dashboard. Two unreferenced scripts printed the same instruction, one handing out a psql string against pooler.supabase.com, and the CLI's .temp cache with the old project ref was committed — twice, once nested under supabase/migrations/. That is not stale clutter, it is the outage. A wrong pointer to a real-looking place is worse than no pointer: no pointer makes someone ask, a plausible one makes them assume it was handled. Nobody pasted anything, the eleven migrations were never applied, and /api/health served PGRST205 for months while every deploy went green. So the doc now describes what is actually true — self-hosted on bitbaum at supabase.orangecat.ch, our tables in the `botsmann` schema because one database backs several apps and `public` is orangecat's, and migrations applied automatically on deploy by fleetcrown's apply-schema.sh against the botsmann._deploy_schema_history ledger. Nothing is pasted anywhere. 280 lines became 100. Fixing today's copies only clears today's copies, so check:selfhost joins verify: it fails on supabase.com/dashboard, app.supabase.com, pooler URLs and real project refs, allows supabase.com/docs because the product documentation is still correct for us, and exempts docs/archive/ so history can stay honest. Proven to fail before shipping — it catches an injected dashboard link and a project ref, and leaves the your-project.supabase.co placeholder alone. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018waGt1ieA9TjpscqrbrnGb --- .env.example | 5 +- .gitignore | 3 + docs/SUPABASE_SETUP.md | 314 ++++-------------- .../5-operations/OPERATIONS_DOCUMENTATION.md | 11 +- lib/supabase.ts | 15 +- package.json | 3 +- scripts/apply-optimizations.mjs | 98 ------ scripts/ci/no-hosted-supabase.sh | 39 +++ scripts/run-migration-009.ts | 103 ------ supabase/.temp/cli-latest | 1 - supabase/.temp/gotrue-version | 1 - supabase/.temp/pooler-url | 1 - supabase/.temp/postgres-version | 1 - supabase/.temp/project-ref | 1 - supabase/.temp/rest-version | 1 - supabase/.temp/storage-migration | 1 - supabase/.temp/storage-version | 1 - supabase/migrations/001_initial_schema.sql | 2 +- supabase/migrations/supabase/.temp/cli-latest | 1 - .../migrations/supabase/.temp/gotrue-version | 1 - supabase/migrations/supabase/.temp/pooler-url | 1 - .../supabase/.temp/postgres-version | 1 - .../migrations/supabase/.temp/project-ref | 1 - .../migrations/supabase/.temp/rest-version | 1 - .../supabase/.temp/storage-migration | 1 - .../migrations/supabase/.temp/storage-version | 1 - 26 files changed, 132 insertions(+), 477 deletions(-) delete mode 100644 scripts/apply-optimizations.mjs create mode 100755 scripts/ci/no-hosted-supabase.sh delete mode 100644 scripts/run-migration-009.ts delete mode 100644 supabase/.temp/cli-latest delete mode 100644 supabase/.temp/gotrue-version delete mode 100644 supabase/.temp/pooler-url delete mode 100644 supabase/.temp/postgres-version delete mode 100644 supabase/.temp/project-ref delete mode 100644 supabase/.temp/rest-version delete mode 100644 supabase/.temp/storage-migration delete mode 100644 supabase/.temp/storage-version delete mode 100644 supabase/migrations/supabase/.temp/cli-latest delete mode 100644 supabase/migrations/supabase/.temp/gotrue-version delete mode 100644 supabase/migrations/supabase/.temp/pooler-url delete mode 100644 supabase/migrations/supabase/.temp/postgres-version delete mode 100644 supabase/migrations/supabase/.temp/project-ref delete mode 100644 supabase/migrations/supabase/.temp/rest-version delete mode 100644 supabase/migrations/supabase/.temp/storage-migration delete mode 100644 supabase/migrations/supabase/.temp/storage-version diff --git a/.env.example b/.env.example index 6eb89af5..91bd38f7 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,9 @@ # =========================================== # Supabase Configuration (required) -# Get these from: https://supabase.com/dashboard/project/_/settings/api +# Self-hosted on bitbaum, NOT supabase.com — URL is https://supabase.orangecat.ch. +# Keys live in /opt/botsmann/shared/.env on the box; ask before minting new ones. +# Our tables are in the `botsmann` schema (see lib/constants.ts), not `public` — +# `public` belongs to orangecat and shares this database with us. # =========================================== NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= diff --git a/.gitignore b/.gitignore index 545928a2..5c4c83f6 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,6 @@ status.json # Lint cache .eslintcache + +# supabase CLI scratch — machine state, and it used to leak the old hosted project ref +supabase/.temp/ diff --git a/docs/SUPABASE_SETUP.md b/docs/SUPABASE_SETUP.md index 27f8486c..49e8b78b 100644 --- a/docs/SUPABASE_SETUP.md +++ b/docs/SUPABASE_SETUP.md @@ -1,280 +1,100 @@ -# Supabase Database Setup for Botsmann +# Botsmann's Database -## ✅ Completed Setup +## Where it is -### 1. Project Configuration +Self-hosted. There is **no supabase.com project**, no hosted dashboard, and no +bill from Supabase. We run the open-source Supabase stack in Docker on the +Hetzner box "bitbaum", the same box that serves the app. -**Supabase Project:** botsmann -**Project Reference:** jkjmhtirxwhljpkcfxqe -**Region:** West EU (Ireland) -**URL:** https://jkjmhtirxwhljpkcfxqe.supabase.co +| | | +| ---------- | ------------------------------------------------------------------ | +| API URL | `https://supabase.orangecat.ch` (Caddy → Kong on `127.0.0.1:8000`) | +| Database | `supabase-db` container, Postgres, no published port | +| Our schema | **`botsmann`** — not `public` | +| Studio | `https://supabase.orangecat.ch/` — behind Kong's basic auth | +| Keys | `/opt/botsmann/shared/.env` on the box | -### 2. Database Schema +If you find a hosted-dashboard link anywhere in this repo, it is a +leftover from before the move and it is wrong. `npm run check:selfhost` fails +the build on new ones. -All core migrations have been successfully applied: +## Why we are not in `public` -#### Tables Created: +**One database backs several apps.** OrangeCat owns `public` and has ~136 tables +there. Our table names collide with theirs — `conversations`, `documents`, +`waitlist` — and our `001` defines `update_updated_at()`, a function name +`public` already holds and OrangeCat's triggers call. -- ✅ `consultations` - Contact form submissions -- ✅ `user_settings` - User preferences and API keys -- ✅ `documents` - Uploaded documents for RAG -- ✅ `document_chunks` - Document chunks with vector embeddings -- ✅ `custom_bots` - User-created AI assistants -- ✅ `bot_knowledge_chunks` - Knowledge base for custom bots +So every app gets its own schema. Ours is `botsmann`, pinned in one place: -#### Security Features: - -- ✅ Row Level Security (RLS) enabled on all user tables -- ✅ RLS policies for user isolation -- ✅ Public bot sharing policies -- ✅ Service role access for admin operations - -#### Performance Features: - -- ✅ Indexes on foreign keys -- ✅ Indexes on frequently queried columns (status, user_id, created_at) -- ✅ Timestamps with auto-update triggers -- ✅ Vector similarity search functions - -### 3. Environment Configuration - -The `.env.local` file must be updated with your project credentials (never commit real values): - -```bash -NEXT_PUBLIC_SUPABASE_URL=https://jkjmhtirxwhljpkcfxqe.supabase.co -NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci... -SUPABASE_SERVICE_ROLE_KEY=eyJhbGci... -SUPABASE_ACCESS_TOKEN=sbp_... +```ts +// lib/constants.ts +export const DB_SCHEMA = 'botsmann'; ``` -### 4. Connection Verified - -All tables are accessible and working: - -- ✅ consultations -- ✅ user_settings -- ✅ documents -- ✅ document_chunks -- ✅ custom_bots -- ✅ bot_knowledge_chunks - ---- - -## 🔧 Additional Optimizations to Apply Manually - -The following optimizations are defined in migration files but should be applied manually through the Supabase dashboard: - -### Migration Files to Apply: - -1. **004_extensions.sql** - PostgreSQL extensions - - `vector` - For embeddings (likely already installed) - - `pgcrypto` - For UUID generation - - `pg_trgm` - For fuzzy text search +Every client in `lib/supabase.ts` passes `db: { schema: DB_SCHEMA }`. **A client +that forgets it reads `public`**, where our tables do not exist, and PostgREST +answers `PGRST205 — Could not find the table 'public.consultations'`. That looks +like a dead database but is really a missing five words of config. It is what +took the app down; `tests/__tests__/lib/supabase-schema.test.ts` now guards it. -2. **005_optimizations.sql** - Performance optimizations - - Additional indexes for email search - - Composite indexes for common queries - - Text search indexes using trigrams - - Email validation constraints - - Helper functions for stats and search - - Cleanup functions for orphaned data +## How migrations are applied -### How to Apply: +**Automatically, on deploy. You never paste SQL anywhere.** -1. Go to [Supabase Dashboard](https://supabase.com/dashboard/project/jkjmhtirxwhljpkcfxqe) -2. Navigate to **SQL Editor** -3. Click **New Query** -4. Copy contents of `supabase/migrations/004_extensions.sql` -5. Run the query -6. Repeat for `supabase/migrations/005_optimizations.sql` +Pushing to `main` runs `.github/workflows/deploy.yml`, which calls fleetcrown's +`selfhost-deploy.yml`. That pipeline runs +`scripts/hetzner/apply-schema.sh botsmann … supabase:botsmann` before restarting +the app. It: ---- +- applies only files in `supabase/migrations/` not already recorded in + `botsmann._deploy_schema_history`, +- runs the batch in **one transaction** — all or nothing, +- **refuses** any migration containing a destructive statement, aborting the + deploy rather than silently dropping production data. -## 📦 Storage Bucket Setup +Current state: 11 migrations applied, 13 tables in the schema. -**Action Required:** Create a storage bucket for document uploads +### Adding one -### Steps: +1. Add `supabase/migrations/0NN_what_it_does.sql`. Keep it forward-only and + non-destructive, or the deploy will refuse it. +2. Open a PR. Merging deploys it and applies it. -1. Go to [Storage](https://supabase.com/dashboard/project/jkjmhtirxwhljpkcfxqe/storage/buckets) -2. Click **New Bucket** -3. Configure: - - **Name:** `documents` - - **Public:** No (private bucket) - - **File size limit:** 50 MB (adjust as needed) - - **Allowed MIME types:** - - `application/pdf` - - `text/plain` - - `text/markdown` - - `application/msword` - - `application/vnd.openxmlformats-officedocument.wordprocessingml.document` +A genuinely destructive change is applied by hand, then recorded so the +automation skips it: -4. **Set up storage policies:** - -```sql --- Allow users to upload to their own folder -CREATE POLICY "Users can upload own documents" -ON storage.objects FOR INSERT -TO authenticated -WITH CHECK ( - bucket_id = 'documents' - AND (storage.foldername(name))[1] = auth.uid()::text -); - --- Allow users to read their own documents -CREATE POLICY "Users can read own documents" -ON storage.objects FOR SELECT -TO authenticated -USING ( - bucket_id = 'documents' - AND (storage.foldername(name))[1] = auth.uid()::text -); - --- Allow users to delete their own documents -CREATE POLICY "Users can delete own documents" -ON storage.objects FOR DELETE -TO authenticated -USING ( - bucket_id = 'documents' - AND (storage.foldername(name))[1] = auth.uid()::text -); +```bash +ssh ubuntu@167.233.22.31 "docker exec supabase-db psql -U postgres -d postgres \ + -c \"INSERT INTO botsmann._deploy_schema_history(tag) VALUES ('0NN_what_it_does')\"" ``` ---- - -## 🔐 Authentication Setup - -**Action Required:** Configure authentication settings - -### Steps: - -1. Go to [Authentication Settings](https://supabase.com/dashboard/project/jkjmhtirxwhljpkcfxqe/auth/url-configuration) -2. Add **Site URL:** `http://localhost:3000` (for development) -3. Add **Redirect URLs:** - - `http://localhost:3000/auth/callback` - - `https://your-production-domain.com/auth/callback` (when deploying) - -4. Configure **Email Templates** (optional but recommended) -5. Enable **Email Provider** or other auth methods as needed - ---- - -## 🚀 Testing the Setup - -### Quick Test - -Run the connection test script: +## Checking the database ```bash -cd /home/g/botsmann -npm install # Ensure dependencies are installed -node scripts/test-db-connection.ts +npm run test:db # connects with our schema and reports every expected table ``` -### Manual API Test +Straight from the box, when you need to see the schema itself: ```bash -curl "https://jkjmhtirxwhljpkcfxqe.supabase.co/rest/v1/consultations?select=count" \ - -H "apikey: YOUR_ANON_KEY" \ - -H "Authorization: Bearer YOUR_ANON_KEY" +ssh ubuntu@167.233.22.31 \ + "docker exec supabase-db psql -U postgres -d postgres \ + -c '\\dt botsmann.*'" ``` ---- - -## 📊 Database Schema Best Practices Implemented +## Storage and auth -### ✅ DRY (Don't Repeat Yourself) +Storage (`supabase-storage`) and auth (`supabase-auth`, GoTrue) are shared +services on the box, not per-app. Buckets and auth redirect URLs are configured +in Studio. Storage policies live on `storage.objects`, which is shared with +every other app on this stack — scope any policy you add to our bucket, and +prefer a bucket per app over a shared one. -- Reusable utility functions (`match_documents`, `match_bot_knowledge`) -- Shared trigger functions (`update_updated_at`) -- Centralized RLS policies +## Resources -### ✅ SSOT (Single Source of Truth) - -- User data linked via foreign keys to `auth.users` -- Document ownership tracked in single location -- Bot knowledge linked to custom bots table - -### ✅ Separation of Concerns - -- Auth handled by Supabase Auth -- Data access controlled by RLS -- Business logic in application layer -- Vector search in database functions - -### ✅ Performance - -- Indexes on all foreign keys -- Composite indexes for common queries -- Vector indexes for similarity search (ready for when data grows) -- Efficient RLS policies - -### ✅ Security - -- Row Level Security on all user tables -- Service role separation -- User data isolation -- Public/private bot sharing controls - ---- - -## 🛠️ Maintenance - -### Regular Tasks - -1. **Monitor Database Size:** - - ```sql - SELECT pg_size_pretty(pg_database_size('postgres')); - ``` - -2. **Clean Orphaned Chunks:** - - ```sql - SELECT cleanup_orphaned_chunks(); - SELECT cleanup_orphaned_bot_chunks(); - ``` - -3. **Check User Stats:** - ```sql - SELECT * FROM get_document_stats('user-uuid-here'); - SELECT get_user_bots_count('user-uuid-here'); - ``` - -### Backup Strategy - -Supabase provides automatic daily backups. To create manual backup: - -1. Go to [Database Settings](https://supabase.com/dashboard/project/jkjmhtirxwhljpkcfxqe/settings/database) -2. Click **Backups** -3. Create manual backup before major changes - ---- - -## 📚 Resources - -- [Supabase Documentation](https://supabase.com/docs) -- [pgvector Documentation](https://github.com/pgvector/pgvector) +- [Supabase docs](https://supabase.com/docs) — the product docs are still the + right reference; only the hosted dashboard does not apply to us. +- [pgvector](https://github.com/pgvector/pgvector) - [PostgreSQL Row Level Security](https://www.postgresql.org/docs/current/ddl-rowsecurity.html) -- [Supabase Storage](https://supabase.com/docs/guides/storage) - ---- - -## ✨ Summary - -Your Botsmann application is now connected to Supabase with: - -- ✅ All tables created with proper schema -- ✅ Row Level Security configured -- ✅ Vector search capabilities ready -- ✅ Environment variables updated -- ✅ Connection tested and verified -- ⏳ Storage bucket (manual setup required) -- ⏳ Advanced optimizations (manual SQL execution recommended) - -**Next Steps:** - -1. Apply the optimization migrations manually -2. Set up the storage bucket -3. Configure authentication URLs -4. Start building features! +- fleetcrown: `scripts/hetzner/apply-schema.sh`, `docs/infrastructure/migration-strategy.md` diff --git a/executive-docs/5-operations/OPERATIONS_DOCUMENTATION.md b/executive-docs/5-operations/OPERATIONS_DOCUMENTATION.md index 2cf95bf0..c1e69297 100644 --- a/executive-docs/5-operations/OPERATIONS_DOCUMENTATION.md +++ b/executive-docs/5-operations/OPERATIONS_DOCUMENTATION.md @@ -930,14 +930,17 @@ All Hands On Deck **Production:** -- Website: https://www.botsmann.com -- Vercel Dashboard: https://vercel.com/botsmann -- Supabase Dashboard: https://app.supabase.com +- Website: https://botsmann.orangecat.ch +- Deploys: GitHub Actions `Deploy` workflow (push to `main`) — self-hosted on + the Hetzner box "bitbaum". There is no Vercel. +- Database: self-hosted Supabase Studio at https://supabase.orangecat.ch + (behind Kong basic auth). There is no supabase.com project. **Monitoring:** +- Uptime: fleetcrown `fleet-uptime` workflow probes `/api/health` every 15 + minutes and opens a GitHub issue when this app goes down. - Sentry: (to be set up) -- UptimeRobot: (to be set up) **Documentation:** diff --git a/lib/supabase.ts b/lib/supabase.ts index ec0415f8..efe17de9 100644 --- a/lib/supabase.ts +++ b/lib/supabase.ts @@ -1,13 +1,16 @@ /** * Supabase Client for Botsmann * - * Free tier includes: - * - 500MB PostgreSQL database - * - 1GB file storage - * - Unlimited API requests - * - pgvector for embeddings + * This talks to OUR Supabase, self-hosted on bitbaum at supabase.orangecat.ch — + * there is no supabase.com project and no dashboard to log into. Capacity is + * whatever the box has, not a hosted tier. * - * Setup: https://supabase.com/dashboard + * One database backs several apps, so every client here is pinned to the + * `botsmann` schema via DB_SCHEMA. An unpinned client reads `public`, which is + * orangecat's, where our tables simply do not exist — that reads as a dead + * database rather than as a misconfiguration. + * + * Setup: docs/SUPABASE_SETUP.md */ import { createClient } from '@supabase/supabase-js'; diff --git a/package.json b/package.json index 77a5f7dd..a2f4f190 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "format": "prettier --write .", "format:check": "prettier --check .", "typecheck": "tsc --noEmit", - "verify": "npm run format:check && npm run lint && npm run typecheck && npm run test && npm run build", + "check:selfhost": "bash scripts/ci/no-hosted-supabase.sh", + "verify": "npm run format:check && npm run lint && npm run typecheck && npm run check:selfhost && npm run test && npm run build", "prepare": "husky install", "lint-staged": "lint-staged" }, diff --git a/scripts/apply-optimizations.mjs b/scripts/apply-optimizations.mjs deleted file mode 100644 index 65a3e018..00000000 --- a/scripts/apply-optimizations.mjs +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env node -/** - * Apply database optimizations directly using Supabase client - */ - -import { createClient } from '@supabase/supabase-js'; -import { readFileSync } from 'fs'; -import { config } from 'dotenv'; -import { fileURLToPath } from 'url'; -import { dirname, join } from 'path'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -// Load environment variables -config({ path: join(__dirname, '../.env.local') }); - -const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; -const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY; - -if (!supabaseUrl || !supabaseKey) { - console.error('❌ Missing Supabase credentials'); - process.exit(1); -} - -const supabase = createClient(supabaseUrl, supabaseKey, { - auth: { - autoRefreshToken: false, - persistSession: false, - }, -}); - -// Read migration files -const extensionsSql = readFileSync( - join(__dirname, '../supabase/migrations/004_extensions.sql'), - 'utf-8', -); - -const optimizationsSql = readFileSync( - join(__dirname, '../supabase/migrations/005_optimizations.sql'), - 'utf-8', -); - -async function applyMigrations() { - console.log('🚀 Applying database optimizations...\n'); - - try { - // Apply extensions first - console.log('📦 Installing PostgreSQL extensions...'); - const { error: extError } = await supabase - .rpc('exec_sql', { - sql: extensionsSql, - }) - .catch(() => { - // If exec_sql doesn't exist, we'll need to use the SQL directly - return { error: null }; - }); - - if (extError) { - console.log('⚠️ Extensions: Using REST API workaround'); - // We'll apply these via the dashboard or manual SQL - } else { - console.log('✅ Extensions installed'); - } - - // Apply optimizations - console.log('\n📈 Adding performance indexes and constraints...'); - const { error: optError } = await supabase - .rpc('exec_sql', { - sql: optimizationsSql, - }) - .catch(() => { - return { error: null }; - }); - - if (optError) { - console.log('⚠️ Optimizations: Using REST API workaround'); - } else { - console.log('✅ Optimizations applied'); - } - - console.log('\n✨ Migration application complete!'); - console.log( - '\nNote: If any steps failed, please apply the SQL manually in the Supabase dashboard:', - ); - console.log('1. Go to https://supabase.com/dashboard'); - console.log('2. Select your botsmann project'); - console.log('3. Go to SQL Editor'); - console.log('4. Run the contents of:'); - console.log(' - supabase/migrations/004_extensions.sql'); - console.log(' - supabase/migrations/005_optimizations.sql'); - } catch (error) { - console.error('❌ Error:', error); - process.exit(1); - } -} - -applyMigrations(); diff --git a/scripts/ci/no-hosted-supabase.sh b/scripts/ci/no-hosted-supabase.sh new file mode 100755 index 00000000..46cedae5 --- /dev/null +++ b/scripts/ci/no-hosted-supabase.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Fail if anything in this repo points at a HOSTED Supabase. +# +# WHY: our database is the self-hosted stack on bitbaum (supabase.orangecat.ch). +# We have no supabase.com project. The repo nevertheless carried a full setup +# doc, two migration scripts and a committed CLI cache all pointing at a hosted +# project ref — so the documented way to apply a migration was "paste this into +# a dashboard", against a dashboard that does not exist for us. Nobody pasted +# anything, the schema was never applied, and the app served PGRST205 in +# production. The instructions were not merely stale; they were the outage. +# +# Fixing those files once only clears today's copies. This gate ends the class. +# +# Allowed: supabase.com/docs — the product documentation is still correct for +# us; only the hosted control plane is not. +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." + +# A hosted project ref is a long opaque token; `your-project.supabase.co` in an +# example file is a placeholder and stays legal. +PATTERN='supabase\.com/dashboard|app\.supabase\.com|pooler\.supabase\.com|[a-z0-9]{15,}\.supabase\.co' + +# docs/archive/ is a historical record of the hosted era — it is supposed to +# describe it. Everything else is read as current instruction. +hits=$(git ls-files -z \ + | grep -zZv -e '^docs/archive/' -e '^scripts/ci/no-hosted-supabase\.sh$' \ + | xargs -0 grep -nEI "$PATTERN" 2>/dev/null || true) + +if [ -n "$hits" ]; then + echo "✗ hosted-Supabase reference(s) found — this repo is self-hosted on bitbaum:" >&2 + echo "$hits" >&2 + echo >&2 + echo " API URL is https://supabase.orangecat.ch and migrations apply on deploy." >&2 + echo " See docs/SUPABASE_SETUP.md. If a line is a historical record, move it" >&2 + echo " under docs/archive/ rather than weakening this check." >&2 + exit 1 +fi + +echo "✓ no hosted-Supabase references" diff --git a/scripts/run-migration-009.ts b/scripts/run-migration-009.ts deleted file mode 100644 index 566b3f42..00000000 --- a/scripts/run-migration-009.ts +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env npx tsx -/** - * Run Migration 009 - User Centric Architecture - * - * Executes the migration using Supabase's SQL execution capabilities - */ - -import * as dotenv from 'dotenv'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -dotenv.config({ path: join(process.cwd(), '.env.local') }); - -const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; -const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY; - -if (!supabaseUrl || !supabaseKey) { - console.error('Missing NEXT_PUBLIC_SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY'); - process.exit(1); -} - -// Read migration -const migrationPath = join(process.cwd(), 'supabase/migrations/009_user_centric.sql'); -const fullSql = readFileSync(migrationPath, 'utf-8'); - -console.log('🚀 Running migration 009_user_centric.sql...\n'); - -// Split into individual statements -const statements = fullSql - .split(/;[\s]*\n/) - .map((s) => s.trim()) - .filter((s) => s.length > 0 && !s.match(/^--/)); - -async function runStatement(sql: string): Promise<{ success: boolean; error?: string }> { - try { - // Use Supabase's SQL execution endpoint - const response = await fetch(`${supabaseUrl}/rest/v1/rpc/`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - apikey: supabaseKey!, - Authorization: `Bearer ${supabaseKey}`, - Prefer: 'return=minimal', - }, - body: JSON.stringify({}), - }); - - // This won't work for DDL, so let's use a different approach - return { success: false, error: 'RPC not suitable for DDL' }; - } catch (err) { - return { success: false, error: String(err) }; - } -} - -// For Supabase, we need to use the Management API or direct DB connection -// Let's try the postgres connection string approach - -async function main() { - // Extract project ref from URL - const projectRef = supabaseUrl!.replace('https://', '').split('.')[0]; - - console.log(`Project: ${projectRef}`); - console.log(`Statements to execute: ${statements.length}`); - console.log(''); - - // Since we can't run DDL via REST API, output instructions - console.log('⚠️ Supabase REST API cannot execute DDL statements directly.'); - console.log(''); - console.log('Options:'); - console.log('1. Run via Supabase Dashboard SQL Editor'); - console.log(` URL: https://supabase.com/dashboard/project/${projectRef}/sql/new`); - console.log(''); - console.log('2. Use Supabase CLI with access token:'); - console.log(' npx supabase login'); - console.log(` npx supabase link --project-ref ${projectRef}`); - console.log(' npx supabase db push'); - console.log(''); - console.log( - '3. Connect directly with psql (need DB password from Supabase Dashboard > Settings > Database):', - ); - console.log( - ` psql "postgresql://postgres.${projectRef}:[YOUR-PASSWORD]@aws-0-eu-central-1.pooler.supabase.com:6543/postgres" -f supabase/migrations/009_user_centric.sql`, - ); - console.log(''); - - // Let's try to see if there's a way to get the connection string - console.log('Checking for database password in Supabase settings...'); - - // Try to fetch from the settings API - try { - const settingsResponse = await fetch(`${supabaseUrl}/rest/v1/`, { - headers: { - apikey: supabaseKey!, - Authorization: `Bearer ${supabaseKey}`, - }, - }); - console.log('REST API accessible:', settingsResponse.ok); - } catch (err) { - console.log('Could not reach REST API'); - } -} - -main().catch(console.error); diff --git a/supabase/.temp/cli-latest b/supabase/.temp/cli-latest deleted file mode 100644 index 9b07af9e..00000000 --- a/supabase/.temp/cli-latest +++ /dev/null @@ -1 +0,0 @@ -v2.72.7 \ No newline at end of file diff --git a/supabase/.temp/gotrue-version b/supabase/.temp/gotrue-version deleted file mode 100644 index 6d9afda6..00000000 --- a/supabase/.temp/gotrue-version +++ /dev/null @@ -1 +0,0 @@ -v2.185.0 \ No newline at end of file diff --git a/supabase/.temp/pooler-url b/supabase/.temp/pooler-url deleted file mode 100644 index 73a367b5..00000000 --- a/supabase/.temp/pooler-url +++ /dev/null @@ -1 +0,0 @@ -postgresql://postgres.jkjmhtirxwhljpkcfxqe@aws-1-eu-west-1.pooler.supabase.com:5432/postgres \ No newline at end of file diff --git a/supabase/.temp/postgres-version b/supabase/.temp/postgres-version deleted file mode 100644 index 3dc41f46..00000000 --- a/supabase/.temp/postgres-version +++ /dev/null @@ -1 +0,0 @@ -17.6.1.063 \ No newline at end of file diff --git a/supabase/.temp/project-ref b/supabase/.temp/project-ref deleted file mode 100644 index 9edf537c..00000000 --- a/supabase/.temp/project-ref +++ /dev/null @@ -1 +0,0 @@ -jkjmhtirxwhljpkcfxqe \ No newline at end of file diff --git a/supabase/.temp/rest-version b/supabase/.temp/rest-version deleted file mode 100644 index 35204367..00000000 --- a/supabase/.temp/rest-version +++ /dev/null @@ -1 +0,0 @@ -v14.1 \ No newline at end of file diff --git a/supabase/.temp/storage-migration b/supabase/.temp/storage-migration deleted file mode 100644 index 5a41722d..00000000 --- a/supabase/.temp/storage-migration +++ /dev/null @@ -1 +0,0 @@ -buckets-objects-grants-postgres \ No newline at end of file diff --git a/supabase/.temp/storage-version b/supabase/.temp/storage-version deleted file mode 100644 index 89c19bef..00000000 --- a/supabase/.temp/storage-version +++ /dev/null @@ -1 +0,0 @@ -v1.33.0 \ No newline at end of file diff --git a/supabase/migrations/001_initial_schema.sql b/supabase/migrations/001_initial_schema.sql index e911dfd7..d01d4a79 100644 --- a/supabase/migrations/001_initial_schema.sql +++ b/supabase/migrations/001_initial_schema.sql @@ -1,5 +1,5 @@ -- Botsmann Initial Schema --- Run this in Supabase SQL Editor: https://supabase.com/dashboard/project/_/sql +-- Applied automatically on deploy into the `botsmann` schema; see docs/SUPABASE_SETUP.md. -- Enable pgvector extension for future vector search CREATE EXTENSION IF NOT EXISTS vector; diff --git a/supabase/migrations/supabase/.temp/cli-latest b/supabase/migrations/supabase/.temp/cli-latest deleted file mode 100644 index 9b07af9e..00000000 --- a/supabase/migrations/supabase/.temp/cli-latest +++ /dev/null @@ -1 +0,0 @@ -v2.72.7 \ No newline at end of file diff --git a/supabase/migrations/supabase/.temp/gotrue-version b/supabase/migrations/supabase/.temp/gotrue-version deleted file mode 100644 index 6d9afda6..00000000 --- a/supabase/migrations/supabase/.temp/gotrue-version +++ /dev/null @@ -1 +0,0 @@ -v2.185.0 \ No newline at end of file diff --git a/supabase/migrations/supabase/.temp/pooler-url b/supabase/migrations/supabase/.temp/pooler-url deleted file mode 100644 index 73a367b5..00000000 --- a/supabase/migrations/supabase/.temp/pooler-url +++ /dev/null @@ -1 +0,0 @@ -postgresql://postgres.jkjmhtirxwhljpkcfxqe@aws-1-eu-west-1.pooler.supabase.com:5432/postgres \ No newline at end of file diff --git a/supabase/migrations/supabase/.temp/postgres-version b/supabase/migrations/supabase/.temp/postgres-version deleted file mode 100644 index 3dc41f46..00000000 --- a/supabase/migrations/supabase/.temp/postgres-version +++ /dev/null @@ -1 +0,0 @@ -17.6.1.063 \ No newline at end of file diff --git a/supabase/migrations/supabase/.temp/project-ref b/supabase/migrations/supabase/.temp/project-ref deleted file mode 100644 index 9edf537c..00000000 --- a/supabase/migrations/supabase/.temp/project-ref +++ /dev/null @@ -1 +0,0 @@ -jkjmhtirxwhljpkcfxqe \ No newline at end of file diff --git a/supabase/migrations/supabase/.temp/rest-version b/supabase/migrations/supabase/.temp/rest-version deleted file mode 100644 index 35204367..00000000 --- a/supabase/migrations/supabase/.temp/rest-version +++ /dev/null @@ -1 +0,0 @@ -v14.1 \ No newline at end of file diff --git a/supabase/migrations/supabase/.temp/storage-migration b/supabase/migrations/supabase/.temp/storage-migration deleted file mode 100644 index 5a41722d..00000000 --- a/supabase/migrations/supabase/.temp/storage-migration +++ /dev/null @@ -1 +0,0 @@ -buckets-objects-grants-postgres \ No newline at end of file diff --git a/supabase/migrations/supabase/.temp/storage-version b/supabase/migrations/supabase/.temp/storage-version deleted file mode 100644 index 89c19bef..00000000 --- a/supabase/migrations/supabase/.temp/storage-version +++ /dev/null @@ -1 +0,0 @@ -v1.33.0 \ No newline at end of file