Skip to content

Latest commit

 

History

History
215 lines (170 loc) · 12.4 KB

File metadata and controls

215 lines (170 loc) · 12.4 KB

Frontend Architecture Overview

This document describes the current structure, data flow, and library choices for the Invoice Liquidity Network (ILN) frontend. It is intentionally concise: enough context for contributors to understand where changes belong without duplicating implementation details from every route.


System Shape

ILN is a Next.js App Router frontend for a Stellar/Soroban invoice liquidity protocol. The UI is organized around the protocol's main actors: freelancers submit invoices, liquidity providers fund them, payers settle or dispute them, governance users vote on proposals, and admins monitor protocol health.

graph TD
    subgraph Routes ["app/ routes"]
        Product["Dashboards, marketplace, pay, submit, governance, analytics, stats"]
        Api["API routes: auth, feedback, notifications, reminders"]
    end

    subgraph UI ["src/components and src/screens"]
        Components["Reusable forms, tables, charts, modals, dashboards, stories"]
        Screens["Dashboard and analytics screen compositions"]
    end

    subgraph State ["State and data"]
        Context["WalletContext, NotificationContext, ToastContext"]
        Hooks["Custom hooks and React Query hooks"]
        Providers["app/Providers.tsx"]
    end

    subgraph Services ["Integration layer"]
        Soroban["src/utils/soroban.ts"]
        Lib["src/lib: env, Supabase, Horizon, events, wallet helpers"]
        Indexer["Indexer REST/WebSocket"]
        Email["Supabase and Resend"]
    end

    subgraph Network ["External systems"]
        Wallet["Freighter wallet"]
        Stellar["Stellar Horizon and Soroban RPC"]
        Contract["ILN contract and token contracts"]
    end

    Product --> Components
    Product --> Screens
    Product --> Hooks
    Api --> Lib
    Providers --> Context
    Hooks --> Soroban
    Hooks --> Lib
    Components --> Context
    Soroban --> Wallet
    Soroban --> Stellar
    Stellar --> Contract
    Lib --> Indexer
    Lib --> Email
Loading

Route Surface

The primary route tree lives in app/. For a complete overview of canonical routes, purposes, primary consumers, and active redirects, refer to the Route Map.

A small legacy src/app/ tree still exists for older route experiments/tests and should be treated carefully when moving code.

app/
├── admin/                       # Admin health and protocol configuration
├── analytics/                   # Freelancer-specific cash-flow analytics (FreelancerAnalyticsDashboard)
├── api/
│   ├── feedback/                # GitHub-backed feedback submission
│   ├── notifications/[address]/ # Notification API bridge
│   └── reminders/               # Supabase/Resend payer reminder cron
├── dashboard/                   # Personalized dashboard
├── freelancer/                  # Freelancer workspace
├── governance/                  # Proposal list, detail, creation, explainer
├── i/[id]/                      # Public invoice detail
├── leaderboard/                 # Protocol leaderboard
├── lp/                          # LP dashboard
│   └── compare/                 # LP invoice comparison
├── marketplace/                 # Fundable invoice marketplace
├── offline/                     # PWA offline fallback
├── pay/[id]/                    # Payer checkout
│   └── dispute/                 # Invoice dispute route
├── payer/                       # Payer landing/dashboard route
├── profile/[address]/           # Reputation profile and activity
├── referrals/                   # Referral dashboard
├── roadmap/                     # Roadmap
├── stats/                       # Protocol stats
├── submit/                      # Invoice submission
├── layout.tsx                   # App shell
└── Providers.tsx                # React Query, theme, toast, MSW, app providers

Core supporting code is split by responsibility:

src/
├── components/                  # Reusable UI, charts, dashboards, stories
│   ├── analytics/               # Analytics widgets and tables
│   ├── charts/                  # Chart primitives and dynamic wrappers
│   ├── governance/              # Voting, delegation, allowlist controls
│   ├── invoices/                # Invoice-specific management widgets
│   ├── onboarding/              # Onboarding flow and spotlight helpers
│   └── ui/                      # Base UI primitives
├── context/                     # Context providers and consumer hooks (global state)
│   ├── WalletContext.tsx         # Wallet state, network checks, roles, signing
│   ├── NotificationContext.tsx   # In-app notification history
│   ├── ToastContext.tsx          # Toast message layer over Sonner
│   └── KeyboardShortcutsContext.tsx  # Keyboard shortcut and command palette state
├── hooks/                       # Custom hooks (no createContext); may consume context
│   ├── queries/                 # React Query keys and query hooks
│   └── useBrowserNotifications.ts # Browser Notification API wrapper
├── lib/                         # Env, Supabase, Horizon, events, notifications
├── screens/                     # Larger dashboard/screen compositions
├── utils/                       # Soroban, analytics, risk, exports, formatting
└── i18n.ts                      # i18next setup

Data Flow

Reads

Most contract and indexer reads flow through hooks:

  1. A route or component calls a hook such as useInvoices, useBalances, useContractStats, useRecentProtocolFeed, or a hook under src/hooks/queries/.
  2. The hook uses TanStack React Query for loading state, cache keys, refetch intervals, and invalidation.
  3. Contract reads call src/utils/soroban.ts or src/lib/* helpers to simulate Soroban reads, parse XDR/ScVal data, query Horizon, or call an indexer endpoint.
  4. Components receive typed data and render tables, cards, charts, badges, and dashboards.

Writes

User-approved contract writes coordinate wallet state, transaction builders, and toasts:

  1. The user triggers an action such as submit, fund, pay, mark paid, cancel, dispute, vote, delegate, or transfer.
  2. A hook or utility builds and simulates the Soroban transaction.
  3. WalletContext requests a Freighter signature and verifies the configured Stellar network.
  4. The signed XDR is submitted and polled until resolution.
  5. Sonner toasts communicate pending/success/error states, and React Query invalidates affected invoice, balance, stats, or governance queries.

Server Routes

API routes are used for server-only integration points:

  • app/api/reminders/route.ts reads Supabase reminder preferences and sends Resend emails when authorized by CRON_SECRET.
  • app/api/reminders/unsubscribe/route.ts updates reminder preferences.
  • app/api/feedback/route.ts can create GitHub issues from app feedback when GitHub credentials are configured.
  • app/api/notifications/[address]/route.ts bridges notification reads by address.
  • Contributor references for these server integrations live in docs/supabase-setup.md, docs/feature-flags.md, docs/api-routes.md, and docs/testing.md.

State, Providers, and UI Boundaries

  • app/Providers.tsx wires global providers, React Query, theme behavior, toasts, and local MSW startup when NEXT_PUBLIC_API_MOCKING=enabled.
  • WalletContext owns wallet address, provider state, network checks, role detection, balances, and signing.
  • NotificationContext stores in-app notification history.
  • ToastContext wraps toast behavior while AppToaster renders the Sonner host.
  • KeyboardShortcutsContext manages keyboard shortcut state and global keydown listeners.
  • Page routes should compose feature components and hooks; reusable components should stay under src/components/.
  • Stellar SDK and RPC details should stay in src/utils/soroban.ts, src/lib/, or focused hooks rather than being called directly from presentational components. Integration status of live vs. stubbed contract details are tracked in docs/contract-integration-status.md.

Context vs Hooks Boundary

  • src/context/ — React Context providers and their consumer hooks (e.g., WalletProvider + useWallet, ToastProvider + useToast, NotificationProvider + useNotification, KeyboardShortcutsProvider + useKeyboardShortcuts). Context files own shared global state that must be available to the entire subtree. If a file exports a *Provider or calls createContext, it belongs here.

  • src/hooks/ — Custom React hooks that do NOT define new contexts. They may consume context hooks to derive or transform state, manage local (component-level) state, wrap external APIs, or encapsulate effect-heavy logic. If a file exports only hook functions (that consume context or are pure utilities), it belongs here.

Naming Conventions

  • useToast — always imported from @/context/ToastContext (the former re-export @/hooks/useToast has been removed).
  • useWallet — always imported from @/context/WalletContext for basic wallet state.
  • useNotification (singular) — always imported from @/context/NotificationContext for in-app notification items.
  • useBrowserNotifications (plural) — imported from @/hooks/useBrowserNotifications for the browser Notification API (permissions, desktop notifications).

Avoiding Duplicate Polling & State

Invoice status changes are the primary source of duplication risk. To keep RPC usage predictable:

  1. React Query is the single source of truth for contract reads. Hooks should prefer useQuery-based data over direct contract calls to avoid bypassing cache and creating redundant network requests.
  2. Notification polling (useNotificationEvents, usePositionPolling) should share a single invoice-change detection loop. Do not add a third polling hook that independently calls getInvoice().
  3. LocalStorage-derived state (bookmarks, watchlist, address book, LP settings, widget layout) is acceptable per-hook, but state computations should not duplicate logic already present in context providers.

Environment Model

The canonical local template is .env.local.example. Direct env references in app/ and src/ are checked by:

pnpm run env:check

The CI workflow runs the same command, and .env.local.example.allowlist documents runtime-provided values such as NODE_ENV.

Client-visible configuration uses NEXT_PUBLIC_*, including Stellar network settings, feature flags, indexer URLs, WalletConnect project ID, app URL/version, and contract version labels. Server-only secrets such as SUPABASE_SERVICE_ROLE_KEY, RESEND_API_KEY, CRON_SECRET, and GitHub feedback credentials must never be exposed with a public prefix.

Library Rationale

  • Next.js App Router: Fits route-level product areas, server API routes, PWA/offline behavior, and deployable static/client-heavy surfaces.
  • TanStack React Query: Provides structured cache keys, query invalidation after wallet transactions, polling controls for live protocol state, and optimistic update patterns.
  • i18next, react-i18next, and next-intl: Support existing locale files and leave room for route-aware internationalized UI.
  • next-pwa: Generates the service worker and offline support used by app/offline/ and public PWA assets.
  • next-themes: Keeps theme state centralized for the light/dark design system.
  • Sonner: Gives mutation flows concise pending/success/error toast updates without heavyweight styling.
  • Supabase JS and Resend: Power opt-in payer reminder persistence and email delivery behind server-only env gates.
  • Recharts: Used for stats, analytics, yield, reputation, allocation, and volume visualizations.
  • jspdf, papaparse, qrcode, and qrcode.react: Cover invoice PDF generation, CSV import/export support, and invoice sharing flows.
  • Storybook, Chromatic, Vitest, Playwright, jest-axe, and Stryker: Cover component documentation, visual regression, unit/accessibility tests, browser journeys, and mutation testing.

Contributor Guidance

When adding a route, update this document and the README route summary if the product surface changes. When adding an env var, update .env.local.example or .env.local.example.allowlist in the same change and run pnpm run env:check.