Commit Graph

3 Commits

Author SHA1 Message Date
wmj a0c70e1411 Add estate agent delegation: real accounts, multi-tenant backend, RLS-enforced roles
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.
2026-08-13 21:07:23 +08:00
wmj 4d244db6d0 Add (i) info button to every tab, explained for the average user
New InfoPanel.svelte: shared (i) button next to each module's h2, toggling
a plain-language explainer with three sections — what this tab is, how to
use it, what to enter in each field. One component so tone stays
consistent across all 10 tabs instead of each screen inventing its own
help pattern.

Deliberately avoids fiqh/legal jargon in favor of concrete, everyday
framing (e.g. Hibah explained as "a gift you give right now, while you're
alive" rather than leading with the Arabic term) — written for someone
with no prior estate-planning or Islamic finance background, consistent
with the "convince a 100-year-old grandmother" usability bar already
established for this product.

Wired into: Coverage, Faraid, Assets, Wassiyah, Hibah, Family Waqf,
Nominate, Trigger, Claims (H2), Settings.

e2e-info.cjs: new suite verifying the info button appears, opens a
non-trivial explanation, and closes again on every one of the 10 tabs.
31/31 passing. Re-verified all five prior suites (32/32, 16/16, 12/12,
10/10, 10/10) — 111/111 total, no regressions.
2026-08-13 18:14:28 +08:00
wmj 6690696f7f Initial build: Horizon 1 Prevention Suite + Horizon 2 Unlock demo
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.
2026-08-13 16:55:58 +08:00