feat(board): Lightning-paid message board with LNbits and admin moderation

Add public /board flow: create invoice, webhook + confirm reconciliation, list
active messages, likes (Nostr), zap fallbacks. Admin table for hide/delete.

Include LNbits webhook body normalization (double-encoded JSON), POST
/api/messages/confirm/:hash, and root npm db:push script. Prisma models for
pending invoices and board messages.

Made-with: Cursor
This commit is contained in:
bbe
2026-04-03 18:37:52 +02:00
parent 7acff1ae38
commit 586b572f73
14 changed files with 1257 additions and 5 deletions

View File

@@ -4,7 +4,9 @@ ADMIN_PUBKEYS=npub1examplepubkey1,npub1examplepubkey2
# Nostr relays (comma-separated)
RELAYS=wss://relay.damus.io,wss://nos.lol,wss://relay.nostr.band
# Database (use an absolute `file:` URL in production, e.g. file:/home/bbe/BelgianBitcoinEmbassy/backend/prisma/prod.db)
# Database (path is relative to backend/prisma/ when using file: URLs — see Prisma docs)
# Apply schema: from repo root run `npm run db:push`, or from backend run `npm run db:push`.
# Do not run bare `npx prisma db push` from the repo root (no schema there; wrong Prisma version).
DATABASE_URL="file:./dev.db"
# JWT
@@ -22,3 +24,15 @@ NEXT_PUBLIC_API_URL=http://localhost:4000/api
NEXT_PUBLIC_SITE_URL=https://belgianbitcoinembassy.org
NEXT_PUBLIC_SITE_TITLE=Belgian Bitcoin Embassy
NEXT_PUBLIC_SITE_TAGLINE=Belgium's Monthly Bitcoin Meetup
# Message board (Lightning / LNbits) — backend
MESSAGE_PRICE_SATS=1000
LNBITS_API_KEY=
LNBITS_WEBHOOK_SECRET=
LNBITS_URL=https://legend.lnbits.com
# Public URL that LNbits can POST webhooks to (usually your site origin so /api/messages/webhook hits the API)
WEBHOOK_BASE_URL=http://localhost:3000
# Optional: lnaddress or LNURL-pay string for “Zap BBE” when the message has no pubkey
BOARD_ZAP_LN_ADDRESS=
# Optional: hex pubkey for njump fallback when BOARD_ZAP_LN_ADDRESS is unset
BOARD_ZAP_PUBKEY=