- Remove production DB dump (db_backup_*.sql) and update.log from git tracking
- Add DB backups to .gitignore
- Replace all console.log/console.error with structured logger module
- Translate Dutch error messages to English (link-discord.ts)
- Remove dead code blocks (register-form.tsx false && pattern)
- Add ESLint flat config with TypeScript, React, Next.js, jsx-a11y, and security plugins
- Add Prettier config
- Add eslint-plugin-security for security-aware linting
- Fix all 119+ ESLint warnings across the codebase:
- Resolve security/detect-object-injection with safe access patterns
- Resolve security/detect-non-literal-fs-filename with path traversal validation
- Replace <img> with next/image <Image> component
- Remove unused variables and imports
- Replace non-null assertions with proper type guards
- Replace <a> with <Link> for internal navigation
- Use next/script Script component for external scripts
- Fix setState-in-useEffect anti-patterns (navbar-color-picker, logo-generator, theme-switcher)
- Add lint and format scripts to package.json
All checks: typecheck ✓, tests 58/58 ✓, lint 0 errors 0 warnings ✓
- Add DB index on bans.user_id to speed up per-request ban lookups (migration 0008)
- Replace in-process rate limiter with Redis-backed implementation with in-memory fallback
- Add Redis caching layer for site settings with TTL invalidation (migration 0009)
- Add rate limiting to resetPassword to prevent token brute-force attacks
- Update all rateLimit callers to await the now-async function
- Flesh out RadioContests and RadioGiveaways models with title, description, prize, date, and winner columns
- Update radio contest/giveaway pages to display new fields
- Add tests for rate limiter (4 tests) and password-reset actions (3 tests)
- Add REDIS_URL environment variable (optional, falls back to in-memory)
- Add lucide-react for SVG icons throughout the admin
- Redesign sidebar with gradient background, icons per nav item, and sticky layout
- Redesign topbar with cleaner user info display
- Redesign dashboard with icon-backed stat cards, gradient progress bars, activity feed
- Update AdminNavLink with icon support and new active state styling
- Improve table styling in admin-page CSS (rounded corners, hover, spacing)
- Clean up unused admin CSS
Final parity push (web-tier only):
- REST API write + token auth: POST /api/tokens (issue a personal_access_token
for the session user), Bearer auth via src/lib/api-auth.ts, POST
/api/articles/[slug]/comment, GET/DELETE /api/me/tokens, full tickets API
(/api/tickets +[id] +[id]/reply), radio current-dj/points/points-leaderboard/
embed-config + POST shouts, and a real-time /api/radio/stream (SSE). 31 public
API routes total.
- Pages: /draw-badge (buy a custom profile badge → credits + RCON), /me
dashboard (stats + online friends + referral claim). Wired into the nav.
- HTML sanitisation (sanitize-html) — the HTMLPurifier equivalent — applied to
writeable boxes + article bodies before dangerouslySetInnerHTML.
- "Dusk" dark theme preset + a default-dark site option honoured by the
no-flash boot script.
Verified live (prod, amx_test): token issue → Bearer endpoint 200, no-token
401; /api/me/tokens lists it; current-dj/leaderboard JSON; /me + /draw-badge
200; reverted the test user + tokens. tsc 0, vitest 49/49, next build 0.
Security (launch blockers):
- src/middleware.ts (edge): forwards x-pathname + real client IP.
- access-guard.ts (Node, from root layout): routes non-staff to /maintenance
when maintenance mode is on, banned users to /banned. New /banned + /maintenance
pages (the consumers the admin toggle was missing). Admin layout enforces
force_staff_2fa before /admin.
- staff-activity.ts audit log wired into ban/lift/give-currency/set-rank actions.
Infra (parallel agents): alert service (alert_logs + Discord embed + email),
PayPal top-up (create/capture API routes + /shop/topup), cron worker
(scripts/jobs-worker.ts via croner: emulator-ping->alert, maintenance-check,
bans-cleanup), social connections page, admin radio settings/banners/ranks.
Public radio subsystem: /radio (+schedule, shouts+post, contests, giveaways,
apply, leaderboard) and /apply/staff + /apply/team submission forms. Radio nav
link added. .env.example documents the new optional vars.
(radio song-requests dropped: its table is a stub in AtomCMS — columns added by
un-modeled alter-migrations.)
Verified: tsc exit 0, vitest 48/48, next build exit 0 (82 page routes).
Make the template match the atom theme, not just approximate it:
- Add Tailwind v4 (+forms/typography plugins, postcss) and port the real atom
CSS (global.css + atom app.css) into globals.css: nav-item underline, currency
+ navigation icon classes, site-bg, card-base/hover-lift, text utils — asset
paths adapted to /assets.
- Copy the real theme assets (backgrounds, icons/currency/navigation, profile,
leaderboards) into public/assets.
- Rebuild the shell 1:1 from the atom Blade: TopHeader (currency pills +
user/admin dropdowns, auth-only), SiteHeader (header image + black/50 overlay,
logo+online+Nitro client / guest Login+Create-account CTA), Navigation (white
bar, nav-item + Community/Assistance dropdowns), Footer. ThemeVars injects the
DB-driven CSS custom properties into :root like app.blade.php. Layout uses the
atom body/site-bg + grid-cols-12 max-w-7xl content wrapper.
Verified: tsc 0, next build exit 0; curl confirms the atom markup, compiled CSS
references the assets, and background-light.jpg + currency/navigation icons all
serve 200.
Minimal but real App Router app that builds (next build exit 0):
- src/lib/auth.ts: NextAuth v5 Credentials provider calling checkLogin()
(argon2id/bcrypt + md5->argon2id upgrade gated by CONVERT_PASSWORDS), JWT
session, /api/auth/[...nextauth] route handler.
- src/app: root layout, home (force-dynamic, reads hotel_name via siteSettings),
/login client form (signIn).
- next.config.ts: pinned turbopack.root, serverExternalPackages for the Prisma
MariaDB adapter; tsconfig set up for Next.
Routes: / (dynamic), /login, /api/auth. Verified: next build exit 0, 28 tests.
Still needs DB+APP_KEY to run auth end-to-end. i18n/middleware/pages to follow.
Pure, unit-tested primitives the AtomCMS->Next.js login must reproduce exactly
(verified now with round-trip + known vectors; full end-to-end check deferred
until a real DB + APP_KEY + live emulator are available):
- password.ts: argon2id (m=65536,t=4,p=1 via hash-wasm) + bcrypt ($2y$ accepted)
verify, and the md5->argon2id on-login upgrade gated by convert_passwords
(mirrors RedirectIfTwoFactorAuthenticatable).
- sso-ticket.ts: '{hotel_name without spaces}-{uuidv4}' written to auth_ticket +
ip_current (mirrors User::ssoTicket()).
- laravel-encrypter.ts: AES-256-CBC + HMAC-SHA256 payload compatible with
Laravel encrypt()/encryptString (for existing 2FA secrets) incl. PHP string
(de)serialization.
- totp.ts: otplib Google2FA-compatible TOTP verify (SHA1/6/30).
Libs: hash-wasm + bcryptjs + otplib (pure JS/WASM, no native build). 28 tests.