Problem
Humanitarian aid to Gaza faces a catastrophic trust crisis. Billions of dollars are pledged globally but donors have no way to verify where funds actually land. Beneficiaries have no visibility into what aid is coming to their area. Aid hubs operate with minimal external accountability.
- Donor opacity: "I donated — now what?" Donors have no live view of transactions, hub performance, or beneficiary outcomes. Distrust kills future giving.
- Beneficiary invisibility: People in need can't check whether aid is allocated to their area, who their designated hub is, or what the status of their case is.
- Hub accountability gap: Distribution hubs operate without public performance records — no way to compare efficiency, flag bottlenecks, or surface high performers.
- Proof-of-delivery problem: There is no cryptographic or independently verifiable record linking a donation to a delivery event. Claims can't be challenged or verified.
- Language exclusion: Most aid transparency tools are English-only — failing the Arabic-speaking population they claim to serve.
Research & Discovery
- Sector analysis: Reviewed existing aid transparency efforts: UNOCHA Financial Tracking Service, GiveWell, and charity watchdogs. All focus on NGO-level reporting, not transaction-level public traceability.
- Trust mechanics research: Studied blockchain-based aid transparency projects (e.g., Building Blocks by UNHCR) — identified that cryptographic proof doesn't require a full blockchain; Merkle root generation over transaction batches achieves the same verifiability goal at a fraction of the cost.
- Arabic UX requirements: RTL layout support, bilingual toggle, and mobile-first design are non-negotiable for reaching the primary affected population.
- User roles mapped: Four distinct audiences require four distinct dashboards — donors, beneficiaries, hub operators, and platform admins.
Key insight: Trust isn't built with a charity report PDF. It's built by showing a live transaction feed, a verifiable Merkle proof, and a public hub performance ranking — all in the native language of the people it serves.
Solution & Approach
TrueAid is a public transparency dashboard where every aid transaction is visible, every hub is ranked by performance, and proof of delivery is cryptographically anchored.
Design pillars:
- Public by default — No login required to view the transaction feed, map, rankings, or beneficiary status
- Trust mechanics — Live transaction feed + daily Merkle root proofs + on-chain anchor references + snapshot checksums
- Role-specific dashboards — Tailored views for donors, beneficiaries, hub operators, and admins
- Bilingual first — Full EN/AR runtime toggle with RTL layout support — not a translation afterthought
Architectural decisions:
- Next.js App Router for SSR/SSG on public pages (fast load, SEO-friendly for transparency reports)
- Supabase RLS to cleanly separate public read paths from authenticated role-scoped routes
- Three Supabase client tiers: Anon (public reads), user-scoped (authenticated routes), admin (trusted ops) — no single client with blanket access
- Mapbox + OSM for the tactical operational map with deferred initialization (loads on viewport entry, not page load)
- Apache ECharts for status/trend charts and hub performance visualizations
- Merkle proof scripts — daily root generation, proof text redaction helper, snapshot CSV/JSON export with checksum
- Pre-registration mode —
NEXT_PUBLIC_PRE_REGISTRATION_MODE=truedefault for safe MVP launch before full auth rollout
Features & Functionality
Public Surfaces:
- Cinematic landing (
/) — Trust-first hero, credibility panel, featured urgent cases, three-step transparency flow, trust pre-check modal before donation intent - Live transaction feed (
/feed) — Expanded feed explorer with search, sort, stats, bookmarks, follow, and notification subscription - Operational map (
/map) — Full-screen map with cluster/completion/urgency HUD overlays - Rankings (
/rankings) — Public hub performance leaderboard - Search (
/search) — Cross-entity search (beneficiaries, transactions, hubs) - Public profiles (
/profiles/[username]) — Per-account analytics page - Beneficiary trace (
/beneficiaries/[id]) — Public beneficiary status and case history - Transaction trace (
/transactions/[tx_id]) — Full audit trail for a single transaction
Role Dashboards:
- Donor (
/donor) — Portfolio view of supported cases, impact summary, transaction history - Beneficiary (
/beneficiary) — Case status, aid allocation, hub contact, notification feed - Hub (
/hub) — Operational metrics, transaction management, beneficiary case queue, performance vs. benchmarks - Admin (
/admin) — Full ops summary, dispute management, fraud flags, moderation queue, role requests, audit log
Trust Mechanics (Hero Features):
Live Transaction Feed: Paginated cursor-based feed showing real-time aid transactions — amount, category, recipient hub, status, timestamp. Every transaction is individually traceable via /transactions/[tx_id]. No aggregates only — individual records are public.
Merkle Proof System: Daily batch proofs are generated over the transaction set. A script computes the Merkle root, which is referenced in the public dashboard trust panel alongside the latest snapshot checksum. An on-chain anchor reference provides an immutable timestamp. Donors can independently verify that the transaction data hasn't been altered.
Tactical Map with HUD: Operational map showing geographic aid distribution with overlaid HUD panels: cluster density, completion rate by zone, urgency level. Initializes on viewport entry (not page load) with event-driven refresh — no polling loop. Powered by Mapbox with OSM data.
Bilingual EN/AR with RTL: Runtime language toggle — not a reload, not a separate URL. Arabic layout switches to full RTL. Mobile header and hamburger drawer both support RTL natively. Bilingual support for all role dashboards, public pages, and auth flows.
Auth + Account System:
- OTP-based signup/signin (start + verify flow)
- Google OAuth callback
- Account settings (multi-page: preferences, security, profile)
- Secure HttpOnly session cookie (
trueaid_user_session) — bearer token not stored in localStorage
Design & UX
Design philosophy:
- Cinematic, credibility-forward landing — first impression must communicate trust before any data is shown
- Trust pre-check modal before donation intent — friction by design to ensure informed giving
- Data-dense dashboards that remain navigable on mobile
- Dark/light mode — system-aware on first load, user-persisted thereafter
Key UI decisions:
- Trust pre-check modal: Appears before any donation CTA — shows the transparency score, last audit date, and verification status of the recipient hub. Deliberate friction to build confidence, not bypass it.
- Tactical map deferred load: Map initializes on viewport entry, not page load — prevents the map from blocking critical above-the-fold content.
- RTL-first layout components: Header, drawer, and all dashboard panels were designed to support both LTR and RTL from the first commit — not patched in later.
- KPI row design: Dashboard opens with a concise KPI strip — total disbursed, active cases, hubs operational, avg delivery time — immediately answers the most important questions.
Accessibility:
- WCAG-compliant component choices
- Keyboard navigable auth flows
- High-contrast text in both dark and light modes
- RTL keyboard navigation support
User Flow — Donor Journey:
flowchart TD
A["Donor visits TrueAid.org"] --> B["Cinematic landing —\ncredibility panel, urgent cases"]
B --> C["Clicks 'Donate' CTA"]
C --> D["Trust Pre-Check Modal:\n- Hub verification status\n- Last audit date\n- Transparency score"]
D --> E{Donor satisfied?}
E -->|Yes| F["Proceed to donation intent"]
E -->|No| G["Explore transactions feed\nor rankings first"]
G --> D
F --> H["Sign up / sign in\n(OTP or Google OAuth)"]
H --> I["Donor dashboard:\nportfolio of supported cases"]
I --> J["Real-time updates:\ntransaction feed + case status\nper supported hub"]
Technical Architecture
Tech Stack:
| Layer | Technology |
|---|---|
| Framework | Next.js (App Router), TypeScript |
| Database / Auth | Supabase (PostgreSQL + Auth + RLS) |
| Charts | Apache ECharts |
| Maps | Mapbox + OpenStreetMap |
| Styling | Tailwind CSS |
| Rate limiting | Supabase-backed distributed counters (in-memory fallback) |
| Proof system | Daily Merkle root generation scripts, snapshot CSV/JSON + checksum |
| Deployment | Vercel (Hobby guardrails respected) |
| Cron | Vercel Cron — daily external tracker sync (0 2 * * *) |
| SEO | JSON-LD structured data, robots.ts, sitemap.ts |
Architecture Overview:
graph TB
subgraph "Public Surfaces"
LAND["Landing /"]
FEED["Transaction Feed /feed"]
MAP["Map /map"]
RANK["Rankings /rankings"]
TRACE["Trace /transactions/:id\n/beneficiaries/:id"]
end
subgraph "Role Dashboards"
DONOR["/donor"]
BENEF["/beneficiary"]
HUB["/hub"]
ADMIN["/admin"]
end
subgraph "API Layer (Next.js)"
PUBAPI["Public API /api/v1/*"]
AUTHAPI["Auth API /api/v1/auth/*"]
ADMINAPI["Admin API /api/v1/admin/*"]
CRON["Cron /api/internal/cron/*"]
end
subgraph "Data / Auth"
ANON["Supabase Anon Client\n(public reads)"]
USER["Supabase User Client\n(authenticated routes)"]
SADMIN["Supabase Admin Client\n(ops/jobs)"]
DB["PostgreSQL + RLS"]
end
subgraph "Trust Layer"
MERKLE["Merkle Root Scripts\n(daily batch)"]
ANCHOR["On-chain Anchor\n(reference only)"]
SNAP["Snapshot Export\n(CSV/JSON + checksum)"]
end
LAND --> PUBAPI
FEED --> PUBAPI
MAP --> PUBAPI
RANK --> PUBAPI
TRACE --> PUBAPI
DONOR --> USER
BENEF --> USER
HUB --> USER
ADMIN --> ADMINAPI
PUBAPI --> ANON --> DB
AUTHAPI --> USER --> DB
ADMINAPI --> SADMIN --> DB
CRON --> SADMIN
MERKLE --> SNAP
SNAP --> ANCHOR
Notable technical challenges:
Three-tier Supabase client split: Rather than a single Supabase client with broad permissions, TrueAid uses three explicitly scoped clients: anon (public read), user-scoped (authenticated), admin (trusted ops). This means a bug in a public endpoint cannot accidentally expose write access.
Merkle proof infrastructure: The daily proof pipeline generates a Merkle root over the transaction batch, exports a checksum-verified snapshot (CSV + JSON), and references an on-chain anchor. This gives donors an independently verifiable audit trail — no need to trust the dashboard's own data presentation.
Vercel Hobby edge-case handling: The deployment is explicitly designed around Vercel Hobby constraints — API paths excluded from middleware matcher (avoids extra edge invocations), client fallback polling at 120s (pauses on hidden tabs), navigation prefetch disabled. These constraints are documented and respected rather than worked around.
Rate limiting: Distributed rate limiting via Supabase RPC as the default backend (falls back to in-memory for dev/test). Admin mutation routes require a non-empty reason field in all PATCH payloads — enforcing auditability at the API level.
Process & Iteration
Landing v2 architecture: The premium landing page is feature-flagged (NEXT_PUBLIC_LANDING_V2=true default). v1 redirected / directly to /dashboard. v2 introduces the cinematic trust-building landing with the pre-check modal as a deliberate conversion and trust step.
Tactical Map v2: Similarly feature-flagged (NEXT_PUBLIC_TACTICAL_MAP_V2=true default). v1 was a static map preview; v2 is a fully interactive map with HUD overlays, event-driven refresh, and viewport-entry deferred initialization.
Auth rollout staged: NEXT_PUBLIC_AUTH_ACCOUNTS_V1=false by default — user auth and account routes are gated behind a flag, allowing the public transparency layer to be deployed and tested independently of the auth system.
Demo data: 0006_seed_demo_expanded.sql provides realistic multi-category dashboard data for development and stakeholder demos — transactions across multiple aid categories, multiple hubs, realistic geographic distribution.
Outcomes & Impact
- Complete role system: 4 distinct dashboards (donor, beneficiary, hub, admin) with proper auth, RLS, and scoped API access
- Cryptographic trust layer: Daily Merkle proofs + on-chain anchor references — independently verifiable without trusting the platform
- Bilingual from day one: Full EN/AR RTL support — not a localization patch, a core design decision
- Public traceability: Every transaction individually traceable via public URL — no aggregate-only reporting
- Agent API: Structured public REST API for external tracker integrations and programmatic consumption
(estimated) Trust impact: A donor who can trace their donation to a specific hub, see the hub's performance ranking, and verify the transaction batch against a Merkle proof is exponentially more likely to donate again than one who receives only a receipt email.
No live user metrics available (pre-registration mode). Qualitative differentiation: TrueAid is the only aid transparency platform in the Gaza context that combines live transaction traceability + cryptographic proofs + bilingual RTL support + role-specific accountability dashboards.
Reflections
What went well:
- The three-tier Supabase client architecture eliminated a whole class of permission bugs — the discipline of explicit trust boundaries paid off during admin panel development
- Feature-flagging the landing v2 and map v2 separately made iteration safe — stable public surface while new experiences were developed
- The bilingual RTL decision made from day one was right; retrofitting RTL onto an existing layout would have been much more painful
What I'd do differently:
- Implement the Merkle proof UI earlier — it's the most compelling trust mechanic and should be front-and-center on the landing, not just in the dashboard trust panel
- The rate limiting backend should have been abstracted from the start rather than defaulting to in-memory first
Skills demonstrated:
- Full-stack Next.js App Router development (SSR, API routes, middleware)
- Security-first API design (RLS, scoped clients, HttpOnly cookies, audit trails)
- Cryptographic transparency systems (Merkle proofs, on-chain anchors)
- Bilingual RTL product design
- Humanitarian technology domain thinking
- Feature flag architecture for staged rollout