Big round covering two different asks: Khairat/emergency infrastructure
(tightly coupled to what's already built) and a Muslim-lifestyle
companion surface (a genuinely different product, added at the user's
explicit request after being offered a smaller scope).
Khairat & emergency contacts:
- nf_khairat_memberships (per-member scheme membership) + nf_emergency_fund
(per-family shared reserve tracker) — records intent/contacts only,
never holds or moves real money.
- nf_trusted_contacts gains category (mosque/police/ambulance/hospital/
khairat/family/other) and email columns.
- New notify-emergency-contacts Edge Function, auto-invoked the moment a
mutawalli fires a member's death trigger (the one place in this app
where auto-send-on-trigger is actually correct), alongside — not
instead of — the existing heir notification. Verified with a live fire
end-to-end (e2e-emergency-notify.cjs, 5/5).
Lifestyle-companion tabs — all computed/searched live, nothing fabricated:
- Qibla: pure great-circle bearing math to the Kaaba from geolocation,
no API/key. Verified against Kuala Lumpur (293°, matches expected ~292°).
- Prayer Times: client-side astronomical calculation (single-pass solar
position, MWL angles), sanity-checked against known KL/London times
before shipping.
- Locate: mosque/halal/cemetery search via the free, keyless OpenStreetMap
Overpass API — real community-sourced results only, honest empty state
when nothing's mapped nearby.
- Quran: Surah list + Arabic/translation via the free alquran.cloud API,
fetched fresh each time, nothing stored in this app's own database.
- Neighbourhood: a join-by-code community announcement board — a
genuinely separate multi-tenant concept from the estate-planning family
structure, scoped to the user account. Found and fixed a real UX gap
during testing: the create/join form was only reachable with zero
existing neighbourhoods, with no way to join a second one.
Also found and fixed a real bug: the heir-notify and emergency-notify
status messages shared the same CSS class, breaking any script (including
the pre-existing e2e-per-member.cjs) that targeted '.notify-status'
without further filtering — gave each its own distinguishing class.
Covered by e2e-khairat-lifestyle.cjs (13/13) and e2e-emergency-notify.cjs
(5/5). Full regression: 316/316 across all suites (several transient
flakes under heavy mail-relay load during the sweep, all confirmed clean
on rerun — one led to the real class-collision fix above).