Practitioner Notifications (Supabase Edge Function)¶
This function sends practitioner emails for:
- patient protocol acceptance
- patient lab sharing
- adherence alert (<50% for 3+ trailing days)
- weekly summary
Required secrets¶
Set these before deploy:
supabase secrets set \
SENDGRID_API_KEY=SG.xxxxx \
NOTIFY_FROM_EMAIL="Onset Clinic <notifications@theonset.app>" \
NOTIFY_FUNCTION_SECRET=your_shared_secret \
ONSET_IOS_APP_STORE_URL="https://apps.apple.com/us/app/the-onset/id6761314183"
Optional: set NEXT_PUBLIC_ONSET_IOS_APP_STORE_URL in the clinic portal for the same App Store link on patient handout PDFs.
SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY are injected by Supabase automatically in hosted Edge Functions.
Deploy¶
Staging (Onset-staging, lzpyfohgfdohrtlamzek)¶
Staging starts with no edge functions. Run once from the clinic portal repo:
cp supabase/.env.staging.example supabase/.env.staging # add SENDGRID_API_KEY
./scripts/supabase/deploy-staging-notifications.sh
See docs/ENVIRONMENTS.md for the full staging email checklist.
Invoke payloads¶
Trigger examples (database webhooks via pg_net)¶
Run this SQL in Supabase SQL editor after enabling pg_net:
create extension if not exists pg_net;
create or replace function public.notify_protocol_accepted()
returns trigger
language plpgsql
security definer
as $$
begin
if new.status = 'accepted' and (old.status is distinct from new.status) then
perform net.http_post(
url := current_setting('app.settings.supabase_url') || '/functions/v1/practitioner-notifications',
headers := jsonb_build_object(
'Content-Type', 'application/json',
'x-notify-secret', current_setting('app.settings.notify_function_secret')
),
body := jsonb_build_object(
'eventType', 'protocol_accepted',
'assignmentId', new.id
)
);
end if;
return new;
end;
$$;
drop trigger if exists trg_notify_protocol_accepted on public.protocol_assignments;
create trigger trg_notify_protocol_accepted
after update on public.protocol_assignments
for each row execute function public.notify_protocol_accepted();
create or replace function public.notify_lab_shared()
returns trigger
language plpgsql
security definer
as $$
begin
perform net.http_post(
url := current_setting('app.settings.supabase_url') || '/functions/v1/practitioner-notifications',
headers := jsonb_build_object(
'Content-Type', 'application/json',
'x-notify-secret', current_setting('app.settings.notify_function_secret')
),
body := jsonb_build_object(
'eventType', 'lab_shared',
'labResultId', new.id
)
);
return new;
end;
$$;
drop trigger if exists trg_notify_lab_shared on public.shared_lab_results;
create trigger trg_notify_lab_shared
after insert on public.shared_lab_results
for each row execute function public.notify_lab_shared();
create or replace function public.notify_adherence_shared()
returns trigger
language plpgsql
security definer
as $$
begin
perform net.http_post(
url := current_setting('app.settings.supabase_url') || '/functions/v1/practitioner-notifications',
headers := jsonb_build_object(
'Content-Type', 'application/json',
'x-notify-secret', current_setting('app.settings.notify_function_secret')
),
body := jsonb_build_object(
'eventType', 'adherence_shared',
'practitionerId', new.practitioner_id,
'patientAppUserId', new.patient_app_user_id
)
);
return new;
end;
$$;
drop trigger if exists trg_notify_adherence_shared on public.shared_adherence;
create trigger trg_notify_adherence_shared
after insert on public.shared_adherence
for each row execute function public.notify_adherence_shared();
Weekly summary scheduling¶
Create a Supabase cron job:
select cron.schedule(
'practitioner-weekly-summary',
'0 15 * * 1',
$$
select net.http_post(
url := current_setting('app.settings.supabase_url') || '/functions/v1/practitioner-notifications',
headers := jsonb_build_object(
'Content-Type', 'application/json',
'x-notify-secret', current_setting('app.settings.notify_function_secret')
),
body := jsonb_build_object('eventType', 'weekly_summary')
);
$$
);