redmeFIXSES — systematic issue & follow-up list
This document is a repo-wide audit of the Democratic Fundraising Platform (/root/fundraising-platform): things that need a solution, decision, wiring, or hardening before calling the product complete for real-world use. Items are grouped for triage; paths are relative to the project root.
1. Security & authentication (high priority)
| # |
Issue |
Where / notes |
| 1.1 |
Socket.IO trusts userId from the browser — anyone can emit another user’s id and trigger debits, refunds, or payouts against the wrong wallet. There is no session cookie / JWT handshake binding the socket to auth(). |
server.ts (join_room, paddle_move for Pong); src/components/casino/CoinFlipRoom.tsx passes userId into io(...).emit("join_room", { roomId, userId }). Fix: authenticate on connection (e.g. pass a short-lived signed token or upgrade request with session), ignore client-supplied userId, use server-derived id. |
| 1.2 |
CORS is origin: "*" on the Socket.IO server — combined with 1.1, third-party sites could script abuse if a victim is logged in (and even without, id spoofing is already possible). |
server.ts → new SocketIOServer(..., { cors: { origin: "*" } }). Fix: restrict to siteUrl() / env allowlist. |
| 1.3 |
Registration endpoint is unthrottled — email enumeration, credential stuffing, mass fake accounts. |
src/app/api/register/route.ts. Fix: rate limit (IP + email), CAPTCHA or proof-of-work for production, optional email verification before wallet use. |
| 1.4 |
No automated password reset — acceptable as a placeholder only; increases support load and lockout risk. |
src/app/forgot-password/page.tsx (static copy). Fix: SMTP or auth provider + VerificationToken flow. |
| 1.5 |
Admin role can only be granted out-of-band (DB/seed). There is no secure admin bootstrap or audit log for privileged actions. |
src/lib/admin.ts, usage in FAQ/billboard/etc. Fix: documented procedure, optional separate admin app, logging. |
| 1.6 |
Public FAQ API leaks pending community submissions (display names + text) to anyone. |
src/app/api/faq/route.ts GET returns pending without auth. Fix: require auth for pending, or admin-only pending list. |
2. Data integrity, races, and consistency
| # |
Issue |
Where / notes |
| 2.1 |
/api/public/stats vs treasury — donation aggregates use no status: "succeeded" filter, while getTreasuryTotalUsdCents() filters succeeded. Today most rows are succeeded-only, but the two can diverge if statuses are ever used. |
src/app/api/public/stats/route.ts vs src/lib/treasury.ts. Fix: align queries on the same predicate. |
| 2.2 |
Prediction bets: debit and row insert are not one transaction — edge cases under concurrency could desync balance vs bets. |
src/app/api/games/prediction/route.ts (debitForBet then predictionBet.create). Fix: single prisma.$transaction. |
| 2.3 |
Movement meter milestone bonuses — crossing METER_TARGET can race under concurrent POSTs; bonus grants are not idempotent keys. |
src/app/api/boost/route.ts. Fix: row lock / serializable transaction, or separate “epoch_closed” record before paying bonuses. |
| 2.4 |
Ledger vs GameSession — DEBIT_GAME_BET / CREDIT_GAME_WIN ledger lines are not FK-linked to GameSession/GameRoom, making reconciliation and support harder. |
src/lib/game-ledger.ts, prisma/schema.prisma. Fix: optional gameSessionId / gameRoomId on LedgerEntry. |
| 2.5 |
Pong server state — setInterval runs in process memory; multi-instance deploy would break. Process crash mid-game loses state (partial debits may already have happened). |
server.ts. Fix: document single-instance requirement, or Redis-backed rooms + recovery. |
3. Features implemented in API only (no UI wiring)
Grep shows no fetch("/api/…") usage from the React app for these routes; they are dead from an end-user perspective unless hit manually or by a future screen.
| Route area |
Files |
Needed solution |
| Community FAQ board |
src/app/api/faq/route.ts |
Add a page or embed: list approved, submit/vote when signed in, admin approve/reject UI (or drop the API). |
| Democracy billboard |
src/app/api/billboard/route.ts |
Wire ticker/post UI; or remove until product wants it. |
| Issue spotlight auction |
src/app/api/spotlight/route.ts |
Wire homepage “issue of the week” UI to real bids; or remove. |
| Movement meter (BWT sink + milestone) |
src/app/api/boost/route.ts |
The homepage “Grassroots meter” (ProgressSection) is Stripe USD goal, not this BWT meter — product copy vs implementation are misaligned. Either wire /api/boost into the UI + clarify copy, or retire the feature. |
| Supporter trading cards |
src/app/api/cards/route.ts |
Add profile/wallet cards UI; or remove. |
Static marketing FAQ (src/components/FaqSection.tsx) and the dynamic FAQ API are two parallel systems — decide which is source of truth.
4. Product / compliance / copy
| # |
Issue |
Notes |
| 4.1 |
Committee & legal placeholders |
README and env still assume NEXT_PUBLIC_COMMITTEE_LEGAL_NAME_PLACEHOLDER, disclaimers, counsel review before live fundraising. |
| 4.2 |
Casino / prediction / games |
Server-side games exist; jurisdiction, gambling, and campaign-finance implications need counsel. Disclosure copy may be insufficient sitewide. |
| 4.3 |
Prediction markets |
Creator resolves outcome (PATCH in src/app/api/games/prediction/route.ts) — no independent oracle; reputational and fairness risk. |
| 4.4 |
User-generated initiatives |
src/app/api/initiatives/route.ts — public text up to 8k chars with no moderator queue in code. |
| 4.5 |
Email verification |
User.emailVerified exists in Prisma but credentials flow does not set or enforce it. |
5. Configuration, dev/prod parity, and tooling
| # |
Issue |
Where / notes |
| 5.1 |
NEXT_PUBLIC_SITE_URL missing from .env.example |
Defaults in src/lib/public-env.ts to https://democracyrising.org — local/staging can silently emit wrong canonical URLs in metadata/sitemap. |
| 5.2 |
npm run dev uses server.ts |
Socket games depend on this. npm run dev:next skips custom server — coin flip / pong break if a developer uses the wrong script. Document clearly or unify. |
| 5.3 |
npm run lint is only tsc --noEmit |
eslint is in devDependencies but not wired as a script — style and Next lint rules are unused in CI script form. |
| 5.4 |
Strict-Transport-Security with preload |
next.config.ts applies globally. Local HTTP dev is usually fine, but misconfigured hosts + HSTS have bitten teams before — confirm intended behavior for each environment. |
| 5.5 |
Sitemap is incomplete |
src/app/sitemap.ts omits major routes (/missions, /initiatives, /casino, etc.) vs actual app surface. SEO gap or intentional — decide. |
6. UX / polish still called out historically
From the workspace plan platform_bug_hunt_&_polish_30ad9fd4.plan.md (many items marked done), the following may still be desirable:
| Item |
Notes |
| Active nav state |
src/components/SiteNav.tsx — no “current page” styling for non-anchor routes. |
| Loading shimmer coverage |
Plan mentioned skeletons beyond what MockExchangeTicker already does for errors. |
| DonationCheckout |
Mentions .env in user-visible copy — consider production-friendly wording (src/components/DonationCheckout.tsx). |
7. Testing & observability
| # |
Gap |
| 7.1 |
No unit test suite — only scripts/smoke-integration.ts, scripts/http-smoke.sh, and scripts/full-site-test.ts (manual against a running server). |
| 7.2 |
No structured logging / APM hooks for Stripe webhooks or game transactions. |
| 7.3 |
Webhook path returns 500 on processing errors — need alerting and Stripe retry monitoring in production. |
8. Quick reference — files that most often need attention
- Auth & gatekeeping:
src/middleware.ts (only protects /wallet), src/auth.ts, src/auth.config.ts
- Money:
src/app/api/webhooks/stripe/route.ts, src/app/api/stripe/create-payment-intent/route.ts
- Realtime games:
server.ts, src/app/api/games/rooms/route.ts, src/components/casino/CoinFlipRoom.tsx
- Public truth vs internals:
src/app/api/public/stats/route.ts, src/lib/treasury.ts
Generated by a full-tree pass of source, Prisma schema, config, and README; re-run this audit after large feature merges.