- Replace Prisma client runtime with Drizzle ORM (zero Prisma engine/query engine in production) - Add Prisma-compatible facade (@/lib/prisma-facade.ts) backed by Drizzle for backwards compatibility - Runtime queries route through Drizzle ORM; @prisma/client is now devDependency (types only) - Remove @prisma/adapter-mariadb dependency; delete prisma-pool.ts and types/prisma.ts - New Drizzle schema layer: src/db/schema.ts (176 tables) and src/lib/db.ts (connection) - Update README documenting the dual-layer ORM architecture - Restore src/generated/ gitignore (build artifact for local type generation) - 0 TypeScript errors, 583 tests passing The facade intentionally uses `any` types to match the Prisma Client API surface, allowing existing code to run unmodified while routing queries through Drizzle at runtime.
291 lines
12 KiB
Markdown
291 lines
12 KiB
Markdown
# EpicNext-CMS v1.0.1
|
|
|
|
A modern, high-performance content management system for Habbo hotel emulators, built on **Next.js 16** (App Router) with **Drizzle ORM** and **React 19**. Designed to integrate seamlessly with Polaris / Arcturus Morningstar MySQL/MariaDB databases.
|
|
|
|
Features a premium animated homepage (typewriter hero, floating orbs, scroll counters), a full admin panel, NextAuth authentication (bcrypt with MD5-to-bcrypt upgrade), real-time RCON communication, Server-Sent Events for live radio data, smooth page transitions, and PM2 production deployment.
|
|
|
|
---
|
|
|
|
## System Requirements
|
|
|
|
| Component | Version | Notes |
|
|
| --------------- | -------------- | ---------------------------------------- |
|
|
| Node.js | >= 22 | Required by Next.js 16 |
|
|
| pnpm | >= 10.33.4 | Package manager (npm/yarn not supported) |
|
|
| MySQL / MariaDB | 8.0+ / 10.6+ | Shared with the emulator |
|
|
| Redis | 7.x+ | Optional — caching, rate limiting, SSE |
|
|
| Java | 17+ | Required only if building the emulator |
|
|
| Maven | 3.9+ | Required only if building the emulator |
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### 1. Clone & Install
|
|
|
|
```bash
|
|
git clone https://gitlab.epicnabbo.nl/remco/EpicNext-Cms.git
|
|
cd EpicNext-Cms
|
|
pnpm install
|
|
```
|
|
|
|
### 2. Database Setup
|
|
|
|
The CMS shares a database with the Polaris/Arcturus emulator. Use an existing database or create a new one:
|
|
|
|
```sql
|
|
CREATE DATABASE IF NOT EXISTS epicnext_cms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
```
|
|
|
|
The CMS reads emulator-owned tables (`users`, `items`, `rooms`, `bans`, etc.) directly. It never creates, alters, or drops them. The Drizzle schema in `src/db/schema.ts` is generated from the existing database structure and does not modify it.
|
|
|
|
> **Note:** The CMS does **not** own the database schema — it maps to tables that are managed by the emulator. All Drizzle schema definitions use `drizzle-orm`'s runtime mapping (no `drizzle-kit push/migrate` is ever run against the emulator schema). CMS-owned tables (`website_*`, `radio_*`, etc.) are created via idempotent SQL files in `prisma/migrations/`.
|
|
|
|
### 3. Configure Environment
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
Edit `.env` with at minimum:
|
|
|
|
```dotenv
|
|
DATABASE_URL=mysql://user:[email protected]:3306/epicnext_cms
|
|
AUTH_SECRET=<random 32+ character string>
|
|
HOTEL_NAME=YourHotel
|
|
APP_URL=http://localhost:3000
|
|
```
|
|
|
|
See `.env.example` for all optional variables (RCON, email, Redis, OAuth, PayPal, etc.).
|
|
|
|
### 4. Type Generation (Optional for Development)
|
|
|
|
```bash
|
|
pnpm prisma:generate
|
|
```
|
|
|
|
Generates TypeScript types in `src/generated/prisma/`. This is only needed for developer type-checking of the `prisma` facade — it does not add any Prisma runtime overhead in production. The facade (`src/lib/prisma-facade.ts`) routes all queries through Drizzle ORM at runtime.
|
|
|
|
Alternatively, you can work with Drizzle directly via the typed schema in `src/db/schema.ts`:
|
|
|
|
```ts
|
|
import { db } from "@/lib/db";
|
|
import { users } from "@/db/schema";
|
|
const result = await db.select().from(users).where(eq(users.username, "hello"));
|
|
```
|
|
|
|
### 5. Run CMS Migrations
|
|
|
|
```bash
|
|
pnpm db:migrate
|
|
```
|
|
|
|
Creates all CMS-owned tables (`website_*`, `radio_*`, `acl_*`, `admin_audit_log`, etc.) via idempotent SQL files in `prisma/migrations/`. Emulator tables are never touched.
|
|
|
|
Check migration status:
|
|
|
|
```bash
|
|
pnpm db:migrate:status
|
|
```
|
|
|
|
### 6. Build & Start
|
|
|
|
```bash
|
|
# Development (hot reload)
|
|
pnpm dev
|
|
|
|
# Production
|
|
pnpm build && pnpm start
|
|
```
|
|
|
|
Open `http://localhost:3000` in your browser.
|
|
|
|
### 7. First Login
|
|
|
|
1. Register an account at `/register`, or log in with an existing emulator account.
|
|
2. Grant yourself admin access: `UPDATE users SET rank = 7 WHERE username = 'yourname';`
|
|
3. Visit `/admin` and configure your hotel via **Admin → CMS Settings**.
|
|
|
|
---
|
|
|
|
## Production Deployment (PM2)
|
|
|
|
```bash
|
|
pnpm build
|
|
pm2 start pnpm --name "next" -- start
|
|
pm2 save
|
|
```
|
|
|
|
Restart after updates:
|
|
|
|
```bash
|
|
git pull
|
|
pnpm install
|
|
pnpm build
|
|
pm2 restart next
|
|
```
|
|
|
|
The CMS runs behind an nginx reverse proxy on the default port 3000. Static assets (media uploads) are persisted via `/api/media/*` and survive rebuilds.
|
|
|
|
---
|
|
|
|
## Scripts
|
|
|
|
| Command | Description |
|
|
| ---------------------- | -------------------------------------------------- |
|
|
| `pnpm dev` | Start development server (hot reload) |
|
|
| `pnpm build` | Production build |
|
|
| `pnpm start` | Start production server |
|
|
| `pnpm typecheck` | Run TypeScript type checking |
|
|
| `pnpm test` | Run all tests (Vitest) |
|
|
| `pnpm db:migrate` | Apply pending SQL migrations |
|
|
| `pnpm db:migrate:status` | Show migration status |
|
|
| `pnpm analyze` | Build + open bundle analyzer |
|
|
| `pnpm jobs:worker` | Start background task worker (systemd / PM2) |
|
|
| `pnpm biome:check` | Lint and format code |
|
|
|
|
---
|
|
|
|
## Performance Features
|
|
|
|
| Feature | Description |
|
|
| ------------------------------ | -------------------------------------------------------------- |
|
|
| **React Compiler** | Automatic memoization — reduces unnecessary re-renders |
|
|
| **View Transitions API** | Native browser transitions between page navigations |
|
|
| **Lenis Smooth Scroll** | Fluid, customizable scrolling (respects `prefers-reduced-motion`) |
|
|
| **Server-Sent Events** | Real-time radio now-playing & listeners via SSE (no polling) |
|
|
| **Redis Caching** | Caches API responses (home, radio config) up to 30s in Redis |
|
|
| **Bundle Analyzer** | Run `pnpm analyze` to visualize and optimize bundle sizes |
|
|
| **RCON (TCP Socket)** | Live commands to the emulator (credits, badges, kick, ban) |
|
|
| **Streaming & Suspense** | Next.js App Router streaming for fast page loads |
|
|
| **Automatic Image Optimization** | `next/image` with Sharp for resizing and WebP/AVIF |
|
|
| **CSS-based Animations** | `input-glow`, `btn-shine`, `Reveal` scroll animations, floating orbs |
|
|
| **Compression** | Gzip compression enabled on all responses |
|
|
| **Stale Times** | Optimized router cache (30s dynamic, 180s static) |
|
|
| **PWA** | Service worker with skip-waiting, stale CSS chunk recovery |
|
|
| **Biome** | Fast linting and formatting (replaces ESLint + Prettier) |
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
```
|
|
├── prisma/
|
|
│ ├── schema.prisma # ~190 models (emulator + CMS) — used for type generation only
|
|
│ └── migrations/ # 16 SQL migrations for CMS tables
|
|
├── src/
|
|
│ ├── db/
|
|
│ │ ├── schema.ts # Drizzle ORM schema (176 tables — runtime data layer)
|
|
│ │ └── migrations/ # Drizzle migration files (if used)
|
|
│ ├── app/ # Next.js App Router (pages & API routes)
|
|
│ ├── actions/ # Server Actions
|
|
│ ├── components/ # UI components
|
|
│ ├── lib/
|
|
│ │ ├── auth/ # NextAuth, password hashing, 2FA, SSO tickets
|
|
│ │ ├── services/ # RCON, email, currency, PayPal, alerts
|
|
│ │ ├── prisma.ts # Prisma-compatible facade (routes to Drizzle at runtime)
|
|
│ │ ├── prisma-facade.ts # Drizzle-backed implementation of Prisma API surface
|
|
│ │ ├── db.ts # Drizzle connection singleton (runtime)
|
|
│ │ ├── redis.ts # Redis client (ioredis)
|
|
│ │ ├── redis-cache.ts # Redis caching utility for API routes
|
|
│ │ ├── cache.ts # In-memory cache fallback
|
|
│ │ ├── motion.ts # Framer Motion animation variants
|
|
│ │ └── use-event-source.ts # React hook for SSE subscriptions
|
|
│ ├── messages/ # i18n translations (en, nl, de, fr, es, it, pt, da, no, sv)
|
|
│ └── env.ts # Zod-validated environment schema
|
|
├── public/
|
|
│ ├── assets/ # Images, icons, fonts
|
|
│ └── scripts/ # Client-side scripts (theme-init.js)
|
|
├── update-Nitrov3.sh # Emulator & Nitro updater utility
|
|
├── next.config.ts # Next.js configuration
|
|
└── .env.example # Environment template with all options
|
|
```
|
|
|
|
### Database Ownership
|
|
|
|
| Component | Type | Migrations |
|
|
| ------------------------------------------------- | ----------------------- | ----------------------------------- |
|
|
| Emulator tables (`users`, `items`, `rooms`, etc.) | Existing Polaris schema | None — CMS reads/writes only |
|
|
| CMS tables (`website_*`, `radio_*`, etc.) | CMS-owned | `prisma/migrations/*.sql` (16 files) |
|
|
| Migration tracking | `cms_migrations` table | Auto-created by migration runner |
|
|
|
|
### ORM Architecture
|
|
|
|
The CMS uses a dual-layer approach:
|
|
|
|
- **Runtime (Drizzle ORM)**: `@/lib/db` exposes a Drizzle singleton connected to the MySQL/MariaDB database. All new code should use this directly. The schema is defined in `src/db/schema.ts` with 176 tables typed against the existing database columns.
|
|
- **Legacy Compatibility (Prisma Facade)**: `@/lib/prisma` provides a Prisma-compatible API surface backed by Drizzle. This allows existing code to continue working without refactoring. The facade (`@/lib/prisma-facade.ts`) implements the Prisma client API (`findMany`, `findUnique`, `create`, `$transaction`, `$queryRaw`, etc.) but routes all queries through Drizzle at runtime — **no Prisma client engine or query engine is loaded in production**.
|
|
- **Type Generation**: `src/generated/prisma/` (regenerated via `pnpm prisma:generate`) exists solely for TypeScript type-checking. It is `gitignore`d and is never bundled in the production build.
|
|
|
|
Migration path: new database access should use `import { db } from "@/lib/db"` with queries built via `src/db/schema.ts`. The facade is maintained for backwards compatibility but is not recommended for new code.
|
|
|
|
---
|
|
|
|
## Optional Integrations
|
|
|
|
### Emulator — RCON
|
|
|
|
For live actions (credits, badges, rank changes, kick, ban, hotel alerts). The emulator must be running with RCON enabled at `RCON_HOST:RCON_PORT`.
|
|
|
|
### Client — Nitro
|
|
|
|
The `/client` page loads the Nitro client. Configure the client URL via **Admin → CMS Settings** (`nitro_client_url`). See `update-Nitrov3.sh` for deployment.
|
|
|
|
### Radio
|
|
|
|
Supports any streaming radio (e.g., Azuracast). Configure endpoints via CMS Settings:
|
|
|
|
- `radio_now_playing_api_url`
|
|
- `radio_listeners_api_url`
|
|
|
|
The radio player uses SSE for real-time updates (10s interval, no polling).
|
|
|
|
### Background Jobs
|
|
|
|
Run as a persistent process:
|
|
|
|
```bash
|
|
pnpm jobs:worker
|
|
```
|
|
|
|
Scheduled tasks:
|
|
- **Daily 03:00** — Emulator JAR backup (requires `EMULATOR_JAR_PATH` + `EMULATOR_BACKUP_DIR`)
|
|
- **Daily 04:00** — Cleanup login logs (>30 days) and expired password reset tokens (>7 days)
|
|
|
|
### CAPTCHA
|
|
|
|
Supports Cloudflare Turnstile and Google reCAPTCHA. Configure via CMS Settings.
|
|
|
|
### Theming
|
|
|
|
12 preset themes with fully customizable colors via **Admin → Theme** (`/admin/theme`).
|
|
|
|
### AI Content Moderation
|
|
|
|
Optional OpenAI-powered moderation for comments and guestbook posts. Set `OPENAI_API_KEY`.
|
|
|
|
---
|
|
|
|
## Development
|
|
|
|
```bash
|
|
pnpm dev # Start with hot reload
|
|
pnpm typecheck # Type check all files
|
|
pnpm test # Run test suite
|
|
pnpm analyze # Build and analyze bundle sizes
|
|
pnpm biome:check # Lint and format
|
|
```
|
|
|
|
### Contributing
|
|
|
|
1. Ensure typecheck and tests pass: `pnpm typecheck && pnpm test`
|
|
2. Follow existing code conventions (Server Components where possible, minimal client boundaries)
|
|
3. Use the `src/lib/motion.ts` animation variants for consistent animations
|
|
4. SQL migrations in `prisma/migrations/` must be idempotent
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
CC BY-NC-SA 4.0. See `LICENSE` for details.
|