Architecture
SuperSats is two cooperating open-source applications — an attendance tracker and a rewards server — connected via a private API. Together they form a complete loop: attendance in, sats out.
System overview
┌──────────────────────────────────┐
│ Admin Dashboard │
│ (supersats-attendance web UI) │
│ │
│ • Register participants & groups │
│ • Review monthly reports │
│ • Approve → trigger payout │
└────────────┬─────────────────────┘
│
┌──────────────────┼──────────────────────┐
│ │ │
▼ ▼ ▼
┌────────────────┐ ┌──────────────────┐ ┌──────────────────────┐
│ Marshal PWA │ │ Attendance DB │ │ Rewards Server │
│ (mobile-first)│ │ (SQLite/Prisma) │ │ (supersats-rewards) │
│ │ │ │ │ │
│ Coaches tap │ │ Sessions, │ │ • Card balances │
│ attendance │ │ reports, │ │ • LNURL-W (BoltCard)│
│ per session │ │ participants │ │ • LNURL-P (LN addr) │
└────────────────┘ └──────────────────┘ └──────────┬───────────┘
│
▼
┌──────────────────┐
│ Blink Wallet API│
│ (GraphQL + WS) │
└──────────┬───────┘
│
▼
┌──────────────────┐
│ NFC Bolt Cards │
│ (participants) │
└──────────────────┘Admin dashboard
The admin dashboard is the private web interface inside supersats-attendance. Only administrators can access it.
What it does:
- Register participants — stores name, photo, SA ID, and assigns a sequential TSK ID
- Manage groups (Turtles, Seals, Dolphins, Sharks, Free Surfers, etc.)
- View per-group monthly attendance reports auto-generated from session data
- Approve reports — this is the trigger that initiates Lightning payouts
- Lock in the ZAR/sat exchange rate at approval time for auditable historical records
Tech: Next.js 15 (App Router) · TypeScript · SQLite via Prisma ORM · NextAuth.js v5
Marshal PWA
The Marshal PWA is a mobile-first Progressive Web App inside the supersats-attendance repo. It is the attendance capture tool used by coaches on the ground.
What it does:
- Marshals install it to their Android home screen (no app store — Chrome PWA)
- Each group has its own PIN-based passcode so marshals only access their group
- Coaches mark each participant present or absent per session
- Data saves instantly to the attendance database
Access model: Marshals have no access to reports, participant PII, or payout controls — only the attendance capture screen for their assigned group.
Rewards server
supersats-rewards is a standalone Express + TypeScript service that owns all Bitcoin logic. The attendance app calls it; it handles everything Bitcoin-related.
What it does:
- Maintains a sats balance for each participant’s Bolt Card
- Serves LNURL-W — when a participant taps their NFC card at a merchant, the card resolves the LNURL, the server checks the balance, and returns a Lightning invoice for the tap amount
- Serves LNURL-P — participants can receive sats to their card via a Lightning address (
user@yourdomain) - Exposes a batch payout API called by the attendance app on report approval — credits each participant’s card balance with their monthly reward
- Tracks a sats reserve; generates top-up invoices via Blink when reserve runs low
- Provides an admin dashboard for card management, balance views, and transaction history
Tech: Node.js 20 · Express 4 · TypeScript · SQLite via better-sqlite3 · React + Vite + Tailwind CSS
Blink Wallet API integration
The rewards server settles all real Bitcoin payments through Blink via their GraphQL API and WebSocket subscription.
Why Blink:
- Hosted Lightning — no self-managed Lightning node required
- GraphQL API makes programmatic invoice generation and payment sending straightforward
- WebSocket subscriptions give real-time payment confirmation without polling
Credentials required:
| Secret | Purpose |
|---|---|
BLINK_API_KEY | Authenticates API calls |
BLINK_WALLET_ID | Identifies which Blink wallet to debit/credit |
blinkapicredentials file | Alternative credential file (gitignored) |
NFC Bolt Card management
Participants receive a physical NFC Bolt Card pre-programmed with an LNURL-W endpoint pointing at the rewards server. The card is the wallet.
Payment flow (participant spending sats):
- Participant taps card at an NFC-enabled merchant terminal
- Terminal resolves the LNURL-W on the card
- Rewards server receives the withdraw request and checks the participant’s balance
- If sufficient balance, server returns a Lightning invoice for the merchant
- Merchant’s wallet pays the invoice; Blink settles via Lightning
- Server deducts the amount from the participant’s card balance
Admin operations available:
- Issue new cards and link them to a participant profile
- View per-card balance and full transaction history
- Filter cards by group
- Manually adjust balances for corrections
Exponential rewards curve
Sats rewards are not linear — the system uses an exponential curve tied to monthly attendance percentage. This structure rewards consistency more than sporadic presence.
Default tiers (configurable in admin UI):
| Attendance % | Monthly reward |
|---|---|
| 100% | 7 500 sats |
| 90–99% | 7 000 sats |
| 80–89% | 6 000 sats |
| 70–79% | 5 000 sats |
| < 70% | 0 sats |
The gap between tiers is intentionally larger at the top — the jump from 90% to 100% is the same reward as 70%→80% and 80%→90% combined. This is the exponential shape: the marginal value of each additional session attended increases as you approach perfect attendance.
Junior coaches are excluded from payout calculations regardless of attendance.
Security notes
- The batch payout API is protected by
BOLT_API_KEY— only the attendance app should know this key - Admin sessions in both apps are JWT-signed; rotate
NEXTAUTH_SECRET/JWT_SECRETbefore deploying - Blink credentials live in environment variables and a gitignored credentials file — never in source
- The Marshal PWA exposes no PII — group passcodes gate access to attendance capture only