;
+}
diff --git a/supabase/migrations/20260719215429_intake_tokens.sql b/supabase/migrations/20260719215429_intake_tokens.sql
new file mode 100644
index 0000000..0f1e3e1
--- /dev/null
+++ b/supabase/migrations/20260719215429_intake_tokens.sql
@@ -0,0 +1,14 @@
+-- One-time intake links: a token lets an unauthenticated parent fill out a
+-- student's intake. Reached only via server functions (service role); RLS on
+-- with no policies blocks all direct client access.
+CREATE TABLE IF NOT EXISTS public.intake_tokens (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ token TEXT NOT NULL UNIQUE,
+ student_id UUID NOT NULL REFERENCES public.students(id) ON DELETE CASCADE,
+ created_by UUID REFERENCES auth.users(id),
+ expires_at TIMESTAMPTZ NOT NULL,
+ used_at TIMESTAMPTZ,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+CREATE INDEX IF NOT EXISTS idx_intake_tokens_token ON public.intake_tokens(token);
+ALTER TABLE public.intake_tokens ENABLE ROW LEVEL SECURITY;