Membership
:::info Status
Implemented. Source: fastapi-backend/api/v1/endpoints/{memberships,invites,join}.py, core/mosque_registration.py.
:::
The memberships table records a user's relationship to one mosque —
distinct from Mosque Management's admin
relationship, and distinct from Device or
App Install ownership. An approved
membership is what Playback Entitlement
is ultimately derived from.
Status state machine
Valid statuses: pending, approved, rejected, banned
(core/db.py:VALID_MEMBERSHIP_STATUSES). Only an admin (mosque admin for
that mosque, or superadmin) may change status — a member can only edit
their own notification toggles (notify_azaan, notify_jummah,
notify_waaz, notify_announcement). This split exists specifically so a
banned member can't PATCH themself back to approved.
Every status change an admin makes (not the member acting on themself)
fires an Expo push notification to the affected member, with copy specific
to the transition (e.g. "Membership restored" when moving banned →
approved, vs. "Membership approved" for pending → approved).
Three ways to become a member
| Path | Endpoint | Resulting status |
|---|---|---|
| Self-service join | POST /mosques/{id}/join | approved if the mosque has auto_approve_members, else pending |
| Join by code | POST /join (body: code) | Same auto-approve logic, resolved via db.get_mosque_by_join_code |
| Admin adds directly | POST /mosques/{mosque_id}/memberships | Always approved immediately — there is no admin-initiated pending state |
| Admin invites by contact | POST /invites (email or WhatsApp/phone contact) | approved if auto_approve requested, else pending; creates the user account first if none exists for that contact |
Joining (self-service or by code) makes the target mosque the user's
only active mosque — a previous mosque's membership is demoted in the
same transaction so it stops triggering azaan for that user
(core/mosque_registration.py:register_user_with_mosque).
Invite edge case: promoting an existing member to admin
POST /invites with role: "mosque_admin" against a contact that already
has an approved membership at the mosque doesn't create a second
membership — it adds a mosque-admin row for the existing member
(is_owner: false, can_trigger: true, can_manage: true) and returns a 409
if they're already an admin. mosque_admin role invites require
auto_approve: true — you can't invite a pending admin.
Leaving / removing
DELETE /memberships/{id} — the member themself, or a mosque admin/
superadmin for that mosque.
API
| Endpoint | Purpose |
|---|---|
GET /memberships | Current user's own memberships, filterable by status/mosque |
PATCH /memberships/{id} | Update status (admin) or notification toggles (member, own membership only) |
DELETE /memberships/{id} | Leave / remove a membership |
GET /mosques/{mosque_id}/memberships | Admin view of a mosque's memberships |
Full request/response schemas: API Reference.