mirror of
https://github.com/rmoren97/mc-manager.git
synced 2026-02-10 17:40:30 -08:00
214 lines
12 KiB
Markdown
214 lines
12 KiB
Markdown
# MC-Manager — Copilot Instructions
|
|
|
|
## Project Overview
|
|
Minecraft Server Manager — a full-stack Next.js 15+ (App Router) web application for managing Minecraft server instances. Built following Rezzect's organization-wide Next.js standards.
|
|
|
|
## Tech Stack
|
|
- **Framework:** Next.js 15+ (App Router, Turbopack), React 19+, TypeScript 5.9+ (strict mode)
|
|
- **Styling:** Tailwind CSS 3.4+ with dark glassmorphism design system (cyan-500 primary, `bg-gray-900/80 backdrop-blur-lg`)
|
|
- **Database:** MongoDB 6+ via Mongoose 8+ with serverless-safe cached connections (`src/lib/mongodb.ts`)
|
|
- **Auth:** Dual-token JWT (1h access + 7d refresh) in HTTP-only cookies, mandatory 2FA via email, bcryptjs (12 rounds)
|
|
- **Containers:** Docker via dockerode — each MC server runs as its own container
|
|
- **Icons:** Lucide React only — no other icon libraries
|
|
- **Email:** Microsoft Graph API primary, SMTP (nodemailer) fallback — always implement dual-provider
|
|
|
|
## Project Structure
|
|
```
|
|
src/app/ — Pages ('use client' on every page) and API routes
|
|
src/components/ — Shared components; templates/ for reusable CRUD patterns (DataManagementTemplate)
|
|
src/contexts/ — AuthContext, ToastContext, ConfirmationContext
|
|
src/lib/ — Server utilities: auth.ts, mongodb.ts, models.ts, docker.ts, date-utils.ts, input-validation.ts, audit.ts
|
|
src/hooks/ — Custom React hooks
|
|
src/types/ — TypeScript interfaces and types
|
|
```
|
|
|
|
## Critical Conventions
|
|
- **Every page** must start with `'use client'`; add `export const dynamic = 'force-dynamic'` if using `useSearchParams`
|
|
- **Date formatting:** NEVER create custom formatters — always use `formatDate()`, `formatDateTime()`, `formatDateForInput()` from `@/lib/date-utils`
|
|
- **Images:** Always `next/image` — never raw `<img>` tags
|
|
- **CRUD pages:** Use `DataManagementTemplate` from `@/components/templates/` for consistent data management UIs
|
|
- **Drawers** over modals for detail views (`max-w-3xl`, `animate-slide-in-right`)
|
|
|
|
## API Route Pattern (every route must follow this order)
|
|
1. `validateSession(request)` → 401 if missing
|
|
2. `getClientIP(request)` for audit trail
|
|
3. `sanitizeObject(await request.json())` — sanitize ALL input
|
|
4. `isValidObjectId()` / `isValidEmail()` — validate params
|
|
5. Permission check → 403 + audit log if denied
|
|
6. `connectToDatabase()` then business logic
|
|
7. `createAuditLog()` for every CREATE/UPDATE/DELETE (success AND failure)
|
|
8. Return proper HTTP status: 200/201/400/401/403/404/409/500
|
|
|
|
## Security (non-negotiable)
|
|
- Server-side permission checks are **authoritative**; client-side checks are UI hints only
|
|
- Permission format: `resource:action` (e.g., `servers:edit`, `servers:view:department`)
|
|
- Sanitize all inputs via `sanitizeObject()` from `@/lib/input-validation.ts`
|
|
- Parameterized DB queries only — never string concatenation
|
|
- Audit log ALL mutations with previous/new values and client IP
|
|
|
|
## UI Patterns (Dark Theme)
|
|
- **Base background:** `bg-gray-950` (page), `bg-gray-900` (surfaces), `bg-gray-800` (elevated elements)
|
|
- **Color semantics:** cyan=primary, emerald=success/active, amber=warning/pending, red=error/danger, gray=neutral
|
|
- **Text colors:** `text-gray-100` (primary), `text-gray-400` (secondary), `text-gray-500` (muted)
|
|
- **Animations:** Only animate `transform` and `opacity`, keep under 300ms
|
|
- **Buttons:** `bg-cyan-500 hover:bg-cyan-600 text-white rounded-lg` (primary), `bg-red-500 hover:bg-red-600` (danger), `bg-gray-700 hover:bg-gray-600 text-gray-200` (secondary)
|
|
- **Inputs:** `bg-gray-800 border-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-cyan-500 focus:border-transparent placeholder-gray-500`
|
|
- **Cards:** `bg-gray-900/80 backdrop-blur-lg rounded-lg shadow-lg border border-gray-700/50 p-6`
|
|
- **Glassmorphism card:** `bg-gray-800/60 backdrop-blur-lg rounded-lg border border-gray-700/50 shadow-xl`
|
|
- **Tables:** `bg-gray-900` body, `bg-gray-800/50` header, `divide-gray-700`, `hover:bg-gray-800` rows
|
|
- **Badges:** `bg-cyan-500/20 text-cyan-400` (info), `bg-emerald-500/20 text-emerald-400` (success), `bg-amber-500/20 text-amber-400` (warning), `bg-red-500/20 text-red-400` (error)
|
|
- **Borders:** `border-gray-700` (standard), `border-gray-700/50` (subtle)
|
|
- **Import order:** React hooks → Next.js hooks → contexts → lib utilities → components
|
|
|
|
## Minecraft Domain & Server Types
|
|
|
|
Each server instance has a **type** that determines its capabilities:
|
|
|
|
| Type | Examples | Supports Plugins | Supports Mods |
|
|
|------|----------|:-:|:-:|
|
|
| `vanilla` | Official Mojang JAR | ✗ | ✗ |
|
|
| `bukkit` | Spigot, PaperMC, Purpur, etc. | ✓ | ✗ |
|
|
| `forge` | Forge | ✗ | ✓ |
|
|
| `fabric` | Fabric | ✗ | ✓ |
|
|
|
|
**Feature matrix by type — gate UI and API logic on `server.type`:**
|
|
- **All types:** start/stop/restart, console streaming, command execution, server.properties editing, JVM args, backup/restore, player management (whitelist, ops, bans)
|
|
- **Bukkit-based only:** plugin install/remove/enable/disable (JAR-based in `plugins/` directory)
|
|
- **Forge/Fabric only:** mod install/remove/enable/disable (JAR-based in `mods/` directory)
|
|
- **Vanilla:** no extension management — only core server features
|
|
|
|
### Core Feature Areas
|
|
1. **Server Lifecycle** — create, start, stop, restart, delete instances; real-time status (online/offline/starting/stopping)
|
|
2. **Console** — live log streaming (tail server stdout), send commands to server stdin
|
|
3. **Configuration** — edit server.properties, JVM memory/flags, world settings per instance
|
|
4. **Backups** — manual + scheduled backups of world data; restore to point-in-time
|
|
5. **Plugins** (bukkit only) — upload/install/remove JARs; enable/disable without removing
|
|
6. **Mods** (forge/fabric only) — upload/install/remove JARs; enable/disable without removing
|
|
7. **Player Management** — whitelist add/remove, op/deop, ban/unban, view online players
|
|
|
|
## Data Models (Mongoose schemas in `src/lib/models.ts`)
|
|
|
|
### User
|
|
- `username`, `email`, `passwordHash` (bcrypt 12 rounds)
|
|
- `roles: [ObjectId]` → references Role
|
|
- `twoFactorCode`, `twoFactorExpiry` — for mandatory 2FA
|
|
- `loginAttempts`, `lockUntil` — account lockout (5 attempts → 30 min)
|
|
- `status`: active | inactive | locked
|
|
- `lastLogin`, `createdAt`, `updatedAt`
|
|
|
|
### Role
|
|
- `name` (e.g., Admin, Operator, Viewer)
|
|
- `permissions: [{ resource: string, actions: string[] }]`
|
|
- `description`, `isDefault`, `createdAt`
|
|
|
|
### Server
|
|
- `name`, `type`: vanilla | bukkit | forge | fabric
|
|
- `version` (MC version, e.g., "1.21.4")
|
|
- `dockerImage` (default `itzg/minecraft-server`, or a custom image)
|
|
- `containerId` (Docker container ID — set after creation)
|
|
- `containerName` (e.g., `mc-{serverId}`)
|
|
- `port` (host port mapped to container 25565)
|
|
- `rconPort` (host port mapped to container 25575, optional)
|
|
- `status`: online | offline | starting | stopping | crashed
|
|
- `maxPlayers`, `memory` (min/max heap in MB)
|
|
- `jvmArgs: [string]`
|
|
- `autoStart: boolean`, `autoRestart: boolean`
|
|
- `backupSchedule`: cron expression (e.g., `0 */6 * * *` = every 6h) or `null` if manual-only
|
|
- `backupRetention`: max number of backups to keep per server (oldest auto-deleted)
|
|
- `createdBy: ObjectId` → User who created it
|
|
- `createdAt`, `updatedAt`
|
|
|
|
### Backup
|
|
- `serverId: ObjectId` → Server
|
|
- `filename`, `filePath`, `fileSize`
|
|
- `type`: manual | scheduled
|
|
- `status`: completed | in_progress | failed
|
|
- `createdBy: ObjectId`, `createdAt`
|
|
|
|
### AuditLog
|
|
- Standard org pattern: `action`, `entityType`, `entityId`, `entityName`, `userId`, `userName`, `userEmail`, `previousValues`, `newValues`, `changes`, `clientIP`, `status`, `statusCode`
|
|
|
|
## Permissions
|
|
|
|
Format: `resource:action`. Relevant resources for this project:
|
|
|
|
```
|
|
servers:view servers:create servers:edit servers:delete
|
|
servers:start servers:stop servers:restart servers:console
|
|
backups:view backups:create backups:restore backups:delete
|
|
plugins:view plugins:install plugins:remove plugins:toggle
|
|
mods:view mods:install mods:remove mods:toggle
|
|
players:view players:whitelist players:op players:ban
|
|
users:view users:create users:edit users:delete
|
|
roles:view roles:create roles:edit roles:delete
|
|
audit:view
|
|
```
|
|
|
|
Admin role gets `*:*` (wildcard). Always check `server.type` before allowing plugin/mod actions — return 400 if mismatched (e.g., plugin install on a Forge server).
|
|
|
|
## Docker Architecture
|
|
|
|
Every Minecraft server runs as an isolated Docker container. Use **dockerode** (`src/lib/docker.ts`) to interact with the Docker Engine API via Unix socket.
|
|
|
|
### Docker Images
|
|
- **Default:** `itzg/minecraft-server` — supports all server types via `TYPE` env var (e.g., `VANILLA`, `PAPER`, `SPIGOT`, `FORGE`, `FABRIC`)
|
|
- **Custom:** Users can specify any Docker image in `server.dockerImage`; when custom, the app still bind-mounts the same volume layout but skips `itzg`-specific env vars — the user is responsible for image compatibility
|
|
- Store `dockerImage` on the Server model; default to `itzg/minecraft-server` if not provided
|
|
|
|
### Container Lifecycle
|
|
- **Create:** `docker.createContainer()` with `server.dockerImage`, bind-mount a host volume for persistent data
|
|
- **Start/Stop/Restart:** `container.start()`, `container.stop()`, `container.restart()` — update `server.status` in MongoDB to match
|
|
- **Delete:** `container.remove({ force: true })`, then optionally clean up host volume
|
|
- **Status sync:** On app startup and periodically, reconcile `server.status` with `container.inspect()` state
|
|
|
|
### Volume Layout
|
|
Each server gets a host-mounted volume at a configurable base path (env `MC_SERVERS_PATH`, default `/opt/mc-servers/`):
|
|
```
|
|
/opt/mc-servers/{serverId}/
|
|
├── server.properties # MC config (editable via API)
|
|
├── world/ # World data (backed up)
|
|
├── plugins/ # Bukkit-type only
|
|
├── mods/ # Forge/Fabric only
|
|
├── logs/ # Server logs
|
|
└── backups/ # Backup archives
|
|
```
|
|
|
|
### Console & Logs
|
|
- **Log streaming:** `container.logs({ follow: true, stdout: true, stderr: true })` → stream to client via SSE or WebSocket
|
|
- **Command execution:** `container.exec()` to run `rcon-cli` or attach to stdin to send commands
|
|
- Alternative: use RCON protocol directly on the `rconPort` if RCON is enabled in server.properties
|
|
|
|
### Key Patterns for `src/lib/docker.ts`
|
|
- Export a singleton `getDockerClient()` that returns a cached dockerode instance
|
|
- All container operations must catch Docker API errors and map to proper HTTP status codes
|
|
- Container names follow convention: `mc-{server._id}` for easy lookup
|
|
- Always set resource limits: `--memory` from `server.memory.max`, CPU shares as needed
|
|
- Use `RestartPolicy: { Name: 'unless-stopped' }` when `server.autoRestart` is true
|
|
|
|
### Backups
|
|
- Pause world saving (`save-off` + `save-all` via RCON/exec) → tar/gzip the `world/` directory → resume (`save-on`)
|
|
- Store backup archives in `{serverDir}/backups/` and record metadata in the Backup model
|
|
- Restore: stop container → replace `world/` with extracted backup → start container
|
|
|
|
### Scheduled Backups (node-cron)
|
|
- Use **node-cron** running inside the Next.js process — no external scheduler needed
|
|
- Each server stores a `backupSchedule` cron expression (e.g., `0 */6 * * *`) and `backupRetention` count
|
|
- On app startup, query all servers with a `backupSchedule` and register cron jobs via `cron.schedule()`
|
|
- When a server's schedule is created/updated/deleted via API, dynamically add/update/remove the cron job
|
|
- Keep a `Map<serverId, CronJob>` in memory for lifecycle management
|
|
- `backupRetention`: after each successful backup, delete oldest archives exceeding the limit
|
|
- Scheduled backups set `backup.type = 'scheduled'`; manual backups set `backup.type = 'manual'`
|
|
|
|
### Environment Variables (Docker-specific)
|
|
```env
|
|
MC_SERVERS_PATH=/opt/mc-servers # Base path for server volumes
|
|
DOCKER_SOCKET=/var/run/docker.sock # Docker socket path (default)
|
|
```
|
|
|
|
## Commands
|
|
```bash
|
|
npm run dev # Start dev server (port 3000, Turbopack)
|
|
npm run build # Production build
|
|
npm run lint # ESLint check
|
|
```
|