Why
We have a backlog of registered volunteers — rows in the volunteer table,
created via the public "Become a Volunteer" form or coordinator import — who
have never created a login (User account). They can't sign in, see their
own profile, or get matched through the app. We want to invite all of them by
email to finish registering as a User with role: VOLUNTEER.
Today Volunteer has no direct link to User at all — the only path is
Volunteer.person → Person.users, and that link is frequently empty for
exactly this population.
Design decisions (already made)
- Account creation timing: eager. The
User row is created immediately
when the invite is sent (isActive: false, placeholder password), not
deferred until the person accepts. No schema/migration changes anticipated.
- Feature scope: one-off backfill only. No persisted coordinator-facing
"invite" button or per-volunteer endpoint — just a script that clears the
current backlog. The invite-acceptance flow itself (JWT + accept-invite
endpoint + FE page) is still a real, reusable piece of infrastructure; only
the triggering side is one-off for now.
Sub-issues
sdk
be
fe
Acceptance criteria
Why
We have a backlog of registered volunteers — rows in the
volunteertable,created via the public "Become a Volunteer" form or coordinator import — who
have never created a login (
Useraccount). They can't sign in, see theirown profile, or get matched through the app. We want to invite all of them by
email to finish registering as a
Userwithrole: VOLUNTEER.Today
Volunteerhas no direct link toUserat all — the only path isVolunteer.person→Person.users, and that link is frequently empty forexactly this population.
Design decisions (already made)
Userrow is created immediatelywhen the invite is sent (
isActive: false, placeholder password), notdeferred until the person accepts. No schema/migration changes anticipated.
"invite" button or per-volunteer endpoint — just a script that clears the
current backlog. The invite-acceptance flow itself (JWT + accept-invite
endpoint + FE page) is still a real, reusable piece of infrastructure; only
the triggering side is one-off for now.
Sub-issues
sdk
be
POST /usermust link to an existingPersonby email instead of creating a duplicate — fix: POST /user must link to an existing Person by email instead of creating a duplicate #923 (found while reviewing feat: volunteer self-registration with email confirmation fe#955; without this, new self-registrations keep recreating the same problem this epic backfills away)fe
Acceptance criteria
Volunteerrow with a usable person email and no linkedUserhas received an invite email
role: VOLUNTEERUsernecessary, it's called out explicitly with the reason)