================================================================================
DEMOCRACY RISING / FUNDRAISING PLATFORM — DEEP SITE AUDIT
================================================================================
Generated: 2026-05-19 (UTC)
Scope:     /root/fundraising-platform (source, config, Prisma, scripts, runtime)
Machine:   Linux (Proxmox LXC), 4 vCPU, ~7.8 GiB RAM, 64 GiB disk (~7% used)
Service:   fundraising-platform.service → npm run start → tsx server.ts :8008
Public:    https://bwt.democracyrisingbwt.us (Cloudflare proxy, not direct to origin)
Typecheck: npm run lint (tsc --noEmit) — PASS at audit time
Build:     npm run build — PASS (includes /threads-callback, /api/threads-exchange)

Severity legend:
  [CRITICAL]  Exploit, money loss, secret exposure, or production outage risk
  [HIGH]      Broken feature, data corruption risk, or major UX failure
  [MEDIUM]    Correctness edge case, maintainability, or meaningful perf waste
  [LOW]       Polish, SEO, docs, minor duplication

================================================================================
0. EXECUTIVE SUMMARY
================================================================================

This is a Next.js 16 App Router political fundraising app with:
  - Stripe donations + webhooks
  - Supporter credits (BWT) wallet + ledger
  - 10 casino-style games (7 REST solo, 2 Socket.IO PvP, 1 prediction market)
  - Community features (billboard, spotlight, cards, FAQ board, boost meter)

Overall code quality: TypeScript compiles clean; core wallet debits use atomic
updateMany; many game routes use optimistic locking (updateMany + outcome:"active").
The largest risks are DEPLOYMENT/DNS (Cloudflare serving stale static pages),
SOCKET/PONG in-memory state (single-process assumption), BLACKJACK transaction
gaps, and CLIENT-SIDE performance (always-on canvas animations + polling).

Approximate codebase: ~15,246 lines in src/**/*.ts(x), 561M node_modules, 1.1G .next

Top 10 actions (ordered):
  1. Fix Cloudflare routing for bwt.democracyrisingbwt.us → origin :8008 (not static HTML)
  2. Align NEXT_PUBLIC_SITE_URL / AUTH_URL with real public hostname
  3. Rotate any secrets ever committed or logged (.env, old Threads static page)
  4. Wrap blackjack natural/push/resolve in single DB transactions
  5. Add gameSessionId FK on ledger entries for reconciliation
  6. Document/require npm run start (not dev:next) for Socket.IO games
  7. Reduce homepage/global canvas + polling load on this 8GB box
  8. Delete or wire DonationCheckout.tsx (~400 lines dead)
  9. Harden coin-flip/pong payout failure paths (room stuck ACTIVE)
 10. Add rate limits on /api/register and game POST endpoints

================================================================================
1. DEPLOYMENT & INFRASTRUCTURE (CRITICAL FOR LIVE SITE)
================================================================================

1.1 [CRITICAL] Cloudflare intercepts traffic before Next.js
------------------------------------------------------------------------------
Symptom verified on live host:
  - https://bwt.democracyrisingbwt.us/datadeletion → was 404 until service restart;
    may still vary by cache
  - https://bwt.democracyrisingbwt.us/threads-callback → serves OLD static HTML
    ("Threads Bot Setup", client-side secret exchange) NOT the Next.js route
  - curl shows: server: cloudflare, cf-ray present
  - DNS: bwt.democracyrisingbwt.us → 104.21.29.229 / 172.67.171.225 (Cloudflare)
  - Origin direct :8008 on public IP → connection refused (port not exposed)

Local origin (correct):
  - http://127.0.0.1:8008/threads-callback → Next.js page "Threads callback"
  - http://127.0.0.1:8008/datadeletion → legal page

Old static /threads-callback HTML (served via Cloudflare) contains:
  - client_id in page JS
  - client_secret in browser fetch to graph.threads.net (SECURITY DISASTER)
  - Inline OAuth flow bypassing /api/threads-exchange

Action: In Cloudflare dashboard, remove Workers/Pages/static asset rules for
  /threads-callback, /datadeletion, /api/*; proxy pass-through to origin tunnel
  or open 8008 via cloudflared. Purge cache after fix.

Files (new, correct): src/app/threads-callback/*, src/app/api/threads-exchange/route.ts

1.2 [HIGH] Environment URL mismatch
------------------------------------------------------------------------------
.env currently has:
  NEXT_PUBLIC_SITE_URL=https://democratic.thetempleofdoom.com
Public users use:
  https://bwt.democracyrisingbwt.us

Impact:
  - Canonical URLs, Open Graph, JSON-LD, sitemap base wrong for BWT subdomain
  - Socket.IO CORS allowedOrigin may reject browser if users hit bwt.* but env says democratic.*
  - Stripe/NextAuth redirect_uri mismatches if callbacks use SITE_URL

Action: Set NEXT_PUBLIC_SITE_URL, NEXTAUTH_URL, AUTH_URL to the hostname users
  actually use (or support multiple origins in server.ts CORS).

Reference: server.ts lines 18-22 (allowedOrigin), src/lib/public-env.ts

1.3 [MEDIUM] Single-process architecture
------------------------------------------------------------------------------
server.ts holds:
  - pongRooms Map + setInterval game loops (20 Hz per active room)
  - coin-flip resolution inline on join
  - No Redis, no horizontal scaling

If you scale to 2+ Node processes: PvP games break, rooms split-brain.

Action: Document "single instance only" or migrate room state to Redis.

1.4 [LOW] systemd unit note
------------------------------------------------------------------------------
/etc/systemd/system/fundraising-platform.service uses npm run start (good).
Unknown key StartLimitIntervalSec ignored on older systemd — harmless.

NODE_OPTIONS=--max-old-space-size=8192 on an 7.8GB machine leaves little headroom
for PostgreSQL + OS. Consider 4096 unless you see OOM during build.

================================================================================
2. SECURITY
================================================================================

2.1 [CRITICAL] Secrets exposure vectors
------------------------------------------------------------------------------
- Old Cloudflare-hosted threads-callback HTML embeds THREADS client_secret in JS
- .env on server contains live Stripe sk_live_* (never commit; restrict file perms)
- Threads credentials in .env (THREADS_CLIENT_ID, THREADS_CLIENT_SECRET) — OK if
  server-only; ensure .gitignore blocks .env (it does)

Action: Rotate Threads app secret + Stripe keys if static page was ever public.
  chmod 600 /root/fundraising-platform/.env

2.2 [HIGH] No global API rate limiting
------------------------------------------------------------------------------
Unauthenticated or session-authenticated endpoints can be spammed:
  - POST /api/register
  - POST /api/games/* (each debits DB)
  - POST /api/faq, /api/billboard, etc.

Action: nginx/cloudflare rate limits, or middleware with IP buckets.

2.3 [MEDIUM] Auth middleware disabled
------------------------------------------------------------------------------
src/middleware.ts → matcher: [] — no edge protection.
All auth is per-route auth() calls. Easy to forget on new routes.

Wallet page protected in page.tsx; most /api/* check session — good pattern but
not enforced centrally.

2.4 [MEDIUM] FAQ pending submissions
------------------------------------------------------------------------------
src/app/api/faq/route.ts GET:
  - pending[] only returned when signedIn (line 29-44) — IMPROVED vs old audit
  - Still: any logged-in user sees ALL pending submissions (moderation leak)

Action: pending visible to admin role only.

2.5 [MEDIUM] Socket.IO auth — PARTIALLY FIXED
------------------------------------------------------------------------------
server.ts resolveSocketUserId() uses getToken from cookie — GOOD.
CoinFlipRoom no longer sends client userId in join_room — GOOD.

Remaining:
  - CORS origin single string; subdomains need array
  - No explicit origin check on Engine.IO handshake beyond cors config

2.6 [LOW] Prediction market trust model
------------------------------------------------------------------------------
Creator resolves outcome (PATCH). No oracle — fine for demo, risky for prod.

2.7 [LOW] No email verification enforced
------------------------------------------------------------------------------
User.emailVerified in schema unused in credentials flow.

================================================================================
3. DEAD CODE, DUPLICATION, ORPHANS
================================================================================

3.1 [HIGH] Unused component — DonationCheckout.tsx
------------------------------------------------------------------------------
Path: src/components/DonationCheckout.tsx (~400 lines)
Imports: NONE in app (only EmbeddedDonationCheckout used)
  - src/app/donate/page.tsx → EmbeddedDonationCheckout
  - src/components/DonateSection.tsx → EmbeddedDonationCheckout

Action: Delete file or merge unique features into EmbeddedDonationCheckout.

3.2 [MEDIUM] Unused exports / dead helpers
------------------------------------------------------------------------------
- src/lib/auth-links.ts: LOGIN_RETURN_WALLET, LOGIN_RETURN_RAISED — no imports
- src/app/api/games/dice/route.ts: imports hashServerSeed, never used
- src/app/api/games/tower/route.ts: SAFE_PER_FLOOR constant was reported unused
  (verify before delete)
- src/lib/exchange.ts: @deprecated BLW_* aliases — internal only

3.3 [MEDIUM] Duplicated game metadata
------------------------------------------------------------------------------
- src/app/casino/page.tsx — GAMES array (lobby cards)
- src/app/casino/[game]/page.tsx — GAME_META record
- src/components/casino/GameHistory.tsx — GAME_ICONS

Any new game requires 3 edits. Extract shared catalog module.

3.4 [MEDIUM] Duplicated settlement logic
------------------------------------------------------------------------------
mines/route.ts and tower/route.ts — nearly identical cashout/win transactions.
dice, slots, roulette — copy-paste instant-game transaction blocks.
crash/mines/tower use creditWalletCredits + manual ledger; dice uses same;
blackjack uses creditForWin/refundBet from game-ledger — INCONSISTENT.

Action: Single settleGameWin() / settleGameLoss() in game-ledger.ts.

3.5 [LOW] redmeFIXSES.md partially stale
------------------------------------------------------------------------------
Section 3 claims API-only features have no UI — FALSE for:
  billboard, spotlight, cards, faq-board, boost (all have pages + fetch)
Section 1.1 socket userId spoof — FIXED in current server.ts
Section 1.2 CORS * — FIXED (restricted origin)
Section 2.1 public stats — BOTH use status:"succeeded" now

Keep redmeFIXSES.md or merge into this audit after triage.

================================================================================
4. GAME-BY-GAME AUDIT (LOGIC, BUGS, EXPLOITS)
================================================================================

Shared infrastructure:
  - lib/provably-fair.ts — HMAC-SHA256, crash 3% edge, deriveMinePositions
  - lib/game-ledger.ts — debitForBet, creditForWin, refundBet
  - lib/wallet-safety.ts — atomic debit via updateMany gte check
  - prisma GameSession — @@index([userId]), @@index([userId, gameType])

------------------------------------------------------------------------------
4.1 CRASH (REST: POST + PATCH) — src/app/api/games/crash/route.ts
------------------------------------------------------------------------------
Client: src/components/casino/CrashGame.tsx

Behavior:
  - POST debits wager, stores crashAt in resultData (hidden until loss/cashout)
  - PATCH tick: client sends currentMultiplier; server settles loss if >= crashAt
  - PATCH cashout: pays floor(wager * cashoutAt)

Issues:
  [MEDIUM] cashOut() sends `cashoutAt: multiplier` (React state) while tick probe
    uses multiplierRef.current — possible 1-frame desync under load.
    Fix: always send multiplierRef.current on cashout.

  [MEDIUM] Tick interval every 220ms while running = ~4.5 req/s per active player.
    Many concurrent crash players = DB load. Consider server-side timer or WS.

  [LOW] Animation runs to 100x client-side even if crashAt is 2x — cosmetic only
    until tick returns loss.

  [LOW] No max wager cap server-side beyond integer >= 1.

Provably fair: serverSeed returned on end — good for verification.

------------------------------------------------------------------------------
4.2 DICE (REST: POST instant) — src/app/api/games/dice/route.ts
------------------------------------------------------------------------------
Client: src/components/casino/DiceGame.tsx

Issues:
  [LOW] Unused import hashServerSeed (no commit hash returned to client)
  [LOW] No serverSeedHash at bet time — weaker commit-reveal than mines/crash

Logic: roll 0-99, threshold 2-98, multiplier = 0.98/winProb — OK.

Transaction: single prisma.$transaction — GOOD.

------------------------------------------------------------------------------
4.3 MINES (REST: POST + PATCH) — src/app/api/games/mines/route.ts
------------------------------------------------------------------------------
Client: src/components/casino/MinesGame.tsx

Issues:
  [MEDIUM] Loss path uses prisma.gameSession.update (not updateMany) — double-tile
    race could overwrite outcome if two PATCHes in flight.

  [MEDIUM] calcMultiplier() uses inverted product formula — verify house edge
    matches advertised 1%; not unit tested.

  [LOW] Cashout with 0 reveals refunds full wager (push) — intentional?

  [LOW] minePositions sent to client on loss/cashout — correct for transparency;
    during active play positions hidden — GOOD.

------------------------------------------------------------------------------
4.4 TOWER (REST: POST + PATCH) — src/app/api/games/tower/route.ts
------------------------------------------------------------------------------
Client: src/components/casino/TowerGame.tsx

Same settlement duplication as mines. Pre-generated bomb positions per floor.

Issues:
  [MEDIUM] Same updateMany vs plain update race as mines on some paths
  [LOW] FLOOR_MULTIPLIERS hardcoded — not derived from provably-fair module

------------------------------------------------------------------------------
4.5 SLOTS / ROULETTE (REST: POST instant)
------------------------------------------------------------------------------
Files: src/app/api/games/slots/route.ts, roulette/route.ts
Clients: SlotsGame.tsx, RouletteGame.tsx

Pattern: transaction wraps debit + credit + GameSession — GOOD.

Issues:
  [LOW] No explicit max wager
  [LOW] Outcome math not documented in UI paytable linkage to server

------------------------------------------------------------------------------
4.6 BLACKJACK (REST: POST + PATCH) — src/app/api/games/blackjack/route.ts
------------------------------------------------------------------------------
Client: src/components/casino/BlackjackGame.tsx

Issues:
  [HIGH] Natural blackjack / push on POST (lines 91-100):
    creditForWin/refundBet + gameSession.update are OUTSIDE initial transaction.
    Failure between them → wallet credited but session still "active" or inverse.

  [HIGH] resolveStand() (lines 157-193):
    credit/refund then session update — not atomic.
    Partial failure → duplicate payout or lost payout.

  [MEDIUM] Card rank parsing: handValue uses c.slice(0,-1) — works for "10♠"
    but fragile if format changes.

  [MEDIUM] Double down debits second wager but doesn't link ledger memo to session.

Action: Wrap each resolution path in prisma.$transaction like dice route.

------------------------------------------------------------------------------
4.7 COIN FLIP (REST rooms + Socket.IO) — rooms/route.ts + server.ts
------------------------------------------------------------------------------
Client: src/components/casino/CoinFlipRoom.tsx

Flow:
  - POST /api/games/rooms creates WAITING room (balance check only, no debit)
  - Creator connects socket, waits
  - Joiner connects → atomic claim → debit both → instant resolve

Issues:
  [HIGH] Payout failure (server.ts lines 129-132): logs error, still emits
    "result" to clients; room may stay ACTIVE — needs reconciliation job.

  [MEDIUM] Creator never debited until joiner arrives — creator can spam WAITING
    rooms (DB clutter). Expire job runs every 60s — OK.

  [LOW] Instant resolution — no rematch within room

  [LOW] GameHistory does not show coin flip (no GameSession row)

Socket auth: server-derived userId — GOOD.

------------------------------------------------------------------------------
4.8 PONG (REST rooms + Socket.IO + setInterval) — server.ts
------------------------------------------------------------------------------
Client: src/components/casino/PongGame.tsx

Issues:
  [HIGH] Game loop setInterval(50ms) per room in Node process — CPU scales with
    active pong rooms. On 4-core VPS, cap concurrent rooms.

  [HIGH] pongRooms Map: if process crashes mid-game, debits already taken,
    room may stay ACTIVE, interval orphaned until process exit.

  [MEDIUM] paddle_move has no rate limit — flood events

  [MEDIUM] Client/server paddle collision logic duplicated — desync possible

  [LOW] No GameSession history entry

Payout path (lines 244-255): improved with async IIFE + logging — still emits
game_over even if payout fails.

------------------------------------------------------------------------------
4.9 PREDICTION MARKET — src/app/api/games/prediction/route.ts
------------------------------------------------------------------------------
Client: src/components/casino/PredictionMarket.tsx

POST bet: NOW uses single $transaction (debit + ledger + bet + market increment) — GOOD.

PATCH resolve: transaction with resolvedTo null guard — GOOD.
  - Pays winners via tx.wallet.upsert — bypasses creditWalletCredits integer guard
    if payout is 0 skipped; dust handling to first winner — clever

Issues:
  [MEDIUM] GET markets: no auth required — OK for public markets
  [LOW] No GameSession — not in GameHistory
  [LOW] Creator can resolve early? — throws MARKET_NOT_ENDED if endsAt > now — GOOD

------------------------------------------------------------------------------
4.10 GAME HISTORY — src/app/api/games/history/route.ts + GameHistory.tsx
------------------------------------------------------------------------------
Issues:
  [MEDIUM] Client: fetch without res.ok check — silent failure on 401
  [MEDIUM] Only GameSession rows — PvP and prediction invisible
  [LOW] No pagination UI (API may support cursor — verify route)

================================================================================
5. API ROUTES — COMPLETE INVENTORY & GAPS
================================================================================

37 HTTP route handlers under src/app/api/:

Auth:        /api/auth/[...nextauth]
Register:    /api/register
Public:      /api/public/stats, /api/leaderboard, /api/exchange/rate
Wallet:      /api/wallet, summary, ledger, donations, community
Stripe:      create-checkout-session, create-payment-intent, webhooks/stripe
Missions:    /api/missions, /api/missions/spend
Initiatives: /api/initiatives, [slug]/pledge
Poll:        /api/polls/next-president
Rewards:     catalog, redeem, raffle
Community:   /api/billboard, /api/spotlight, /api/cards, /api/faq, /api/boost
Games:       crash, dice, mines, tower, slots, blackjack, roulette, rooms,
             prediction, history
Threads:     /api/threads-exchange

Validation:
  [MEDIUM] Game routes use manual req.json() casts — no Zod. Malformed body → 500.
  [GOOD]   FAQ, boost, cards, many others use Zod schemas.

Missing patterns:
  - No If-None-Match / caching on public stats (force-dynamic everywhere)
  - No request ID in logs
  - Inconsistent error JSON shape { error } vs { issues }

------------------------------------------------------------------------------
5.1 Feature pages vs API (wiring status)
------------------------------------------------------------------------------
WIRED (page fetches API):
  /billboard      → /api/billboard
  /spotlight      → /api/spotlight
  /cards          → /api/cards
  /faq-board      → /api/faq
  /boost          → /api/boost
  /casino/*       → game APIs
  /missions       → /api/missions
  /initiatives    → /api/initiatives
  /vote/*         → /api/polls/next-president
  /wallet         → wallet APIs
  /donate         → Stripe checkout

HOMEPAGE mismatch:
  [MEDIUM] ProgressSection → /api/public/stats (USD Stripe goal meter)
  Boost page → /api/boost (BWT community epoch meter)
  Marketing copy may conflate two different "meters" — clarify UX.

================================================================================
6. DATABASE / PRISMA
================================================================================

Schema: prisma/schema.prisma (515 lines, 8 migrations)

Indexes present:
  LedgerEntry userId
  GameSession userId, [userId, gameType]
  GameRoom status
  PollVote, Faq*, MovementBoost, etc.

Missing indexes (performance at scale):
  [MEDIUM] GameSession.createdAt — history orders by time, filter by user
  [MEDIUM] GameRoom [status, gameType, expiresAt] composite for lobby listing
  [MEDIUM] Donation [status, createdAt] for leaderboard aggregations
  [LOW] LedgerEntry [userId, createdAt] for wallet ledger pagination

Missing FKs:
  [MEDIUM] LedgerEntry has no gameSessionId / gameRoomId — hard to audit bets

Enums: GameType, RoomStatus, LedgerType — comprehensive

------------------------------------------------------------------------------
6.1 Data integrity notes
------------------------------------------------------------------------------
  [GOOD] Wallet debit uses conditional updateMany (balance >= amount)
  [GOOD] Boost uses Serializable isolation for epoch milestone
  [GOOD] public/stats and treasury both filter donation status succeeded
  [MEDIUM] Movement boost milestone race under concurrent POSTs (documented in redmeFIXSES)

================================================================================
7. FRONTEND / UX / MALFORMED PATTERNS
================================================================================

7.1 Global layout performance killers
------------------------------------------------------------------------------
src/app/layout.tsx loads on EVERY page:
  - CursorStreamers — full-screen canvas, mousemove listener, RAF loop
  - SiteNav
  - framer-motion on Hero and many sections

src/components/ParticleField.tsx — second full-section canvas on homepage Hero
src/components/SmokeWisps.tsx — additional animation layer

Impact on 8GB Linux VPS:
  - Constant GPU/CPU use even on /datadeletion legal pages
  - Battery drain for mobile users
  - Competes with Node build (npm run build spikes memory)

Actions:
  - Load CursorStreamers only on homepage or casino
  - Respect prefers-reduced-motion (CursorStreamers already skips reduced motion)
  - Lazy-load framer-motion below fold

7.2 Polling / duplicate fetches
------------------------------------------------------------------------------
Endpoints polled from multiple components without shared SWR/React Query:

  /api/exchange/rate — 9+ separate useEffects across site
  /api/wallet       — ExchangePanel every 15s on casino pages
  /api/public/stats — ProgressSection, HeroLiveStats

Action: Single client provider for rate + wallet; stale-while-revalidate.

7.3 Casino page architecture
------------------------------------------------------------------------------
src/app/casino/[game]/page.tsx:
  - Server component fetches wallet once — GOOD
  - ExchangePanel re-fetches wallet every 15s — balance can drift from server
  - Game components receive static `balance` prop — not updated after wins/losses
    unless user refreshes or ExchangePanel poll updates (partial fix)

  [MEDIUM] User sees stale balance in wager inputs after big win until poll.

7.4 Error handling gaps
------------------------------------------------------------------------------
  - GameHistory: no res.ok check
  - Many fetch().then without .catch — silent network errors
  - CrashGame tick: empty catch {} swallows errors — intentional comment

7.5 Accessibility
------------------------------------------------------------------------------
  - Canvas decorations aria-hidden — GOOD
  - Some icon-only buttons may lack aria-labels in casino grids
  - Focus management on game phase transitions not tested

7.6 SEO / metadata
------------------------------------------------------------------------------
  [MEDIUM] layout.tsx alternates.canonical hardcoded to "/" — subpages should
    override (some do, e.g. privacy-policy)

  [MEDIUM] sitemap.ts missing /casino, /missions, /boost, /billboard, etc.

  [LOW] opengraph-image force-dynamic — regenerates every request

================================================================================
8. STRIPE / PAYMENTS / WALLET
================================================================================

  - EmbeddedDonationCheckout → create-checkout-session (primary path)
  - DonationCheckout → create-payment-intent (UNUSED)
  - Webhook: src/app/api/webhooks/stripe/route.ts — signature verify — GOOD

Issues:
  [HIGH] Ensure webhook endpoint not cached by Cloudflare (POST body must reach origin)
  [MEDIUM] CREDIT_RATIO_CENTS_PER_USD — verify webhook grants match UI promises
  [LOW] Guest checkout path — document in FAQ

================================================================================
9. AUTH
================================================================================

  - next-auth v5 beta with Credentials provider
  - Email OR username login — GOOD (lib/account-identifiers.ts)
  - bcrypt password hashing — GOOD
  - JWT session with role — GOOD
  - No OAuth providers configured

Issues:
  [MEDIUM] No password reset flow (forgot-password page is static)
  [MEDIUM] No brute-force lockout on /api/auth/callback/credentials
  [LOW] ADMIN role only via DB seed

================================================================================
10. TESTING & OBSERVABILITY
================================================================================

Scripts:
  scripts/smoke-integration.ts  — Prisma/DB
  scripts/http-smoke.sh         — curl stats + wallet 401
  scripts/full-site-test.ts   — extensive HTTP checks (manual, server must run)
  scripts/seed-leaderboard.ts

Gaps:
  [HIGH] No automated tests for game math or wallet settlement
  [HIGH] No CI pipeline evident
  [MEDIUM] console.error only — no structured logs, no correlation IDs
  [MEDIUM] No health check endpoint (/api/health) for monitoring
  [LOW] eslint installed but npm run lint = tsc only

================================================================================
11. LINUX / NODE PERFORMANCE TUNING (THIS MACHINE)
================================================================================

Current resources (audit snapshot):
  RAM: 7.8 GiB total, ~1.6 GiB used, 6.2 GiB available
  CPU: 4 cores
  Disk: 64G volume, 7% used
  node_modules: 561M
  .next: 1.1G

Recommendations:

A. Process manager
   - Keep single fundraising-platform.service instance
   - Add MemoryMax=5G in systemd unit to avoid OOM killing Postgres
   - Lower NODE_OPTIONS to --max-old-space-size=4096 for steady-state

B. PostgreSQL (localhost:5432)
   - Ensure shared_buffers ~256MB, effective_cache_size ~2GB on this VM
   - Enable log_min_duration_statement = 500 for slow query discovery
   - Run EXPLAIN on leaderboard + poll aggregation queries

C. Next.js production
   - Run `npm run build` after every deploy (already required for new routes)
   - Consider output: 'standalone' in next.config for smaller runtime footprint
   - Disable turbopack for production build if instability observed (using default)

D. Reverse proxy
   - Prefer cloudflared tunnel → 127.0.0.1:8008 over exposing :8008
   - Enable gzip/brotli at edge; Next already compresses

E. Static assets
   - next.config.ts sets immutable cache for /_next/static — GOOD
   - Ensure Cloudflare respects cache for hashed assets only

F. Background jobs
   - server.ts setInterval 60s for room expiry — OK
   - Add cron for stuck ACTIVE GameRoom reconciliation

G. Build/deploy workflow
   - systemctl restart after git pull + npm run build
   - Avoid running build while service uses CPU (schedule maintenance window)

H. Monitoring
   - journalctl -u fundraising-platform -f
   - Add node_exporter or simple /api/health returning { ok, db, version }

================================================================================
12. LEGAL / COMPLIANCE PAGES (RECENT)
================================================================================

Added:
  /privacy-policy  — src/app/privacy-policy/page.tsx
  /datadeletion    — src/app/datadeletion/page.tsx
  /threads-callback — OAuth UI (blocked on live domain by Cloudflare static file)

Issues:
  [MEDIUM] legal-contact falls back to privacy@example.com if env unset
  [LOW] Template disclaimer on pages — counsel review still required
  [LOW] threads-callback not in sitemap (robots noindex — OK)

================================================================================
13. PACKAGE / DEPENDENCY NOTES
================================================================================

  next@16.2.6, react@19.2.6, prisma@7.8.0, next-auth@5.0.0-beta.31
  socket.io@4.8.3 — matches client
  framer-motion@12 — large bundle; tree-shake or lazy load
  zod@4.4.3 — v4 API; ensure team knows breaking changes vs zod 3

  [LOW] npm audit not run in this audit — run `npm audit` separately

================================================================================
14. FILE-BY-FILE HOTSPOT INDEX (QUICK REFERENCE)
================================================================================

server.ts                          Socket.IO, pong loop, coin flip, room expiry
src/middleware.ts                  matcher [] — auth not global
src/auth.ts                        Credentials only
src/app/api/games/blackjack/route.ts  NON-ATOMIC payouts — FIX FIRST
src/app/api/games/crash/route.ts     tick spam, cashout state sync
src/app/api/games/mines/route.ts     loss race, ledger bypass
src/app/api/games/prediction/route.ts  resolve logic OK; trust model
src/components/DonationCheckout.tsx   DELETE (dead)
src/components/CursorStreamers.tsx    perf — scope to homepage
src/components/ParticleField.tsx      perf — homepage only
src/components/casino/ExchangePanel.tsx 15s polling
src/components/casino/CrashGame.tsx   220ms PATCH polling
src/components/casino/GameHistory.tsx  no error handling
src/app/casino/[game]/page.tsx        stale balance prop
src/lib/game-ledger.ts               canonical money API
src/lib/provably-fair.ts             all RNG
prisma/schema.prisma                 indexes + missing FKs
next.config.ts                       security headers, HSTS preload
.env / .env.example                  URL + Threads vars

================================================================================
15. SUGGESTED FIX ROADMAP (PHASED)
================================================================================

Phase 0 — Today (ops):
  [ ] Cloudflare: route all paths to Node origin; delete static threads HTML
  [ ] Fix NEXT_PUBLIC_SITE_URL for bwt.democracyrisingbwt.us
  [ ] Rotate Threads secret if static page was public
  [ ] systemctl restart after build

Phase 1 — Money safety (1-2 days dev):
  [ ] Blackjack transactions
  [ ] Coin-flip/pong stuck room reconciler
  [ ] LedgerEntry.gameSessionId optional FK + backfill

Phase 2 — Games UX (2-3 days):
  [ ] Unify game catalog
  [ ] Fix CrashGame cashout ref
  [ ] GameHistory error states + PvP rows (or document omission)
  [ ] Balance sync via context after each game

Phase 3 — Performance (1-2 days):
  [ ] Remove/limit CursorStreamers + ParticleField scope
  [ ] Shared exchange rate provider
  [ ] Add DB indexes listed above
  [ ] Lower Node heap to 4GB

Phase 4 — Hardening (ongoing):
  [ ] Rate limits
  [ ] Health endpoint
  [ ] Integration tests for dice/mines settlement
  [ ] Delete DonationCheckout.tsx

================================================================================
16. AUDIT METHODOLOGY
================================================================================

Performed:
  - Full tree listing src/, prisma/, scripts/
  - tsc --noEmit (pass)
  - npm run build route list (pass)
  - Manual read of all game API routes + server.ts + key components
  - Grep for TODO, console.*, fetch patterns, dead imports
  - Live HTTP comparison Cloudflare vs 127.0.0.1:8008
  - Subagent explore pass for architecture map
  - Cross-check against redmeFIXSES.md (partially outdated)

Not performed:
  - npm audit / dependency CVE scan
  - Load testing (k6/ab) on game endpoints
  - Stripe live transaction test
  - Full line-by-line read of all 15k lines (hot paths covered)
  - PostgreSQL EXPLAIN ANALYZE
  - Accessibility audit tooling (axe)

================================================================================
END OF AUDIT — 16 sections, ~450+ line items reviewed
================================================================================
