Commit Graph
112 Commits
Author SHA1 Message Date
Simo f7b3845131 Close the web-feasible 100% gaps: REST write/token API, tickets, draw-badge, /me, sanitisation, dusk, radio SSE
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.
2026-06-29 18:15:01 +02:00
Simo 7daeccb832 Add dark mode, i18n, messenger/moderation/verify, admin CRUD parity
Web-tier features completing the AtomCMS→Next.js conversion (slice 2):

UI/UX:
- Dark mode: html.dark CSS-var overrides + ThemeSwitcher (localStorage,
  no-flash boot script) wired into the nav.
- i18n (next-intl, cookie-based / no URL routing): en + it catalogs,
  request.ts, provider in root layout, LanguageSwitcher; shell (nav,
  header, footer) fully translated. URLs + access-guard unchanged.
- globals.css: --muted/--border aliases used across admin pages.

User features:
- /messages: offline messages + friend-request accept (server action
  re-reads session, two directional rows, idempotent).
- Email verification: signed-token /verify route + sendVerification wired
  into register (best-effort, never blocks signup).
- Article reactions: toggle UI on news/[slug] + server action.
- Content moderation service (website_wordfilter + optional OpenAI
  moderations, fail-open) wired into article comments + guestbook.

Admin CRUD parity (Filament replacement):
- /admin/shop (+ new/[id]) packages CRUD + read-only orders.
- /admin/transactions read-only PayPal log.
- /admin/permissions, /admin/tags, /admin/ads (+ new/[id]),
  /admin/help-questions (+ new/[id]), /admin/radio/history,
  /admin/users/[id]/edit. All gated by requireStaff + logStaffActivity.

Verified: tsc 0, vitest 48/48, next build 0 (all routes incl. new
admin CRUD + /messages + /verify).
2026-06-28 16:06:42 +02:00
Simo 22d53d0e9c Add security middleware, audit log, alerts, PayPal, cron, radio + apps
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).
2026-06-28 15:10:19 +02:00
Simo e19debb795 Port AtomCMS atom theme faithfully (Tailwind v4 + real CSS/assets + shell)
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.
2026-06-28 14:50:09 +02:00
Simo e668fa85ec Add 2FA, email + password reset, and batch-7 pages
Auth (hand-built on the auth core):
- 2FA: User model gains two_factor_secret/recovery_codes/confirmed_at (+ idempotent
  MariaDB migration). authorize() requires a valid TOTP code when 2FA is confirmed
  (secret decrypted via Laravel APP_KEY, fail-closed). Two-step login (precheckLogin
  reveals the code field). /settings/2fa enable/confirm/disable flow.
- Password reset: nodemailer email service; PasswordReset model + migration;
  /forgot (request, generic response) + /reset (token sha256 + 1h TTL, sets argon2id
  hash). Login links to forgot.

Batch 7 (parallel agents): /admin/commandocentrum (RCON controls + emulator_errors),
social write actions (friend request + guild forum new thread), /help/[category],
/badges (public). env: APP_KEY, APP_URL, SMTP_*. Nav extended.

Verified: tsc exit 0, vitest 48/48, next build exit 0 (64 page routes).
2026-06-28 14:25:19 +02:00
Simo 443d908909 Scaffold Next.js 16 app + wire NextAuth Credentials to auth core
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.
2026-06-27 16:11:52 +02:00
Simo ec2d46e583 Add byte-compatible Auth & SSO core primitives
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.
2026-06-27 16:00:25 +02:00
Simo b5bc7f6daf Rebuild atomcms-next foundation on Prisma (align to habbo-next reference)
Replace the superseded Drizzle monorepo scaffold with a single-app Prisma 7
data layer, mirroring the proven habbo-next approach to the shared Arcturus
emulator DB (introspect/conform only, idempotent SQL migrations via a custom
runner; never migrate-diff).

- prisma/schema.prisma: User, UsersCurrency (composite PK), Ban, WebsiteSetting
  mapped to AtomCMS's default.sql columns; client generated to src/generated/prisma
- src/lib/prisma.ts: PrismaMariaDb adapter singleton; src/env.ts zod env
- src/lib/services: siteSettings (cached setting() equivalent) + CurrencyType enum
- prisma/migrations + scripts/apply-migrations.ts: idempotent CMS-table runner

Verified: prisma generate OK, tsc --noEmit exit 0, vitest 6/6 pass.
2026-06-27 15:26:40 +02:00
Simo d04ed42586 feat(db): add users/currency/bans/settings read repositories 2026-06-27 14:34:59 +02:00
Simo 0966aa7dda feat(db): add @atomcms/db package skeleton + mysql2/drizzle client 2026-06-27 14:32:45 +02:00
Simo edbd5c89ba feat(settings): add emulator-fixed CurrencyType enum 2026-06-27 14:30:47 +02:00
Simo 8e0ad40c19 chore(next): scaffold atomcms-next monorepo (pnpm + turborepo) 2026-06-27 14:29:24 +02:00