Initial push

This commit is contained in:
2026-03-08 15:49:34 +01:00
parent 8da12bb7d1
commit 47127f276d
101 changed files with 13844 additions and 8 deletions

359
lib/db/schema.ts Normal file
View File

@@ -0,0 +1,359 @@
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").notNull(),
updatedAt: integer("updated_at").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").notNull(),
ipAddress: text("ip_address"),
userAgent: text("user_agent"),
createdAt: integer("created_at").notNull(),
updatedAt: integer("updated_at").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"),
expiresAt: integer("expires_at"),
createdAt: integer("created_at").notNull(),
updatedAt: integer("updated_at").notNull(),
});
export const verifications = sqliteTable("verifications", {
id: text("id").primaryKey(),
identifier: text("identifier").notNull(),
value: text("value").notNull(),
expiresAt: integer("expires_at").notNull(),
createdAt: integer("created_at").notNull(),
updatedAt: integer("updated_at").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;