-- In-app notifications for applicants (admin adjudication → inbox). -- Best-effort insert after PUT/POST admin-result; full text duplicated for read UX. CREATE TABLE IF NOT EXISTS user_notifications ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), recipient_user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, type TEXT NOT NULL CHECK (type IN ('admin_application_decision')), title TEXT NOT NULL, body TEXT NOT NULL, application_id TEXT NOT NULL, related_initiative_id UUID REFERENCES initiatives(id) ON DELETE SET NULL, source_admin_result_id UUID REFERENCES application_admin_results(id) ON DELETE SET NULL, decision TEXT NOT NULL CHECK (decision IN ('approved','rejected')), merit_category_label TEXT, feedback_text TEXT NOT NULL DEFAULT '', rationale_text TEXT, read_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS user_notifications_inbox_idx ON user_notifications (recipient_user_id, created_at DESC); CREATE INDEX IF NOT EXISTS user_notifications_unread_idx ON user_notifications (recipient_user_id) WHERE read_at IS NULL;