import mongoose, { Schema, Document, Model } from 'mongoose' // ─── User ──────────────────────────────────────────────────────── export interface IUser extends Document { username: string email: string passwordHash: string roles: mongoose.Types.ObjectId[] twoFactorCode: string | null twoFactorExpiry: Date | null loginAttempts: number lockUntil: Date | null status: 'active' | 'inactive' | 'locked' lastLogin: Date | null createdAt: Date updatedAt: Date } const userSchema = new Schema( { username: { type: String, required: true, unique: true, trim: true }, email: { type: String, required: true, unique: true, trim: true, lowercase: true }, passwordHash: { type: String, required: true }, roles: [{ type: Schema.Types.ObjectId, ref: 'Role' }], twoFactorCode: { type: String, default: null }, twoFactorExpiry: { type: Date, default: null }, loginAttempts: { type: Number, default: 0 }, lockUntil: { type: Date, default: null }, status: { type: String, enum: ['active', 'inactive', 'locked'], default: 'active' }, lastLogin: { type: Date, default: null }, }, { timestamps: true } ) // ─── Role ──────────────────────────────────────────────────────── export interface IPermission { resource: string actions: string[] } export interface IRole extends Document { name: string permissions: IPermission[] description: string isDefault: boolean createdAt: Date updatedAt: Date } const roleSchema = new Schema( { name: { type: String, required: true, unique: true, trim: true }, permissions: [ { resource: { type: String, required: true }, actions: [{ type: String, required: true }], }, ], description: { type: String, default: '' }, isDefault: { type: Boolean, default: false }, }, { timestamps: true } ) // ─── Server ────────────────────────────────────────────────────── export interface IServer extends Document { name: string type: 'vanilla' | 'bukkit' | 'forge' | 'fabric' version: string dockerImage: string containerId: string | null containerName: string port: number rconPort: number | null status: 'online' | 'offline' | 'starting' | 'stopping' | 'crashed' maxPlayers: number memory: { min: number; max: number } jvmArgs: string[] autoStart: boolean autoRestart: boolean backupSchedule: string | null backupRetention: number admins: mongoose.Types.ObjectId[] createdBy: mongoose.Types.ObjectId createdAt: Date updatedAt: Date } const serverSchema = new Schema( { name: { type: String, required: true, trim: true }, type: { type: String, required: true, enum: ['vanilla', 'bukkit', 'forge', 'fabric'] }, version: { type: String, required: true }, dockerImage: { type: String, default: 'itzg/minecraft-server' }, containerId: { type: String, default: null }, containerName: { type: String, required: true, unique: true }, port: { type: Number, required: true }, rconPort: { type: Number, default: null }, status: { type: String, enum: ['online', 'offline', 'starting', 'stopping', 'crashed'], default: 'offline', }, maxPlayers: { type: Number, default: 20 }, memory: { min: { type: Number, default: 512 }, max: { type: Number, default: 1024 }, }, jvmArgs: [{ type: String }], autoStart: { type: Boolean, default: false }, autoRestart: { type: Boolean, default: true }, backupSchedule: { type: String, default: null }, backupRetention: { type: Number, default: 5 }, admins: [{ type: Schema.Types.ObjectId, ref: 'User', default: [] }], createdBy: { type: Schema.Types.ObjectId, ref: 'User', required: true }, }, { timestamps: true } ) // ─── Backup ────────────────────────────────────────────────────── export interface IBackup extends Document { serverId: mongoose.Types.ObjectId filename: string filePath: string fileSize: number type: 'manual' | 'scheduled' status: 'completed' | 'in_progress' | 'failed' createdBy: mongoose.Types.ObjectId createdAt: Date } const backupSchema = new Schema( { serverId: { type: Schema.Types.ObjectId, ref: 'Server', required: true, index: true }, filename: { type: String, required: true }, filePath: { type: String, required: true }, fileSize: { type: Number, default: 0 }, type: { type: String, enum: ['manual', 'scheduled'], required: true }, status: { type: String, enum: ['completed', 'in_progress', 'failed'], default: 'in_progress', }, createdBy: { type: Schema.Types.ObjectId, ref: 'User' }, }, { timestamps: true } ) // ─── Audit Log ─────────────────────────────────────────────────── export interface IAuditLog extends Document { action: string entityType: string entityId?: string entityName?: string userId?: string userName?: string userEmail?: string previousValues: Record | null newValues: Record | null changes: Record | null clientIP: string status: 'SUCCESS' | 'FAILED' statusCode: number errorMessage?: string createdAt: Date } const auditLogSchema = new Schema( { action: { type: String, required: true, index: true }, entityType: { type: String, required: true, index: true }, entityId: { type: String, default: '' }, entityName: { type: String, default: '' }, userId: { type: String, default: '', index: true }, userName: { type: String, default: '' }, userEmail: { type: String, default: '' }, previousValues: { type: Schema.Types.Mixed, default: null }, newValues: { type: Schema.Types.Mixed, default: null }, changes: { type: Schema.Types.Mixed, default: null }, clientIP: { type: String, default: '' }, status: { type: String, enum: ['SUCCESS', 'FAILED'], required: true }, statusCode: { type: Number, required: true }, errorMessage: { type: String }, }, { timestamps: true } ) // ─── Model Exports (prevent re-compilation in dev) ─────────────── export const User: Model = mongoose.models.User || mongoose.model('User', userSchema) export const Role: Model = mongoose.models.Role || mongoose.model('Role', roleSchema) export const Server: Model = mongoose.models.Server || mongoose.model('Server', serverSchema) export const Backup: Model = mongoose.models.Backup || mongoose.model('Backup', backupSchema) export const AuditLog: Model = mongoose.models.AuditLog || mongoose.model('AuditLog', auditLogSchema)