Add DDL-based DB init and bootstrap

Add bootstrap entrypoint and migrate DB schema setup to SQL files. Introduces bootstrap.js, many data/ddl/*.sql files, and a new runDDL() in modules/database.js (exports pool and runDDL). Remove legacy modules/databaseGlobals.js. Update repositories and code to use database.pool.query calls. Bump package version and set main to bootstrap.js. Clean up server.js to remove inline DB/cert init (now handled by bootstrap). Overall: refactor DB initialization to run ordered SQL DDL files and centralize startup logic.
This commit is contained in:
2026-09-06 23:52:25 +02:00
parent 93892197ad
commit 87407fe604
40 changed files with 405 additions and 485 deletions
+8
View File
@@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS players (
email VARCHAR(255) NULL UNIQUE,
username VARCHAR(16) NOT NULL UNIQUE,
password TEXT NOT NULL,
uuid VARCHAR(36) NOT NULL UNIQUE PRIMARY KEY,
nameChangeAllowed TINYINT(1) DEFAULT 1,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP
)
+7
View File
@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS playersProperties (
name VARCHAR(256) NOT NULL,
value VARCHAR(512) NOT NULL,
uuid VARCHAR(36) NOT NULL,
UNIQUE KEY uniqueProperty (uuid, name),
FOREIGN KEY (uuid) REFERENCES players(uuid) ON DELETE CASCADE
)
+6
View File
@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS clientSessions (
accessToken TEXT NOT NULL,
clientToken VARCHAR(36) NOT NULL,
uuid VARCHAR(36) NOT NULL,
FOREIGN KEY (uuid) REFERENCES players(uuid)
)
+5
View File
@@ -0,0 +1,5 @@
CREATE TABLE IF NOT EXISTS legacyClientSessions (
sessionId VARCHAR(36) NOT NULL,
uuid VARCHAR(36) NOT NULL,
FOREIGN KEY (uuid) REFERENCES players(uuid) ON DELETE CASCADE
)
+8
View File
@@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS uuidToNameHistory (
uuid VARCHAR(36) NOT NULL,
username VARCHAR(255) NOT NULL,
changedAt DATETIME NULL,
FOREIGN KEY (uuid) REFERENCES players(uuid) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_uuidToNameHistory_uuid ON uuidToNameHistory (uuid);
+9
View File
@@ -0,0 +1,9 @@
DROP TRIGGER IF EXISTS log_new_user_name;
CREATE TRIGGER log_new_user_name
AFTER INSERT ON players
FOR EACH ROW
BEGIN
INSERT INTO uuidToNameHistory (uuid, username, changedAt)
VALUES (NEW.uuid, NEW.username, NULL);
END;
+11
View File
@@ -0,0 +1,11 @@
DROP TRIGGER IF EXISTS log_user_name_change;
CREATE TRIGGER log_user_name_change
AFTER UPDATE ON players
FOR EACH ROW
BEGIN
IF OLD.username != NEW.username THEN
INSERT INTO uuidToNameHistory (uuid, username, changedAt)
VALUES (NEW.uuid, NEW.username, CURRENT_TIMESTAMP);
END IF;
END;
+5
View File
@@ -0,0 +1,5 @@
CREATE TABLE IF NOT EXISTS blockedServers (
hashedIp VARCHAR(40) NOT NULL PRIMARY KEY,
banner VARCHAR(256) DEFAULT 'CONSOLE',
reason VARCHAR(512) NULL
)
+8
View File
@@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS playersPrivileges (
uuid VARCHAR(36) PRIMARY KEY,
onlineChat TINYINT(1) DEFAULT 1,
multiplayerServer TINYINT(1) DEFAULT 1,
multiplayerRealms TINYINT(1) DEFAULT 1,
telemetry TINYINT(1) DEFAULT 1,
FOREIGN KEY (uuid) REFERENCES players(uuid) ON DELETE CASCADE
)
+5
View File
@@ -0,0 +1,5 @@
CREATE TABLE IF NOT EXISTS playersPreferences (
uuid VARCHAR(36) PRIMARY KEY,
profanityFilter TINYINT(1) DEFAULT 0,
FOREIGN KEY (uuid) REFERENCES players(uuid) ON DELETE CASCADE
)
+4
View File
@@ -0,0 +1,4 @@
CREATE TABLE IF NOT EXISTS banReasons (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
reasonKey VARCHAR(512) UNIQUE NOT NULL
)
+11
View File
@@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS bans (
banId VARCHAR(512) PRIMARY KEY NOT NULL,
uuid VARCHAR(36) NOT NULL,
expires BIGINT DEFAULT NULL,
reason INTEGER NOT NULL,
reasonMessage VARCHAR(1024) DEFAULT NULL,
FOREIGN KEY(reason) REFERENCES banReasons(id),
FOREIGN KEY (uuid) REFERENCES players(uuid) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_bans_uuid ON bans (uuid)
@@ -0,0 +1,9 @@
DROP TRIGGER IF EXISTS auto_init_player_settings;
CREATE TRIGGER auto_init_player_settings
AFTER INSERT ON players
FOR EACH ROW
BEGIN
INSERT INTO playersPrivileges (uuid) VALUES (NEW.uuid);
INSERT INTO playersPreferences (uuid) VALUES (NEW.uuid);
END;
+7
View File
@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS playersBlockslist (
blockerUuid VARCHAR(36) NOT NULL,
blockedUuid VARCHAR(36) NOT NULL,
PRIMARY KEY (blockerUuid, blockedUuid),
FOREIGN KEY (blockerUuid) REFERENCES players(uuid) ON DELETE CASCADE,
FOREIGN KEY (blockedUuid) REFERENCES players(uuid) ON DELETE CASCADE
)
+5
View File
@@ -0,0 +1,5 @@
CREATE TABLE IF NOT EXISTS usernameRules (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
rule VARCHAR(255) NOT NULL,
type INTEGER DEFAULT 0
)
+8
View File
@@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS textures (
uuid VARCHAR(36) NOT NULL UNIQUE,
hash VARCHAR(64) PRIMARY KEY NOT NULL,
type VARCHAR(10) NOT NULL,
url VARCHAR(2048) NOT NULL,
alias VARCHAR(64) NULL,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP
)
+12
View File
@@ -0,0 +1,12 @@
CREATE TABLE IF NOT EXISTS playersSkins (
playerUuid VARCHAR(36) NOT NULL,
assetHash VARCHAR(64) NOT NULL,
variant VARCHAR(10) DEFAULT "CLASSIC",
isSelected TINYINT(1) DEFAULT 0,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (playerUuid, assetHash),
FOREIGN KEY (playerUuid) REFERENCES players(uuid) ON DELETE CASCADE,
FOREIGN KEY (assetHash) REFERENCES textures(hash)
);
CREATE INDEX IF NOT EXISTS idx_active_skin ON playersSkins (playerUuid, isSelected);
+11
View File
@@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS playersCapes (
playerUuid VARCHAR(36) NOT NULL,
assetHash VARCHAR(64) NOT NULL,
isSelected TINYINT(1) DEFAULT 0,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (playerUuid, assetHash),
FOREIGN KEY (playerUuid) REFERENCES players(uuid) ON DELETE CASCADE,
FOREIGN KEY (assetHash) REFERENCES textures(hash) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_active_cape ON playersCapes (playerUuid, assetHash)
+3
View File
@@ -0,0 +1,3 @@
INSERT IGNORE INTO textures (hash, type, url, uuid) VALUES
('df8ed96c557d441a63e7b6a4a911ab84fa453b42fc2ae6b01c3e1b02e138168c', 'SKIN', '/texture/alex.png', UUID()),
('4c7b0468044bfecacc43d00a3a69335a834b73937688292c20d3988cae58248d', 'SKIN', '/texture/steve.png', UUID());
@@ -0,0 +1,2 @@
DROP TRIGGER IF EXISTS unique_active_skin;
DROP TRIGGER IF EXISTS unique_active_cape;
@@ -0,0 +1,23 @@
DROP TRIGGER IF EXISTS auto_assign_random_default_skin;
CREATE TRIGGER auto_assign_random_default_skin
AFTER INSERT ON players
FOR EACH ROW
BEGIN
INSERT INTO playersSkins (playerUuid, assetHash, variant, isSelected)
SELECT
NEW.uuid,
hash,
CASE
WHEN hash = '4c7b0468044bfecacc43d00a3a69335a834b73937688292c20d3988cae58248d' THEN 'CLASSIC'
ELSE 'SLIM'
END,
1
FROM textures
WHERE hash IN (
'4c7b0468044bfecacc43d00a3a69335a834b73937688292c20d3988cae58248d',
'df8ed96c557d441a63e7b6a4a911ab84fa453b42fc2ae6b01c3e1b02e138168c'
)
ORDER BY RAND()
LIMIT 1;
END;
+9
View File
@@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS playerCertificates (
uuid VARCHAR(36) PRIMARY KEY,
privateKey TEXT NOT NULL,
publicKey TEXT NOT NULL,
publicKeySignatureV2 TEXT NOT NULL,
expiresAt DATETIME NOT NULL,
refreshedAfter DATETIME NOT NULL,
FOREIGN KEY (uuid) REFERENCES players(uuid) ON DELETE CASCADE
)
+7
View File
@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS playerProfileActions (
uuid VARCHAR(36) NOT NULL,
action VARCHAR(64) NOT NULL,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (uuid, action),
FOREIGN KEY (uuid) REFERENCES players(uuid) ON DELETE CASCADE
)
+8
View File
@@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS serverSessions (
uuid VARCHAR(36) PRIMARY KEY,
accessToken TEXT NOT NULL,
serverId VARCHAR(255) NOT NULL,
ip VARCHAR(45) NULL,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (uuid) REFERENCES players(uuid) ON DELETE CASCADE
)
+1
View File
@@ -0,0 +1 @@
SET GLOBAL event_scheduler = ON;
@@ -0,0 +1,4 @@
CREATE EVENT IF NOT EXISTS clean_expired_certificates
ON SCHEDULE EVERY 1 HOUR
DO
DELETE FROM playerCertificates WHERE expiresAt < NOW();
+6
View File
@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS apiAdministrators (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(255) UNIQUE NOT NULL,
password TEXT NOT NULL,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP
)
@@ -0,0 +1,5 @@
CREATE TABLE IF NOT EXISTS apiAdministratorsPermissionsList (
permissionKey VARCHAR(64) PRIMARY KEY
);
INSERT IGNORE INTO apiAdministratorsPermissionsList(permissionKey) VALUES ("RESET_PLAYER_SKIN"), ("GRANT_PLAYER_CAPE"), ("REMOVE_PLAYER_CAPE"), ("CHANGE_PLAYER_USERNAME"), ("CHANGE_PLAYER_PASSWORD"), ("UPLOAD_CAPE"), ("DELETE_CAPES"), ("PLAYER_BAN"), ("PLAYER_BAN_HISTORY"), ("PLAYER_BAN_STATUS"), ("PLAYER_ACTIONS_LIST"), ("PLAYER_UNBAN"), ("REGISTER_USER")
@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS apiAdministratorsPermissions (
administratorId INTEGER NOT NULL,
permissionKey VARCHAR(64) NOT NULL,
PRIMARY KEY (administratorId, permissionKey),
FOREIGN KEY (administratorId) REFERENCES apiAdministrators(id) ON DELETE CASCADE,
FOREIGN KEY (permissionkey) REFERENCES apiAdministratorsPermissionsList(permissionKey) ON DELETE CASCADE
)
+6
View File
@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS oaauth2LinkAttempts (
OAuth2LinkId VARCHAR(255) NOT NULL,
playerUuid VARCHAR(255) NOT NULL,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (playerUuid) REFERENCES players(uuid) ON DELETE CASCADE
)