All projects

AI Product Design

TrueAid

A public dashboard for Gaza aid. Donations, hubs, and beneficiary status are all traceable in real time. Built on the belief that "trust us" isn't a response to famine.

Role

Founder, product designer, full-stack engineer

Team

Solo

Duration

2025 → Ongoing

Year

2025

Next.js TypeScript Supabase PostgreSQL Apache ECharts Mapbox Merkle Proofs
Humanitarian Transparency Full-Stack Bilingual RTL
TrueAid hero

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:

  1. Public by default — No login required to view the transaction feed, map, rankings, or beneficiary status
  2. Trust mechanics — Live transaction feed + daily Merkle root proofs + on-chain anchor references + snapshot checksums
  3. Role-specific dashboards — Tailored views for donors, beneficiaries, hub operators, and admins
  4. 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 modeNEXT_PUBLIC_PRE_REGISTRATION_MODE=true default 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:

LayerTechnology
FrameworkNext.js (App Router), TypeScript
Database / AuthSupabase (PostgreSQL + Auth + RLS)
ChartsApache ECharts
MapsMapbox + OpenStreetMap
StylingTailwind CSS
Rate limitingSupabase-backed distributed counters (in-memory fallback)
Proof systemDaily Merkle root generation scripts, snapshot CSV/JSON + checksum
DeploymentVercel (Hobby guardrails respected)
CronVercel Cron — daily external tracker sync (0 2 * * *)
SEOJSON-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