import { sqliteTable, text, integer, real, uniqueIndex, } from "drizzle-orm/sqlite-core"; import { createInsertSchema, createSelectSchema } from "drizzle-zod"; // --------------------------------------------------------------------------- // Better Auth core tables // --------------------------------------------------------------------------- export const users = sqliteTable("users", { id: text("id").primaryKey(), name: text("name").notNull(), email: text("email").notNull().unique(), emailVerified: integer("email_verified", { mode: "boolean" }) .notNull() .default(false), image: text("image"), role: text("role", { enum: ["superadmin", "admin", "moderator"], }) .notNull() .default("moderator"), createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }).notNull(), }); export const sessions = sqliteTable("sessions", { id: text("id").primaryKey(), userId: text("user_id") .notNull() .references(() => users.id, { onDelete: "cascade" }), token: text("token").notNull().unique(), expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(), ipAddress: text("ip_address"), userAgent: text("user_agent"), createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }).notNull(), }); export const accounts = sqliteTable("accounts", { id: text("id").primaryKey(), userId: text("user_id") .notNull() .references(() => users.id, { onDelete: "cascade" }), accountId: text("account_id").notNull(), providerId: text("provider_id").notNull(), accessToken: text("access_token"), refreshToken: text("refresh_token"), idToken: text("id_token"), expiresAt: integer("expires_at", { mode: "timestamp_ms" }), password: text("password"), // hashed password for email/password auth createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }).notNull(), }); export const verifications = sqliteTable("verifications", { id: text("id").primaryKey(), identifier: text("identifier").notNull(), value: text("value").notNull(), expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(), createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }).notNull(), }); // --------------------------------------------------------------------------- // Invitation system // --------------------------------------------------------------------------- export const invitations = sqliteTable("invitations", { id: text("id").primaryKey(), email: text("email").notNull(), role: text("role", { enum: ["superadmin", "admin", "moderator"], }) .notNull() .default("moderator"), invitedBy: text("invited_by") .notNull() .references(() => users.id, { onDelete: "cascade" }), token: text("token").notNull().unique(), expiresAt: integer("expires_at").notNull(), acceptedAt: integer("accepted_at"), createdAt: integer("created_at").notNull(), }); // --------------------------------------------------------------------------- // Minecraft player management // --------------------------------------------------------------------------- export const mcPlayers = sqliteTable( "mc_players", { id: text("id").primaryKey(), // uuid uuid: text("uuid").notNull(), // Minecraft UUID username: text("username").notNull(), firstSeen: integer("first_seen"), lastSeen: integer("last_seen"), isOnline: integer("is_online", { mode: "boolean" }).notNull().default(false), playTime: integer("play_time").notNull().default(0), // minutes role: text("role"), isBanned: integer("is_banned", { mode: "boolean" }) .notNull() .default(false), notes: text("notes"), }, (table) => [uniqueIndex("mc_players_uuid_idx").on(table.uuid)], ); export const playerBans = sqliteTable("player_bans", { id: text("id").primaryKey(), playerId: text("player_id") .notNull() .references(() => mcPlayers.id, { onDelete: "cascade" }), reason: text("reason"), bannedBy: text("banned_by").references(() => users.id, { onDelete: "set null", }), bannedAt: integer("banned_at").notNull(), expiresAt: integer("expires_at"), isActive: integer("is_active", { mode: "boolean" }).notNull().default(true), unbannedBy: text("unbanned_by").references(() => users.id, { onDelete: "set null", }), unbannedAt: integer("unbanned_at"), }); export const playerChatHistory = sqliteTable("player_chat_history", { id: text("id").primaryKey(), playerId: text("player_id") .notNull() .references(() => mcPlayers.id, { onDelete: "cascade" }), message: text("message").notNull(), channel: text("channel"), timestamp: integer("timestamp").notNull(), serverId: text("server_id"), }); export const playerSpawnPoints = sqliteTable("player_spawn_points", { id: text("id").primaryKey(), playerId: text("player_id") .notNull() .references(() => mcPlayers.id, { onDelete: "cascade" }), name: text("name").notNull(), world: text("world").notNull(), x: real("x").notNull(), y: real("y").notNull(), z: real("z").notNull(), createdAt: integer("created_at").notNull(), }); // --------------------------------------------------------------------------- // Plugin management // --------------------------------------------------------------------------- export const plugins = sqliteTable("plugins", { id: text("id").primaryKey(), name: text("name").notNull(), version: text("version"), description: text("description"), isEnabled: integer("is_enabled", { mode: "boolean" }) .notNull() .default(true), jarFile: text("jar_file"), config: text("config"), // JSON blob installedAt: integer("installed_at").notNull(), updatedAt: integer("updated_at").notNull(), }); // --------------------------------------------------------------------------- // Backup management // --------------------------------------------------------------------------- export const backups = sqliteTable("backups", { id: text("id").primaryKey(), name: text("name").notNull(), type: text("type", { enum: ["worlds", "plugins", "config", "full"], }).notNull(), size: integer("size"), // bytes path: text("path"), createdAt: integer("created_at").notNull(), status: text("status", { enum: ["pending", "running", "completed", "failed"], }) .notNull() .default("pending"), triggeredBy: text("triggered_by").references(() => users.id, { onDelete: "set null", }), }); // --------------------------------------------------------------------------- // Scheduled tasks // --------------------------------------------------------------------------- export const scheduledTasks = sqliteTable("scheduled_tasks", { id: text("id").primaryKey(), name: text("name").notNull(), description: text("description"), cronExpression: text("cron_expression").notNull(), command: text("command").notNull(), // MC command to run isEnabled: integer("is_enabled", { mode: "boolean" }) .notNull() .default(true), lastRun: integer("last_run"), nextRun: integer("next_run"), createdAt: integer("created_at").notNull(), updatedAt: integer("updated_at").notNull(), }); // --------------------------------------------------------------------------- // Audit logs // --------------------------------------------------------------------------- export const auditLogs = sqliteTable("audit_logs", { id: text("id").primaryKey(), userId: text("user_id").references(() => users.id, { onDelete: "set null" }), action: text("action").notNull(), target: text("target"), targetId: text("target_id"), details: text("details"), // JSON blob ipAddress: text("ip_address"), createdAt: integer("created_at").notNull(), }); // --------------------------------------------------------------------------- // Server settings (singleton row, id = 1) // --------------------------------------------------------------------------- export const serverSettings = sqliteTable("server_settings", { id: integer("id").primaryKey().default(1), minecraftPath: text("minecraft_path"), serverJar: text("server_jar"), serverVersion: text("server_version"), serverType: text("server_type", { enum: ["vanilla", "paper", "spigot", "bukkit", "fabric", "forge", "bedrock"], }), maxRam: integer("max_ram").default(4096), minRam: integer("min_ram").default(1024), rconEnabled: integer("rcon_enabled", { mode: "boolean" }) .notNull() .default(false), rconPort: integer("rcon_port").default(25575), rconPassword: text("rcon_password"), // stored encrypted javaArgs: text("java_args"), autoStart: integer("auto_start", { mode: "boolean" }) .notNull() .default(false), restartOnCrash: integer("restart_on_crash", { mode: "boolean" }) .notNull() .default(false), backupEnabled: integer("backup_enabled", { mode: "boolean" }) .notNull() .default(false), backupSchedule: text("backup_schedule"), bluemapEnabled: integer("bluemap_enabled", { mode: "boolean" }) .notNull() .default(false), bluemapUrl: text("bluemap_url"), updatedAt: integer("updated_at").notNull(), }); // --------------------------------------------------------------------------- // Zod schemas (insert + select) for each table // --------------------------------------------------------------------------- export const insertUserSchema = createInsertSchema(users); export const selectUserSchema = createSelectSchema(users); export const insertSessionSchema = createInsertSchema(sessions); export const selectSessionSchema = createSelectSchema(sessions); export const insertAccountSchema = createInsertSchema(accounts); export const selectAccountSchema = createSelectSchema(accounts); export const insertVerificationSchema = createInsertSchema(verifications); export const selectVerificationSchema = createSelectSchema(verifications); export const insertInvitationSchema = createInsertSchema(invitations); export const selectInvitationSchema = createSelectSchema(invitations); export const insertMcPlayerSchema = createInsertSchema(mcPlayers); export const selectMcPlayerSchema = createSelectSchema(mcPlayers); export const insertPlayerBanSchema = createInsertSchema(playerBans); export const selectPlayerBanSchema = createSelectSchema(playerBans); export const insertPlayerChatHistorySchema = createInsertSchema(playerChatHistory); export const selectPlayerChatHistorySchema = createSelectSchema(playerChatHistory); export const insertPlayerSpawnPointSchema = createInsertSchema(playerSpawnPoints); export const selectPlayerSpawnPointSchema = createSelectSchema(playerSpawnPoints); export const insertPluginSchema = createInsertSchema(plugins); export const selectPluginSchema = createSelectSchema(plugins); export const insertBackupSchema = createInsertSchema(backups); export const selectBackupSchema = createSelectSchema(backups); export const insertScheduledTaskSchema = createInsertSchema(scheduledTasks); export const selectScheduledTaskSchema = createSelectSchema(scheduledTasks); export const insertAuditLogSchema = createInsertSchema(auditLogs); export const selectAuditLogSchema = createSelectSchema(auditLogs); export const insertServerSettingsSchema = createInsertSchema(serverSettings); export const selectServerSettingsSchema = createSelectSchema(serverSettings); // --------------------------------------------------------------------------- // Inferred TypeScript types // --------------------------------------------------------------------------- export type User = typeof users.$inferSelect; export type NewUser = typeof users.$inferInsert; export type Session = typeof sessions.$inferSelect; export type NewSession = typeof sessions.$inferInsert; export type Account = typeof accounts.$inferSelect; export type NewAccount = typeof accounts.$inferInsert; export type Verification = typeof verifications.$inferSelect; export type NewVerification = typeof verifications.$inferInsert; export type Invitation = typeof invitations.$inferSelect; export type NewInvitation = typeof invitations.$inferInsert; export type McPlayer = typeof mcPlayers.$inferSelect; export type NewMcPlayer = typeof mcPlayers.$inferInsert; export type PlayerBan = typeof playerBans.$inferSelect; export type NewPlayerBan = typeof playerBans.$inferInsert; export type PlayerChatHistory = typeof playerChatHistory.$inferSelect; export type NewPlayerChatHistory = typeof playerChatHistory.$inferInsert; export type PlayerSpawnPoint = typeof playerSpawnPoints.$inferSelect; export type NewPlayerSpawnPoint = typeof playerSpawnPoints.$inferInsert; export type Plugin = typeof plugins.$inferSelect; export type NewPlugin = typeof plugins.$inferInsert; export type Backup = typeof backups.$inferSelect; export type NewBackup = typeof backups.$inferInsert; export type ScheduledTask = typeof scheduledTasks.$inferSelect; export type NewScheduledTask = typeof scheduledTasks.$inferInsert; export type AuditLog = typeof auditLogs.$inferSelect; export type NewAuditLog = typeof auditLogs.$inferInsert; export type ServerSettings = typeof serverSettings.$inferSelect; export type NewServerSettings = typeof serverSettings.$inferInsert;