chore: improve Supabase migrations via CLI after login and fix compatibility issues

- Update supabase/push-migrations.js:
  - Detect modern Supabase CLI link state (supabase/.temp/project-ref)
  - Prefer `supabase db query --linked --file` (works in this env where direct postgres connections fail with ENOTFOUND/network unreachable)
  - Updated docs/comments for `supabase login` + `supabase link --project-ref wnzkhezyhnfzhkhiflrp` workflow

- Add MEMORY.md capturing the Supabase login/link session, tooling changes, migration patches applied, and gotchas

- Patch migrations for current remote schema (column drift, syntax, idempotency, pre-existing tables):
  - 091_brand_plan_tier.sql: fix extra paren in get_brand_plan_info
  - 145_create_product_images_bucket.sql: allowed_mime_types + DROP POLICY IF EXISTS + safer bucket insert
  - 148_public_stops_rpc.sql: quote reserved "time" column in RETURNS TABLE + SELECT
  - 200_production_features.sql: add ALTER TABLE for user_activity_logs (originated in 036) so policies/indexes validate
  - 201_seed_data.sql: trim demo seeds with outdated column lists (products/stops/etc.); keep only compatible brands insert

- Include 202_fix_admin_create_stop.sql and related stop creation updates (src/actions/stops/create-stop.ts, 147_admin_create_stop_rpcs.sql, ADMIN_CREATE_STOP_FIX.sql)

- Update CLAUDE.md with pointer to MEMORY.md for recent migration work

Applied via the new flow (after supabase login + link): 084, 091, 142–148, 200–202 etc.

Refs: Supabase CLI now linked; use `node supabase/push-migrations.js <prefix>` or `npm run migrate:one NNN`
This commit is contained in:
2026-06-03 15:11:42 +00:00
parent f155bf6f5c
commit ba94d755fa
12 changed files with 653 additions and 296 deletions
+33 -19
View File
@@ -3,19 +3,21 @@
* push-migrations.js
*
* Pushes migration files to the linked Supabase project.
* Uses the Supabase CLI if available (supabase db push),
* Uses the Supabase CLI (supabase db query --linked --file) if the project
* is linked (after `supabase login` + `supabase link --project-ref <ref>`),
* otherwise falls back to direct PostgreSQL connection via `pg`.
*
* Usage:
* node supabase/push-migrations.js # push all pending migrations
* node supabase/push-migrations.js 082 # push only migration 082
* node supabase/push-migrations.js # push all migration files
* node supabase/push-migrations.js 148 # push only migrations matching 148_*.sql
*
* Prerequisites for CLI mode:
* brew install supabase/tap/supabase # install CLI
* supabase link --project-ref <ref> # link project once
* Prerequisites for CLI mode (preferred, works even without direct 5432 access):
* supabase login
* supabase link --project-ref wnzkhezyhnfzhkhiflrp
*
* Prerequisites for direct PG mode:
* npm install # pg and dotenv already in devDependencies
* .env.local with NEXT_PUBLIC_SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY
* (pg and dotenv are in devDependencies)
*/
const { Client } = require("pg");
@@ -35,17 +37,25 @@ const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
async function pushWithCli(files) {
console.log("Using Supabase CLI (supabase db push)...\n");
const joined = files.map((f) => `supabase/migrations/${f}`).join(" ");
try {
execSync(
`supabase db push --db-url "postgresql://postgres:${serviceRoleKey}@db.wnzkhezyhnfzhkhiflrp.supabase.co:5432/postgres" ${joined}`,
{ stdio: "inherit", cwd: path.resolve(__dirname, "..") }
);
return true;
} catch (err) {
return false;
console.log("Using Supabase CLI (supabase db query --linked --file)...\n");
for (const f of files) {
const filePath = `supabase/migrations/${f}`;
process.stdout.write(` Applying ${f}... `);
try {
execSync(
`supabase db query --linked --file "${filePath}"`,
{ stdio: "inherit", cwd: path.resolve(__dirname, "..") }
);
console.log("✓");
} catch (err) {
console.log("✗");
// execSync with inherit already printed stderr/stdout; surface a short message
const msg = (err && err.message) ? err.message.replace(/\n/g, " ").slice(0, 200) : "";
if (msg) console.error(" " + msg);
return false;
}
}
return true;
}
async function pushWithPg(sql, migrationFile) {
@@ -102,14 +112,18 @@ async function main() {
let ok = false;
// Try CLI first if supabase is linked (has .supabase/config.toml)
// Try CLI first if supabase is linked.
// Legacy link: .supabase/config.toml at project root
// Modern link (post `supabase link`): supabase/.temp/project-ref
let hasSupabaseCli = false;
try {
hasSupabaseCli = !!execSync("which supabase", { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
} catch {
hasSupabaseCli = false;
}
const isLinked = fs.existsSync(path.resolve(__dirname, "../.supabase/config.toml"));
const hasLegacyLink = fs.existsSync(path.resolve(__dirname, "../.supabase/config.toml"));
const hasModernLink = fs.existsSync(path.resolve(__dirname, ".temp/project-ref"));
const isLinked = hasLegacyLink || hasModernLink;
if (hasSupabaseCli && isLinked) {
console.log("Supabase CLI detected and project is linked.\n");