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:
@@ -1,5 +1,6 @@
|
||||
"use server";
|
||||
|
||||
import { revalidateTag } from "next/cache";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { svcHeaders } from "@/lib/svc-headers";
|
||||
import { getMockTableData } from "@/lib/mock-data";
|
||||
@@ -38,33 +39,86 @@ export async function createStop(
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
// Use anon key — the RPC is SECURITY DEFINER so it bypasses RLS regardless
|
||||
// of caller. This also means a missing SUPABASE_SERVICE_ROLE_KEY in
|
||||
// production no longer breaks stop creation.
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
// Preferred path: anon key + SECURITY DEFINER RPC (bypasses RLS, works even if
|
||||
// service role key is absent at runtime). See:
|
||||
// supabase/migrations/202_fix_admin_create_stop.sql
|
||||
// scripts/apply-admin-create-stop.js (run this locally with the keys you have)
|
||||
// supabase/ADMIN_CREATE_STOP_FIX.sql (exact prompt SQL for SQL editor)
|
||||
const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
|
||||
const res = await fetch(`${supabaseUrl}/rest/v1/rpc/admin_create_stop`, {
|
||||
method: "POST",
|
||||
headers: { ...svcHeaders(supabaseKey), "Content-Type": "application/json" },
|
||||
headers: { ...svcHeaders(anonKey), "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
p_active: data.active ?? false,
|
||||
p_address: data.address || null,
|
||||
p_brand_id: brandId,
|
||||
p_city: data.city,
|
||||
p_state: data.state,
|
||||
p_location: data.location,
|
||||
p_cutoff_time: data.cutoff_time || null,
|
||||
p_date: data.date,
|
||||
p_location: data.location,
|
||||
p_state: data.state,
|
||||
p_time: data.time,
|
||||
p_address: data.address ?? null,
|
||||
p_zip: data.zip ?? null,
|
||||
p_cutoff_time: data.cutoff_time ?? null,
|
||||
p_active: data.active ?? false,
|
||||
p_zip: data.zip || null,
|
||||
}),
|
||||
});
|
||||
|
||||
let usedFallback = false;
|
||||
|
||||
if (!res.ok) {
|
||||
const err = await res.text();
|
||||
return { success: false, error: `Failed: ${err}` };
|
||||
const errText = await res.text();
|
||||
const lower = errText.toLowerCase();
|
||||
const looksLikeMissingFn =
|
||||
lower.includes("pgrst202") ||
|
||||
lower.includes("admin_create_stop") ||
|
||||
lower.includes("could not find the function") ||
|
||||
lower.includes("function not found");
|
||||
|
||||
if (looksLikeMissingFn) {
|
||||
usedFallback = true;
|
||||
} else {
|
||||
return { success: false, error: `Failed: ${errText}` };
|
||||
}
|
||||
} else {
|
||||
const inserted = await res.json().catch(() => ({} as any));
|
||||
if (inserted && inserted.success === false) {
|
||||
// Our RPC returns structured errors as 200 + {success:false}
|
||||
const errMsg = inserted.error || "Failed to create stop";
|
||||
const lower = errMsg.toLowerCase();
|
||||
if (lower.includes("function") || lower.includes("not found") || lower.includes("pgrst")) {
|
||||
usedFallback = true;
|
||||
} else {
|
||||
return { success: false, error: errMsg };
|
||||
}
|
||||
} else {
|
||||
// Happy path from RPC (either old {id,slug} or new {success, stop_id})
|
||||
const stopId = inserted?.stop_id || inserted?.id || "";
|
||||
const effectiveBrandId = brandId || adminUser.brand_id;
|
||||
if (effectiveBrandId) {
|
||||
revalidateTag("stops", "default");
|
||||
revalidateTag(`brand:${effectiveBrandId}:stops`, "default");
|
||||
}
|
||||
return { success: true, id: stopId };
|
||||
}
|
||||
}
|
||||
|
||||
const inserted = await res.json();
|
||||
return { success: true, id: inserted?.id ?? "" };
|
||||
if (usedFallback) {
|
||||
// We cannot bypass the block_stops_mutations RLS policy via REST even with the service key.
|
||||
// The only reliable path is the SECURITY DEFINER RPC created by migration 202.
|
||||
// Tell the user exactly how to install it using only the keys they already have.
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
"The admin_create_stop database function is missing (this is why Add New Stop fails with function not found).\n\n" +
|
||||
"Fix using only the keys in your .env.local (no Supabase dashboard needed):\n" +
|
||||
" 1. On a machine that can reach your database (normal laptop usually works):\n" +
|
||||
" node scripts/apply-admin-create-stop.js\n" +
|
||||
" 2. Or: npm run migrate:one 202\n" +
|
||||
" 3. Or apply supabase/migrations/202_fix_admin_create_stop.sql via psql / Supabase CLI with --db-url.\n\n" +
|
||||
"After it succeeds, restart your dev server and Add New Stop will work.",
|
||||
};
|
||||
}
|
||||
|
||||
// Should not reach here
|
||||
return { success: false, error: "Unexpected state creating stop" };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user