openhands 8292cc8ffb
Local Build and Deploy / deploy (push) Successful in 1m2s
fix(infra): serve full TLS chain for epicnabbo.nl to resolve Cloudflare 525
Traefik's ACME resolver stored the epicnabbo.nl leaf certificate without
the Let's Encrypt intermediate. With Cloudflare in Full (strict) mode the
origin TLS handshake failed (HTTP 525), breaking every asset and the whole
site layout (JS/CSS chunks, Nitro client, toolbar).

Configure the epicnabbo router to use a file-based certificate that
includes the full chain (leaf + LE YR2 intermediate), referenced from
dynamic/epicnabbo-tls.yml. Add a regeneration script and README.
2026-07-18 18:37:56 +02:00
2026-07-13 21:57:41 +02:00
2026-07-13 21:57:41 +02:00
2026-07-13 21:57:41 +02:00
2026-07-13 21:57:41 +02:00
2026-07-12 20:54:51 +02:00
2026-07-13 21:57:41 +02:00

EpicNext-CMS .

A modern, high-performance content management system for Habbo hotel emulators, built on Next.js 16 (App Router) with Prisma 7. Designed to integrate seamlessly with the Polaris MySQL/MariaDB database.

Features full public-facing website, administrative panel, NextAuth authentication (argon2id/bcrypt with MD5-to-argon2id upgrade path), real-time RCON communication with the emulator, and extensive extensibility.


Requirements

Component Version
Node.js >= 22
pnpm >= 10.33.4
MySQL / MariaDB 8.0+ / 10.6+
Redis Optional (caching / rate limiting)

1. Database Setup

EpicNext-CMS shares a database with the Polaris emulator. You may use an existing or empty database.

Create a new database:

CREATE DATABASE IF NOT EXISTS epicnext_cms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Use an existing emulator database:
Point DATABASE_URL to your existing database — the CMS reads emulator tables (users, users_currency, bans, etc.) directly.

Create CMS tables:
After configuring .env, run the migration script (step 5). This creates only CMS-owned tables (website_*, radio_*, etc.), leaving the emulator schema untouched.


2. Environment Variables

Copy .env.example to .env and configure:

cp .env.example .env

Required

DATABASE_URL=mysql://user:[email protected]:3306/epicnext_cms
AUTH_SECRET=                              # minimum 32 characters, random
HOTEL_NAME=YourHotel
APP_URL=http://localhost:3000

Database Pool (Tunable)

DATABASE_POOL_SIZE=40
DATABASE_IDLE_TIMEOUT_MS=300000
DATABASE_CONNECT_TIMEOUT_MS=10000

Password Settings

CONVERT_PASSWORDS=false                   # enable to upgrade legacy MD5 hashes to argon2id on login
PASSWORD_HASH=bcrypt                      # bcrypt (default) or argon2id

Laravel APP_KEY (2FA Migration)

Required only for reading existing Laravel-encrypted 2FA secrets:

APP_KEY=base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxx==

RCON (Emulator Bridge)

Enables live credits, badges, motto changes, rank changes, kick/ban:

RCON_HOST=127.0.0.1
RCON_PORT=3001

Badge Upload (Emulator Directory)

BADGE_UPLOAD_DIR=/path/to/emulator/assets/c_images/album1584

Email (Password Reset / Notifications)

Two options — Resend (recommended) or SMTP:

# Resend (preferred)
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxx

# OR SMTP:
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=user
SMTP_PASSWORD=password
[email protected]

OAuth (Discord / Google)

DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=

PayPal (Credit Purchases)

PAYPAL_CLIENT_ID=
PAYPAL_SECRET=
PAYPAL_API=https://api-m.sandbox.paypal.com   # sandbox for testing; live: https://api-m.paypal.com

Redis (Caching / Rate Limiting)

REDIS_URL=redis://127.0.0.1:6379

AI Content Moderation (Comments / Guestbook)

OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx

Notifications & Logging

DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
[email protected]
LOG_LEVEL=info                                # debug | info | warn | error

Emulator JAR Backup (Jobs Worker)

EMULATOR_JAR_PATH=/path/to/emulator.jar
EMULATOR_BACKUP_DIR=/path/to/backups
EMULATOR_BACKUP_KEEP=7                        # number of backups to retain

3. Install Dependencies

pnpm install

4. Generate Prisma Client

pnpm prisma:generate

Generates TypeScript types in src/generated/prisma/.


5. Run CMS Migrations

pnpm db:migrate

Executes SQL files in prisma/migrations/ against the database, creating all CMS-owned tables.

Check migration status:

pnpm db:migrate:status

6. Configure Website Settings

After starting the server (step 7) and logging in as an administrator:

  1. Navigate to Admin → CMS Settings (/admin/settings).
  2. Configure the following essentials:
    • hotel_name — your hotel name
    • habbo_imaging_url — avatar image URL (default: https://www.habbo.com/habbo-imaging/avatarimage)
    • nitro_client_url — Nitro client URL (refer to update-Nitrov3.sh)
    • logo_url — path to your logo
    • cms_favicon — favicon URL
    • min_staff_rank — minimum rank required for admin access (default: 7)
    • Optionally: theme colors, CAPTCHA, VPN blocking, and more.

7. Start the Server

Development (Hot Reload)

pnpm dev

Production

pnpm build && pnpm start

TypeScript Check

pnpm typecheck

Run Tests

pnpm test

8. Jobs Worker (Background Tasks)

Run as a persistent process (e.g., via systemd, screen, or PM2):

pnpm jobs:worker

Scheduled tasks:

  • Daily at 03:00 — Emulator JAR backup (when EMULATOR_JAR_PATH and EMULATOR_BACKUP_DIR are configured)
  • Daily at 04:00 — Cleanup of login logs older than 30 days and expired password reset tokens older than 7 days

9. First Login

  1. Open http://localhost:3000 in your browser.
  2. Register an account via /register, or log in with an existing account.
  3. To obtain administrator access, your rank must equal or exceed min_staff_rank (default: 7).
    • Set it directly in the database: UPDATE users SET rank = 7 WHERE username = 'yourname';
  4. Access the admin panel at /admin.

Optional Integrations

Emulator — RCON

For live actions (credits, badges, rank changes, kick/ban), the Polaris emulator must be running with RCON enabled and accessible at the configured RCON_HOST:RCON_PORT.

Client — Nitro

The /client page loads the Nitro client. Configure the client URL via Admin → CMS Settings (nitro_client_url).

Radio

For use with a streaming radio (e.g., Azuracast):

  • radio_now_playing_api_url
  • radio_listeners_api_url

CAPTCHA

Supports Cloudflare Turnstile and Google reCAPTCHA. Configure via Admin → CMS Settings:

  • captcha_provider — turnstile or recaptcha
  • turnstile_site_key / turnstile_secret
  • recaptcha_site_key / recaptcha_secret

Theming

12 preset themes are available via Admin → Theme (/admin/theme), along with fully customizable color schemes.


Database Architecture

Component Type Migrations
Emulator tables (users, items, rooms, etc.) Existing Polaris schema None — read-only for CMS
CMS tables (website_*, radio_*, etc.) CMS-owned prisma/migrations/*.sql (9 files)
Migration tracking cms_migrations table Auto-created

Project Structure

├── prisma/
│   ├── schema.prisma          # ~190 models (emulator + CMS)
│   └── migrations/            # 9 SQL migrations for CMS tables
├── scripts/
│   ├── apply-migrations.ts    # migration runner
│   └── jobs-worker.ts         # background task scheduler
├── src/
│   ├── app/                   # Next.js App Router (pages & API routes)
│   ├── actions/               # Server Actions
│   ├── components/            # UI components (header, navigation, etc.)
│   ├── lib/
│   │   ├── auth/              # NextAuth with password hashing & 2FA
│   │   ├── services/          # RCON, email, currency, PayPal, etc.
│   │   ├── prisma.ts          # database connection singleton
│   │   └── redis.ts           # Redis client abstraction
│   ├── messages/              # i18n translations (en, nl, de, fr, es, it)
│   └── env.ts                 # Zod-validated environment schema
├── public/assets/             # images, icons, fonts
├── .env.example               # environment template
└── update-Nitrov3.sh          # emulator & Nitro updater utility

License

This project is licensed under the CC BY-NC-SA 4.0 license. See LICENSE for details.

S
Description
No description provided
Readme CC-BY-SA-4.0
172 MiB
1 Stars 1 Watchers 0 Forks
Languages
TypeScript 95.9%
JavaScript 1.4%
Shell 1.1%
CSS 1.1%
PHP 0.3%
Other 0.1%