M0: DB schema, RLS policies, JWT claims hook, seed, Supabase clients

Adds db/schema.sql (12 tables), db/policies.sql (RLS on all 12,
audit_log append-only), db/auth-hook.sql (role/org_id into JWT per
AD-2), db/seed.sql (org + 3 departments, part 2 deferred to M1 auth).
Wires lib/supabase/{client,server,service}.ts per AD-3 and adds
/db-check page confirming DB connectivity and RLS deny-by-default.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FcktbLXSSXzx23GCue813e
This commit is contained in:
Weei Han
2026-07-30 19:00:24 +08:00
co-authored by Claude Sonnet 5
parent 680b6a0194
commit f539d43136
10 changed files with 762 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
import { createBrowserClient } from "@supabase/ssr";
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
+28
View File
@@ -0,0 +1,28 @@
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
export async function createClient() {
const cookieStore = await cookies();
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll();
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
);
} catch {
// setAll was called from a Server Component (cookies are read-only there).
// Safe to ignore as long as session refresh also runs in middleware.
}
},
},
}
);
}
+19
View File
@@ -0,0 +1,19 @@
import { createClient as createSupabaseClient } from "@supabase/supabase-js";
// Service-role client. Bypasses RLS entirely.
// Only ever import this inside /app/api/* route handlers, after the
// route has manually verified the caller's session and role (AD-3).
// Never import this in a client component or a plain read path.
export function createServiceClient() {
return createSupabaseClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{
auth: {
persistSession: false,
autoRefreshToken: false,
detectSessionInUrl: false,
},
}
);
}