Remove the per-route 'export const instant = false' opt-outs now that the root layout carries the single Cache Components opt-out. Child pages inherit the opt-out, so admin/mod/radio leaf pages that only access cached or DB data stay instant while runtime-dependent pages remain dynamic. Update the staff-smoke contract test to assert the root-layout contract.
- Clone import: defer FurnitureData.json writes and append all entries in a
single batched write instead of one read-modify-write per item, removing
the main serialization bottleneck for large batches.
- Clone import: raise SSE batch concurrency cap from 5 to 10 and bump the
clone client/route default from 2 to 6.
- Add a flush hook to runSseBatch so callers can batch deferred work before
batch_complete is emitted, and surface flush errors as an error event.
- Enable Next.js Cache Components (instant: false opt-out) and silence the
related build warnings in next.config.ts.
- Switch isomorphic-dompurify to dompurify and refresh dependencies.
21 files defined their own local formatDate (with three different output
formats: date, datetime, datetime-seconds, and varying null fallbacks).
Replace them with a single shared helper at src/lib/format-date.ts that
takes a variant + optional fallback, preserving the exact previous output
per call site (verified identical string results).
Removes ~21 copies of the same logic. photos.tsx and media-grid.tsx keep
their epoch-ms based formatters since those are a different input shape.
Verified: tsc --noEmit clean, full test suite green (301/301).
Wire orphan routes into hub tabs, group Radio into primary/tools rows, show theme/language once on desktop, and remove duplicate page titles under AdminHubChrome.
Co-authored-by: Cursor <[email protected]>
- 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 ✓
- Replace 'card' class with 'admin-card' (gradient cards, dark mode support)
- Replace 'muted' class with consistent Tailwind muted states
- Standardize page headers with gradient backgrounds and Lucide icons
- Convert all inline styles to Tailwind classes
- Add admin-page CSS helpers (admin-card, admin-filter-bar, admin-section-title)
- Apply pattern to all 42 admin pages (was only 6 before)
- Zero TypeScript errors, production builds successfully
Co-authored-by: openhands <[email protected]>
Built the admin tools previously listed as missing:
- Badge upload (/admin/badges): uploads a <code>.gif into the emulator's
badge dir via BADGE_UPLOAD_DIR (node:fs); validated code/type/size,
logged. Made configurable rather than skipped.
- Radio tools: /admin/radio/api-keys (CRUD, server-generated keys),
/admin/radio/autodj (Auto-DJ playlist CRUD), /admin/radio/embed (embed
snippet generator), /admin/radio/points (points settings),
/admin/radio/monitoring (live stream/now-playing/listeners status).
radio_api_keys + radio_auto_dj_playlist already had real columns.
- /admin/vpn: VPN/proxy detection config (block toggle + provider + key),
complementing /admin/ip's raw blacklist.
- Writeable boxes: new website_writeable_boxes table (model + migration
0006) + /admin/writeable-boxes CRUD; active boxes render on the public
home page. env: BADGE_UPLOAD_DIR.
Verified live (prod, amx_test): all 8 pages render with real data; a test
writeable box appeared on the public home and was reverted. tsc 0,
vitest 49/49, next build 0 (7 new admin routes).