Last updated: 2026-08-26 (Phase 7 stabilization in progress)
Full-stack application: Go modular-monolith API in backend/ and a Next.js
Pages Router application in frontend/.
The current history is linear through Phase 7. main contains Phases 1–6 and
the continuation-note commit; Phase 7 is stacked on top:
phase-1 → phase-2 → phase-3 → phase-4 → phase-5 → phase-6 → main
└─ phase-7-admin-panel ← current branch
Current branch: phase-7-admin-panel. The branch has committed Phase 7 work plus
an active uncommitted stabilization pass; check git status before editing or
committing so the in-progress changes are preserved.
- Foundation: Chi router, structured JSON logging, pgx/Redis connections, graceful shutdown,
/health+/ready. - Events: full CRUD, status lifecycle (
DRAFT → PUBLISHED → REGISTRATION_OPEN → REGISTRATION_CLOSED → COMPLETED, plusCANCELLED/ARCHIVED), categories/schedule/FAQs/rules. - Poster pipeline: configurable artboard selection and positioning, server-normalized JPEG originals, and automatically generated
@card/@herodelivery variants with legacy URL fallback. - Auth: register/login/refresh/logout, JWT access token + rotating refresh-token cookie,
USER < STAFF < ADMIN < SUPER_ADMINRBAC. - Registrations:
SELECT ... FOR UPDATE-based capacity safety (proven under real concurrency), one-active-registration-per-user-per-event, Redis lock/availability-cache/rate-limit, USD/KHR Bakong KHQR checkout with server-side settlement verification, failed-initialization compensation, leased background reconciliation, and QR ticket tokens. - Check-in: QR token verification, one-check-in-per-registration (DB-enforced), admin registration listing, audit log.
- Notifications: all 5 email types (registration confirmation, payment confirmation, cancellation, event update, event reminder), async via a Redis-queued/Postgres-swept worker, SMTP optional (logs instead of sending when unconfigured).
- Worker health: the notification worker publishes an expiring Redis heartbeat; the Super Admin system console reports live, stale, or unavailable state instead of assuming an empty queue means the worker is healthy.
- Frontend: public event discovery/details, authenticated registration, participant race wallet, stable downloadable QR codes, and a role-guarded race-control panel.
- Public-site customization: administrators can publish the public logo,
brand colors, announcement banner, hero copy and carousel artwork/order,
mission/value messaging, primary CTA, and footer from
/admin/public-site. Settings are persisted in PostgreSQL; JPG/PNG/WebP assets are validated and stored in Cloudflare R2 when configured, with/uploads/site/*as the local development fallback. Every publish creates an immutable version; admins can review the editor/timestamp history and safely restore any prior design without deleting newer history. - Realtime public-site delivery: a Socket.IO gateway in
realtime/subscribes to trusted Go API updates through Redis Pub/Sub. Publishing or restoring public-site settings immediately refreshes connected public pages; reconnecting browsers fetch the authoritative current version so missed Pub/Sub messages cannot leave the UI stale. The gateway is outbound-only, origin-restricted, and runs on port8081in Compose. - Lean local containers: Compose applies configurable CPU, memory and PID ceilings; PostgreSQL and Redis use low-memory settings, Go/Node heaps are bounded, health checks are less frequent, logs rotate, and the API build context excludes development-only files.
- Admin operations: exact database-backed metrics, registration roster/CSV, event/category/schedule management, audit trail, real super-admin user-role management, and camera/USB/manual race check-in.
Full per-phase detail, design rationale, and what was explicitly deferred is in each phase's commit message (git log --oneline on this branch) — they're intentionally short now per your preference, but earlier ones (Phases 1–5) are more verbose and worth reading if you want the "why" behind a specific decision.
- Bakong production credentials — the KHQR/Open API integration is built, but a real merchant account ID, acquiring-bank values, API base URL, and bearer token still need to be supplied and certified in Bakong's test environment before production.
- Production deployment — no Dockerfile hardening pass, no Vercel/container-platform config yet.
- Backups and monitoring — automated PostgreSQL/R2 backups, restore drills, and external error alerts are not configured.
- Known gap flagged during Phase 5:
check_ins.staff_user_idhas noON DELETEbehavior, so a staff account that's ever performed a check-in can't be hard-deleted. Worth a soft-delete approach whenever user management gets built out.
Frontend built with Next.js, TypeScript, and Tailwind CSS. Key pages implemented:
-
Public & Participant Pages:
- Auth: Login (
/auth/login) and Register (/auth/register) with API integration - Events: Events listing (
/events) with status badges and registration CTA - Event Register: Dynamic event registration (
/events/[slug]) per event - Dashboard: User dashboard (
/dashboard) showing registrations, profile, and organizer shortcut
- Auth: Login (
-
Admin Panel (
/admin):- Dashboard Overview (
/admin): Metrics (total events, active registrations, ticket revenue, check-in count), quick actions, active events breakdown, and recent registrations. - Check-in Station (
/admin/checkin): Race-day QR scanner with live camera feed (html5-qrcode), continuous USB barcode / text search input, Web Audio API sound synthesis (success chime, already-checked-in warning, error tone), and real-time live check-in tally. - Events Management (
/admin/events): Events table with status filters (Draft,Open & Live,Published,Closed/Done), draft deletion, create wizard (/admin/events/new), and editor (/admin/events/[id]/edit) with poster upload/preview controls and status transitions (DRAFT → PUBLISHED → REGISTRATION_OPEN → REGISTRATION_CLOSED → COMPLETED → ARCHIVED/CANCELLED). Uploaded JPG/PNG/WebP artwork uses Cloudflare R2 in configured environments, with local/uploads/events/*storage retained for development. - Registrations & Attendee Roster (
/admin/registrations): Multi-parameter search & filtering (by event, category, status), participant detail drawer with contact info & emergency snapshot, and one-click CSV export for timing chips/bib assignment. - User & Staff RBAC Management (
/admin/users): API-backed Super Admin directory with audited role assignment (USER,STAFF,ADMIN,SUPER_ADMIN) and self-demotion protection. - System Console (
/admin/system): read-only Super Admin diagnostics for the API runtime, PostgreSQL pool/size/schema, Redis memory and queues, Cloudflare R2 connectivity, Socket.IO, SMTP, Google OAuth, payments, security posture, notification workers, and backup readiness. The API response is deliberately sanitized: secrets are represented only as configured/missing and are never returned to the browser. - System Audit Trail (
/admin/audit-logs): Activity log table tracking sensitive actions, state changes, actor IDs, and timestamps. - Public Site (
/admin/public-site): Live-preview editor for identity, logo, color system, announcement banner, homepage story, CTA/footer, and a one-to-six-image hero carousel with uploads and ordering controls. Includes an immutable version ledger and additive restore workflow. - Role-Guarded Navigation (
AdminLayout): Sidebar and header navigation with dynamic role permission gating and user profile menu.
- Dashboard Overview (
cd /Users/dara/development/Unity-RUNN
cp .env.example .env
docker compose up -d --build # postgres, redis, api, Socket.IO gateway
make migrate # applies pending migrations (00026 is currently latest)
make seed # one example event, always registration-open (dates relative to now)
cd frontend
npm install
npm run dev # Next.js at http://localhost:3000- API: http://localhost:8080
- Socket.IO / realtime health: http://localhost:8081/health
- Super Admin system console: http://localhost:3000/admin/system
make test— unit tests only, no DB neededmake test-integration— needs the compose stack up (-p 1, packages run serially — several integration tests truncate shared tables)make lint—go vet+gofmt -lcd frontend && npm run test:e2e— desktop/mobile public event, session persistence, and poster-editor browser journeys
Local dev credentials only — from .env.example's POSTGRES_* defaults, not secret:
| Field | Value |
|---|---|
| Host | localhost |
| Port | 5432 |
| Database | unity_run_club |
| Username | unity |
| Password | unity |
Redis (if you want to inspect the notifications:queue list or registration locks): localhost:6379, no password, DB 0.
- Read this file, inspect
git status, and skimgit log --oneline -10. - Review the active stabilization diff as a coherent release candidate; automated desktop/mobile journeys now cover public poster rendering, login refresh persistence, and the poster artboard editor.
- Keep backend race tests/vet, frontend lint/build/Playwright, realtime syntax, and Compose validation clean as the stabilization set is reviewed.
- Configure the
BAKONG_*values, switchPAYMENT_PROVIDER=bakong, and run an end-to-end payment in Bakong's test environment before production. - The remaining major roadmap choices are automated backups, a production R2 custom media domain, external monitoring, and production deployment.
- Keep commits short and plain; never add a
Co-Authored-By: Claudetrailer.