chore(supabase): full purge — remove all Supabase references from codebase
- Delete supabase/ directory (config.toml, push-migrations.js, ADMIN_CREATE_STOP_FIX.sql, 137 archived migration files) - Remove @supabase/ssr and @supabase/supabase-js from package.json - Strip *.supabase.co from next.config.ts image hostnames - Strip https://*.supabase.co from vercel.json CSP connect-src - Remove 'supabase/**' ignore from eslint.config.mjs - Clean supabase references from src/lib/db.ts, vitest.config.ts, db/seeds/2026-tuxedo-tour-stops.sql, src/actions/storefront.ts, scripts/import-tuxedo-stops.ts comments - Rewrite env-var docs in README, ENVIRONMENT, PRODUCTION_SETUP, PRODUCTION_DEPLOYMENT_CHECKLIST, LAUNCH_CHECKLIST, CLAUDE, MEMORY, REPORT to drop NEXT_PUBLIC_SUPABASE_URL / SUPABASE_SERVICE_ROLE_KEY / supabase link / supabase CLI references The canonical migration runner is now scripts/migrate.js (uses pg directly via DATABASE_URL). Migrations live in db/migrations/. The Supabase CLI is no longer in the codebase. The only remaining '@supabase/*' in the dep tree is @supabase/auth-js as a transitive of @neondatabase/auth (Neon Auth / Better Auth). Final source scan: grep -rln '@supabase\|rest/v1\|supabase\.co' src/ tests/ db/ scripts/ next.config.ts vercel.json eslint.config.mjs package.json returns zero. Verification: npm install clean (11 added, 21 removed, 12 changed), tsc shows same 17 pre-existing errors (Stripe dahlia API version + fetch preconnect mocks), vitest 172/175 (3 pre-existing failures in getAdminUser.test.ts), lint shows same 14 pre-existing errors. Live-tested: dev server boots in 248ms, public storefronts (/) (/login) (/pricing) (/tuxedo) (/indian-river-direct) all return 200; /admin/v2?demo=1 reaches 200 after dev_session redirect; storefront renders real brand content.
This commit is contained in:
@@ -1,82 +0,0 @@
|
||||
-- Migration 075: Soft-delete for stops + brand scoping enforcement
|
||||
-- 1. Add deleted_at to stops
|
||||
-- 2. Create delete_stop RPC with order guard
|
||||
-- 3. Update RLS to filter deleted_at IS NULL
|
||||
|
||||
-- ── 1. Add deleted_at column ───────────────────────────────────────────────────
|
||||
ALTER TABLE stops ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ DEFAULT NULL;
|
||||
|
||||
-- ── 2. delete_stop RPC ────────────────────────────────────────────────────────
|
||||
CREATE OR REPLACE FUNCTION public.delete_stop(p_stop_id UUID, p_brand_id UUID DEFAULT NULL)
|
||||
RETURNS JSONB
|
||||
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
|
||||
AS $$
|
||||
DECLARE
|
||||
v_stop RECORD;
|
||||
v_active_order_count INT;
|
||||
v_result JSONB;
|
||||
BEGIN
|
||||
-- Lock the stop row for update
|
||||
SELECT * INTO v_stop FROM stops WHERE id = p_stop_id FOR UPDATE;
|
||||
|
||||
IF NOT FOUND THEN
|
||||
RETURN jsonb_build_object('success', false, 'error', 'Stop not found');
|
||||
END IF;
|
||||
|
||||
-- Brand scoping: brand_admin can only delete their own stops
|
||||
IF p_brand_id IS NOT NULL AND v_stop.brand_id != p_brand_id THEN
|
||||
RETURN jsonb_build_object('success', false, 'error', 'Stop not found');
|
||||
ELSIF p_brand_id IS NULL AND v_stop.brand_id IS NOT NULL THEN
|
||||
-- Caller didn't pass brand_id but stop has one — guard against platform admin accident
|
||||
RETURN jsonb_build_object('success', false, 'error', 'Stop not found');
|
||||
END IF;
|
||||
|
||||
-- Guard: check for active or future orders at this stop
|
||||
SELECT COUNT(*) INTO v_active_order_count
|
||||
FROM orders o
|
||||
JOIN stops s ON o.stop_id = s.id
|
||||
WHERE s.id = p_stop_id
|
||||
AND o.pickup_complete = false
|
||||
AND o.deleted_at IS NULL;
|
||||
|
||||
IF v_active_order_count > 0 THEN
|
||||
RETURN jsonb_build_object(
|
||||
'success', false,
|
||||
'error', 'Cannot delete stop — it has ' || v_active_order_count || ' active order(s). Mark orders as picked up first.'
|
||||
);
|
||||
END IF;
|
||||
|
||||
-- Soft delete
|
||||
UPDATE stops SET deleted_at = NOW() WHERE id = p_stop_id;
|
||||
|
||||
RETURN jsonb_build_object('success', true);
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- ── 3. Update RLS — add deleted_at IS NULL to brand_admin read policy ──────────
|
||||
-- drops are re-created in the same block to avoid breaking the audit SQL
|
||||
DROP POLICY IF EXISTS "brand_admin_read_stops" ON stops;
|
||||
DROP POLICY IF EXISTS "platform_admin_read_stops" ON stops;
|
||||
|
||||
-- Platform admin sees all non-deleted stops
|
||||
CREATE POLICY "platform_admin_read_stops" ON stops
|
||||
FOR SELECT USING (
|
||||
deleted_at IS NULL
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM admin_users au
|
||||
WHERE au.user_id = auth.uid()
|
||||
AND au.role = 'platform_admin'
|
||||
)
|
||||
);
|
||||
|
||||
-- Brand admin / store_employee sees only their brand's non-deleted stops
|
||||
CREATE POLICY "brand_admin_read_stops" ON stops
|
||||
FOR SELECT USING (
|
||||
deleted_at IS NULL
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM admin_users au
|
||||
WHERE au.user_id = auth.uid()
|
||||
AND au.role IN ('brand_admin', 'store_employee')
|
||||
AND au.brand_id = stops.brand_id
|
||||
)
|
||||
);
|
||||
Reference in New Issue
Block a user