jameschang.co [experience] [/now] résumé.pdf ↓

James Chang / Projects / The Judge Tool / Roadmap & health

Static snapshot of the in-app /roadmap page as of April 2026. Live version at thejudgetool.com/roadmap.

Judge Tool · Roadmap & health · Last Updated

Product health scorecard, risk register, roadmap.

8.0/10 overall health across six dimensions. Six tracked risks with mitigations. Short-term / medium-term / long-term roadmap with priority triage.

Health scorecard

Six dimensions, scored on intake and reviewed each session.

9/10 Architecture
8/10 Code quality
8/10 Security
7/10 Testing
9/10 Documentation
7/10 Tooling

Architecture 9/10: Feature modules, barrel exports, clean separation.

Code quality 8/10: TypeScript strict, pure utils, tests for business logic.

Security 8/10: Auth guards in place, password hashing, rate limiting. Gaps: per-user PINs, CSP.

Testing 7/10: 113 unit tests, E2E simulation, zero browser tests.

Documentation 9/10: 15 docs in Diataxis framework, CLAUDE.md, build journal.

Tooling 7/10: Vitest, ESLint present. Missing: Playwright, Storybook, bundle analyzer.

Production readiness

Live phases auto-synced daily from docs/PRODUCTION_ROADMAP.md in the source repo.

Security Hardening (Do First)

  • Add Content Security Policy (CSP) headers in next.config.js or middleware — shipped in next.config.mjs (code-review todos #040, #042)
  • Add rate limiting to all API routes (currently only on login)
  • Add per-user PINs instead of shared competition PIN — shared PIN means any judge can log in as any other judge
  • Re-validate JWT role against database on each request — currently a stale role persists until token expires (24h)
  • Add CSRF protection to server actions
  • Set secure cookie flags (httpOnly, sameSite, secure) — verify next-auth config
  • Add input sanitization on all user-facing text fields to prevent XSS
  • Add request size limits to prevent abuse
  • Set up environment variable validation on startup (fail fast if missing)
  • Add audit logging for admin actions (delete competition, modify scores, etc.)
  • Move from in-memory rate limiting to Redis-based (in-memory resets on every deploy)

Reliability & Error Handling

  • Add global error boundary with user-friendly error pages
  • Add health check endpoint (/api/health) for uptime monitoring — src/app/api/health/route.ts returns DB latency + service status; surfaced on public /status page
  • Set up error tracking service (Sentry or similar) — catch production errors before users report them
  • Add database connection pooling (PgBouncer or Supabase connection pooler)
  • Add retry logic for database operations that can transiently fail
  • Add proper logging (structured JSON logs) instead of console.log
  • Add database backups schedule on Supabase (verify it's enabled)
  • Write integration tests for critical flows (login, score submission, tabulation) — plan drafted at [docs/plans/integration-tests.md](plans/integration-tests.md); execution blocked on one-time Supabase test-project provisioning (plan §6)
  • Add end-to-end tests with Playwright for the judge and organizer flows

Scaling & Performance

  • Move off Render free tier — app is on Vercel (auto-deploys from main, app.thejudgetool.com)
  • Add Redis for caching (session data, competition state, leaderboards)
  • Add CDN for static assets (Cloudflare or similar)
  • Optimize database queries — add indexes on frequently queried columns (competitionId, judgeId, categoryRoundId)
  • Add database query logging to identify slow queries
  • Consider read replicas if you get heavy traffic during live competitions
  • Add WebSocket or SSE for real-time score updates instead of 15s polling
  • Load test the app to find breaking points (how many concurrent judges?)

Multi-Tenancy & Monetization (Stripe)

  • Design multi-tenant architecture — each organizer gets isolated data (right now everything is in one pool)
  • Add organizer self-registration (sign up with email, verify email)
  • Integrate Stripe for payments — tiered plans:
  • Add Stripe Checkout for one-time competition purchases or subscriptions
  • Add Stripe webhook handler for payment confirmations, subscription changes, failed payments
  • Add billing dashboard for organizers (view invoices, manage subscription)
  • Add usage tracking (number of competitions, judges, active events)
  • Add organizer onboarding flow (create account → pick plan → pay → create first competition)

Marketing Website & Support

  • Build a landing page (separate from the app) — what it does, pricing, testimonials
  • Add demo mode — let potential customers try the app without signing up
  • Add documentation / help center for organizers (how to set up a competition, import judges, etc.)
  • Add in-app support chat or contact form (Intercom, Crisp, or simple email form)
  • Add Terms of Service and Privacy Policy pages (required for Stripe and for trust)
  • Add status page (upptime or similar) so organizers know if the system is up during events
  • Set up transactional email (welcome email, password reset, competition reminders) via Resend or SendGrid
  • Add social proof — case studies from real competitions
  • SEO basics — meta tags ✓, sitemap ✓ (submitted to GSC on both domains), Open Graph still pending (no per-page openGraph: {...} exports yet) — tracked as ST-7 in /roadmap

Analytics & Observability

Nice-to-Haves

  • Mobile app or PWA (installable on judge phones, works offline)
  • PDF export for final results and score sheets
  • White-label option (organizer's logo and branding)
  • API access for integrations with other competition management tools
  • Multi-language support if expanding beyond US
  • Judge reputation/history tracking across competitions
  • Automated competition setup wizard (walk organizers through step by step)

Medium & long term

Medium term · 1–2 months

• Real-time score updates (L) — replace 15s polling with WebSocket/SSE [P2]

• Table Organizer role (L) — new role for logistics, boxes, distribution [P3]

• Competition templates (M) — save and reuse competition configurations [P3]

• PDF score reports (M) — downloadable standings + judge scorecards [P2]

• Offline judge mode (XL) — service worker + IndexedDB for offline scoring [P3]

Long term · 3–6 months

• Multi-competition management (XL) — dashboard for concurrent events [P3]

• Sanctioning body API integration (XL) — direct integration with competition management systems [P3]

• Mobile native app (XL) — React Native with push, offline, scanning [P3]

• Analytics dashboard (L) — historical trends, judge consistency, outlier detection [P3]

Risk register

Six tracked risks with mitigations. Impact x Likelihood scoring, updated per session.

R-1 · In-memory rate limiter ineffective on Vercel serverless

Impact: Medium · Likelihood: High

Mitigation: Redis migration planned (ST-2).

R-2 · Shared judge PIN allows impersonation

Impact: High · Likelihood: Medium

Mitigation: PIN now bcrypt-hashed. Per-user PINs planned (ST-1). Seat selection is weak identity today.

R-3 · JWT role not re-validated against DB

Impact: Medium · Likelihood: Low

Mitigation: 24h token expiry limits the window. Critical actions should re-check DB (ST-4).

R-4 · No CSP headers configured

Impact: Medium · Likelihood: Low

Mitigation: OWASP headers present. CSP planned (ST-3). No user-generated content reduces XSS surface.

R-5 · Prisma v5 pinned — no patches from v7

Impact: Medium · Likelihood: Low

Mitigation: Next.js 14 incompatible with Prisma v7 node: imports. Will migrate when moving to Next.js 15.

R-6 · Single Supabase instance — no read replicas

Impact: Low · Likelihood: Low

Mitigation: Connection pooling enabled. Single competition doesn't need replicas yet.

Findings history

Ten critical issues caught and fixed during the 20-day build. All closed.

← Under the hood