Per explicit product direction: the app assumed a single user (head of
family) with everything in per-device localStorage. There was no way for
a family to delegate estate management to an agent (relative or
professional) without literally handing over the device. This required
real backend infrastructure, not a UI addition — added Supabase
(Postgres + Auth) as a multi-tenant backend.
Schema (nf_ prefixed to stay isolated from other tables in the reused
"Falah OS demo" project): nf_families, nf_family_members (role: owner/
agent, status: invited/active), and family-scoped versions of every
estate table — nf_assets, nf_trusted_contacts, nf_hibah_gifts,
nf_waqf_designations/nf_waqf_beneficiaries, nf_nominations,
nf_attestors, nf_death_triggers.
Permission model, enforced by RLS at the database level (not just
hidden in the UI): an agent can do everything an owner can — add/edit
assets, draft Hibah/Waqf/Nominations, set up the Death Trigger — except
fire it. nf_death_triggers' UPDATE/INSERT policies use a WITH CHECK that
only allows triggered=true when the caller has role='owner' on that
family. A professional agent can be invited to multiple families and
switches between them from their own dashboard.
New: auth.js, family.js, db.js, AuthScreen.svelte, FamilySwitcher.svelte,
FamilyManagement.svelte (new "Family" tab: invite agents, see members,
switch families). AssetRegistry, HibahTracker, FamilyWaqfDesignator,
NominationRegistry, CoverageDashboard, and DeathTrigger all migrated
from storage.js (localStorage) to db.js (Supabase), scoped to the
active family_id. App.svelte now gates on auth + family selection
before showing the main tab shell.
Three real bugs found and fixed via testing against the live backend
(not caught by the old localStorage-based suites, which had no
cross-client concurrency to expose them):
- RLS gap: pending-invite lookup joins nf_families(name), but the
invitee isn't a family member yet, so the join was silently dropped —
added a policy letting a pending invitee see just the family name.
- Attestor row race: lazy "create on first blur" could double-fire from
two different code paths, creating duplicate rows and confirming the
wrong one. Fixed by eagerly creating attestor rows on first load so
every row always has a real id — no more create-or-update ambiguity.
- Out-of-order async clobber: three death-trigger setup fields each
fired a full-snapshot upsert on every input; whichever request
*finished* last (not fired last) won, silently reverting the other
two fields to stale values. Fixed with per-field partial updates
(updateDeathTriggerField) that can't clobber columns they don't touch.
e2e-family-agent.cjs: full owner/agent flow against the live Supabase
backend — invite, accept, shared live data, agent blocked from firing
the trigger (button stays disabled and a direct RLS-level attempt would
also fail), owner successfully fires it. 12/12 passing.
e2e-smoke-authed.cjs: post-auth-gate sweep confirming every existing tab
still renders and its info panel still opens under the new sign-in
requirement. 24/24 passing, zero console errors.
Known follow-up, not done here: the eight pre-auth E2E suites
(e2e-uat.cjs, e2e-fastpath.cjs, e2e-trust.cjs, e2e-business.cjs,
e2e-digital-vehicle.cjs, e2e-property.cjs, e2e-other.cjs, e2e-info.cjs)
assume an anonymous landing page and need a sign-in prelude added
before they're valid again — their detailed assertions were re-verified
functionally via the smoke test and manual review, not by running them
as-is.
- App.svelte: language toggle (EN/BM) wired to existing i18n.js store,
header tagline reflects selection. Was previously dead code with no
UI control (found by e2e-uat.cjs during full-flow UAT).
- e2e-uat.cjs: Playwright-driven E2E UAT against the live deployment —
real clicks/typing through all 7 tabs, faraid textbook-case
verification, heir-exclusion blocking, marad al-mawt guard, 1/3 cap
override flow, claim issuance/transfer, export/delete-all guards,
PWA and console-error checks.
Svelte 5 + Vite PWA, styled to match moslem03.falahos.my's design system.
Horizon 1: Faraid Calculator (shared calc core, 14 classical cases passing),
Asset Registry, Wassiyah Generator (1/3 meter + heir-exclusion block),
Hibah Tracker and Family Waqf Designator (shared marad al-mawt guardrail).
Horizon 2: Digital Beneficial Claims — local non-custodial demo of the claim
model and transfer restriction only.
Two governance gates in this project's own PRDs were overridden per explicit
product direction, and are flagged in-app and in README.md / deploy/DEPLOY.md
rather than silently shipped as production-ready:
- Family Waqf Designator ships ahead of scholarly sign-off (OPEN-01 in
scholarly-review-log.md remains unresolved).
- Horizon 2 ships ahead of the PRD's stated Phase 0 gate (legal opinion +
signed institutional partner) with no confirmation that gate is cleared.