Skip to content
 
 

Repository files navigation

TrustBridge Dashboard

License: MIT Next.js 14 Stellar

TrustBridge Dashboard is the open-source web interface for the TrustBridge project. It connects GitHub contributor identities to Stellar G-addresses and validates payout readiness before Wave disbursements.

The problem: Stellar payments fail with PAYMENT_NO_TRUST when a recipient account lacks a trustline for the asset being sent (e.g. USDC). Maintainers need a single source of truth mapping github_username → stellar_address with live trustline and reserve checks — before batch payouts.


Table of contents


Features

Audience Capability
Contributors Sign in with GitHub OAuth, register a Stellar G-address, get live Horizon validation (funding, USDC trustline, XLM reserve)
Maintainers View all registrations, filter by readiness, batch re-check via Horizon, export CSV for Wave payout prep, review recent Soroban contract events
Everyone Public landing page with Wave readiness stats

Readiness model

Status Badge Meaning
Ready ✅ Funded, USDC trustline active and authorized, spendable XLM ≥ minimum reserve
Low reserve ⚠️ Funded + authorized trustline, but spendable XLM below threshold
Not ready ❌ Unfunded, missing trustline, or a present-but-unauthorized trustline

Authorization matters: a trustline can exist but remain unauthorized by the asset issuer (Stellar AUTH_REQUIRED assets). Payments to an unauthorized trustline still fail, so the dashboard tracks is_authorized separately and an account is only verified (✅ on-chain badge) when funded and holding an authorized trustline.

Spendable vs. raw XLM: every Stellar account must keep a minimum reserve locked up — baseReserve * (2 + subentries + sponsoring − sponsored) — plus any XLM tied up in selling_liabilities. That reserve is not available for payments, so the reserve check compares against spendable XLM (spendableXlmBalance), not the raw xlm_balance. A contributor with 5 XLM raw balance and 3 trustlines can show ~3.5 XLM locked in reserve, leaving well under 1 XLM spendable — this is low_reserve, not ready, even though the raw balance alone looks healthy.


Quick start

Prerequisites

1. Clone and install

git clone https://github.com/your-org/trustbridge-dashboard.git
cd trustbridge-dashboard
npm install

2. Configure environment

cp .env.example .env.local

Fill in all required values — see docs/ENVIRONMENT.md for full reference.

3. Initialize the database

npm run db:push

4. Run locally

npm run dev

Open http://localhost:3000.

GitHub OAuth callback URL (local): http://localhost:3000/api/auth/callback/github


Documentation

All docs are cross-linked from this README:

Document Description
Setup guide Step-by-step local development setup
Environment variables Every env var explained
Architecture System design, data flow, auth model
Project structure Directory layout and key files
Deployment Vercel deployment checklist
Contributing How to contribute to this repo
CSRF protection Threat model, protected routes, non-browser client policy, testing guide

Tech stack

Layer Technology
Framework Next.js 14 (App Router)
Language TypeScript
Styling Tailwind CSS, shadcn/ui patterns
Data fetching TanStack React Query
Auth NextAuth.js + GitHub OAuth
Database PostgreSQL + Prisma ORM
Blockchain stellar-sdk + Horizon API
Deployment Vercel (recommended)

Brand colors: Stellar purple #3E1BDB, cyan accent #00B4D8. Dark mode supported.


Routes & API

Pages

Route Auth Description
/ Public Landing page, TrustBridge explainer, Wave stats
/register GitHub OAuth Contributor Stellar address registration
/dashboard GitHub OAuth + org member Maintainer payout readiness table

API routes

Endpoint Method Description
/api/auth/[...nextauth] GET/POST NextAuth.js handlers
/api/check POST Horizon validation { address, asset_code?, asset_issuer? }
/api/register GET/POST Read/save contributor registration (authenticated)
/api/contributors GET/POST List contributors / batch re-check (maintainer only)
/api/stats GET Aggregate readiness statistics
/api/check POST Horizon validation { address, asset_code?, asset_issuer? } — returns trustline_authorized and verified
/api/register GET/POST Read/save contributor registration (authenticated)
/api/contributors GET/POST List contributors / batch re-check (maintainer only)
/api/contributors/[id] POST Re-check a single contributor via Horizon (maintainer only)
/api/audit GET Recent maintainer actions — audit log (maintainer only)
/api/stats GET Aggregate readiness statistics
/api/actions/lookup GET Cached Horizon readiness lookup + wizard nextAction guidance, ?address=G...
/api/soroban/events GET Recent events for SOROBAN_CONTRACT_ID (maintainer only)
/api/settings/network GET Resolved Horizon/Soroban network + mismatch warnings (maintainer only)

Resilience

  • Horizon circuit breaker — src/lib/circuit-breaker.ts wraps Horizon API calls. After 5 consecutive failures, the breaker opens and fast-fails for 30s, returning a friendly "Horizon is temporarily unavailable" message. Configurable via HORIZON_CB_FAILURE_THRESHOLD, HORIZON_CB_RECOVERY_MS, and HORIZON_CB_SUCCESS_THRESHOLD.
  • Stale CSV export guard — src/lib/stale-export.ts checks lastCheckedAt timestamps before CSV export. If any contributor hasn't been verified within the configured window (default 24h), the dashboard shows an amber warning banner and requires confirmation before exporting. Configurable via STALE_CSV_MAX_AGE_MS.

Middleware

src/middleware.ts protects /register (requires sign-in) and /dashboard (requires sign-in + GITHUB_MAINTAINER_ORG membership).

Security

  • CSRF protection — All mutating API routes validate the Origin / Referer header against the application's host. See docs/CSRF.md.
  • Rate limiting — POST /api/check is rate-limited per IP (default 10 requests per minute) to prevent Horizon API abuse. Configure via RATE_LIMIT_WINDOW_MS and RATE_LIMIT_MAX_REQUESTS.
  • CSV / JSON exports — Maintainer dashboard exports contributor data as CSV or JSON. Export helpers live in src/lib/csv.ts and are covered by snapshot tests.

Environment variables

Copy .env.example to .env.local and configure:

GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=
TOKEN_ENCRYPTION_KEY=  # required, openssl rand -base64 32 — encrypts stored access tokens
GITHUB_MAINTAINER_ORG=
GITHUB_MAINTAINER_TEAM= # optional, team slug within GITHUB_MAINTAINER_ORG — org-only check if unset
DATABASE_URL=
NEXT_PUBLIC_HORIZON_URL=https://horizon.stellar.org
NEXT_PUBLIC_DEFAULT_ASSET_CODE=USDC
NEXT_PUBLIC_DEFAULT_ASSET_ISSUER=GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX5IHOWEBMGJI55ITFSZ6
NEXT_PUBLIC_MIN_XLM_BALANCE=1
NEXT_PUBLIC_BASE_RESERVE_XLM=0.5  # optional, Stellar base reserve used for spendable-balance checks
SOROBAN_CONTRACT_ID=   # optional, future on-chain registry + event timeline panel
SOROBAN_RPC_URL=       # optional, defaults to soroban-testnet.stellar.org

Note: NEXT_PUBLIC_HORIZON_URL and SOROBAN_RPC_URL should point at the same Stellar network. Their defaults don't (mainnet vs. testnet) — the dashboard detects and warns on this mismatch via /api/settings/network and the maintainer dashboard's network status panel, and records it to the audit log.

See docs/ENVIRONMENT.md for details.

Generate NEXTAUTH_SECRET:

openssl rand -base64 32

Testing

Unit tests run on Vitest and cover the pure business logic (readiness/authorization rules, the Horizon retry helper, audit-log formatting, batch verification, and the Soroban event-timeline read path — including the GET /api/soroban/events maintainer guard, a missing SOROBAN_CONTRACT_ID, and simulated RPC outages/rate limits, all without a live network call):

npm test          # run once
npm run test:watch

Tests also run in CI on every push and pull request, before the build.

Schema note: issue #7 adds a trustlineAuthorized column to Registration, issue #22 adds an AuditLog table, and issue #8 adds a spendableXlmBalance column to Registration. After pulling these changes, sync your database with npm run db:push.


Deployment

This project is optimized for Vercel:

  1. Push to GitHub
  2. Import repo in Vercel
  3. Add environment variables from docs/ENVIRONMENT.md
  4. Attach a Postgres database (Vercel Postgres, Neon, etc.)
  5. Run npm run db:push against production DATABASE_URL
  6. Set GitHub OAuth callback to https://your-domain.vercel.app/api/auth/callback/github

Full checklist: docs/DEPLOYMENT.md


Contributing

We welcome contributions! Please read docs/CONTRIBUTING.md before opening a PR.

Quick flow:

  1. Fork the repo
  2. Create a feature branch (git checkout -b feat/my-feature)
  3. Commit with clear messages
  4. Run tests (npm run test)
  5. Open a pull request against main

Optional: Soroban on-chain registry

PostgreSQL is the source of truth for registrations. Setting SOROBAN_CONTRACT_ID (+ optionally SOROBAN_RPC_URL) today enables the read-only maintainer event timeline (GET /api/soroban/events), which fetches recent contract events and degrades gracefully — never failing the dashboard — on RPC outages, rate limits, or a missing contract ID.

Mirroring registrations to a Soroban contract (write-through) is designed but not yet implemented — see docs/ARCHITECTURE.md § Soroban register write-through for the read-vs-write-through breakdown, the intended write design, and how each edge case (outage, missing config, rate limits) is or would be handled.


License

This project is licensed under the MIT License.


Links

About

A web UI where contributors register their Stellar G-address, view their trustline status, and project maintainers get a bird's-eye view of payout readiness.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages