2015-07-20 00:09:47 -07:00
|
|
|
#### WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
|
|
|
|
#### This file is not used by any code and is here to document the latest schema
|
|
|
|
|
|
|
|
|
|
#### General ideas
|
2025-06-18 20:55:14 +02:00
|
|
|
#### Default char set is utf8mb4 and DEFAULT COLLATE is utf8mb4_bin. Collate affects comparisons in WHERE and ORDER
|
2015-07-20 00:09:47 -07:00
|
|
|
#### Strict mode is enabled
|
|
|
|
|
#### VARCHAR - stored as part of table row (use for strings)
|
|
|
|
|
#### TEXT - stored offline from table row (use for strings)
|
2021-04-29 12:49:48 -07:00
|
|
|
#### BLOB (64KB), MEDIUMBLOB (16MB), LONGBLOB (4GB) - stored offline from table row (use for binary data)
|
2015-07-20 00:09:47 -07:00
|
|
|
#### https://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html
|
2019-03-23 09:46:04 -07:00
|
|
|
#### Times are stored in the database in UTC. And precision is seconds
|
2015-07-20 00:09:47 -07:00
|
|
|
|
2017-11-19 12:36:05 -08:00
|
|
|
# The code uses zero dates. Make sure sql_mode does NOT have NO_ZERO_DATE
|
|
|
|
|
# http://johnemb.blogspot.com/2014/09/adding-or-removing-individual-sql-modes.html
|
|
|
|
|
# SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'NO_ZERO_DATE',''));
|
|
|
|
|
|
2015-07-20 00:09:47 -07:00
|
|
|
CREATE TABLE IF NOT EXISTS users(
|
|
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
2016-04-05 10:54:09 +02:00
|
|
|
username VARCHAR(254) UNIQUE,
|
2015-07-20 00:09:47 -07:00
|
|
|
email VARCHAR(254) NOT NULL UNIQUE,
|
|
|
|
|
password VARCHAR(1024) NOT NULL,
|
|
|
|
|
salt VARCHAR(512) NOT NULL,
|
2021-05-17 07:18:21 -07:00
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
2020-07-09 15:43:22 -07:00
|
|
|
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
2018-04-25 16:33:18 +02:00
|
|
|
displayName VARCHAR(512) DEFAULT "",
|
|
|
|
|
fallbackEmail VARCHAR(512) DEFAULT "",
|
|
|
|
|
twoFactorAuthenticationSecret VARCHAR(128) DEFAULT "",
|
|
|
|
|
twoFactorAuthenticationEnabled BOOLEAN DEFAULT false,
|
2019-08-29 17:52:00 +02:00
|
|
|
source VARCHAR(128) DEFAULT "",
|
2020-02-21 12:17:06 -08:00
|
|
|
role VARCHAR(32),
|
2021-10-01 12:27:22 +02:00
|
|
|
inviteToken VARCHAR(128) DEFAULT "",
|
2020-03-30 16:32:28 -07:00
|
|
|
resetToken VARCHAR(128) DEFAULT "",
|
2020-03-30 16:47:18 -07:00
|
|
|
resetTokenCreationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
2020-03-30 16:32:28 -07:00
|
|
|
active BOOLEAN DEFAULT 1,
|
2025-07-15 10:06:26 +02:00
|
|
|
avatar MEDIUMBLOB,
|
2022-05-14 19:41:32 +02:00
|
|
|
backgroundImage MEDIUMBLOB,
|
2021-08-20 10:30:14 -07:00
|
|
|
loginLocationsJson MEDIUMTEXT, // { locations: [{ ip, userAgent, city, country, ts }] }
|
2024-12-11 18:24:20 +01:00
|
|
|
notificationConfigJson TEXT,
|
2018-01-21 14:25:39 +01:00
|
|
|
|
2021-05-17 07:18:21 -07:00
|
|
|
INDEX creationTime_index (creationTime),
|
2015-07-20 00:09:47 -07:00
|
|
|
PRIMARY KEY(id));
|
|
|
|
|
|
2018-12-01 00:38:00 +01:00
|
|
|
CREATE TABLE IF NOT EXISTS userGroups(
|
2016-02-07 19:24:07 -08:00
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
2016-09-27 21:11:41 +02:00
|
|
|
name VARCHAR(254) NOT NULL UNIQUE,
|
2020-06-04 13:25:55 +02:00
|
|
|
source VARCHAR(128) DEFAULT "",
|
2016-02-07 19:24:07 -08:00
|
|
|
PRIMARY KEY(id));
|
|
|
|
|
|
2016-02-08 08:55:37 -08:00
|
|
|
CREATE TABLE IF NOT EXISTS groupMembers(
|
|
|
|
|
groupId VARCHAR(128) NOT NULL,
|
|
|
|
|
userId VARCHAR(128) NOT NULL,
|
2018-12-01 00:38:00 +01:00
|
|
|
FOREIGN KEY(groupId) REFERENCES userGroups(id),
|
2020-12-22 10:34:19 -08:00
|
|
|
FOREIGN KEY(userId) REFERENCES users(id),
|
|
|
|
|
UNIQUE (groupId, userId));
|
2016-02-08 08:55:37 -08:00
|
|
|
|
2015-07-20 00:09:47 -07:00
|
|
|
CREATE TABLE IF NOT EXISTS tokens(
|
2019-02-15 13:57:18 -08:00
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
2018-08-27 14:50:41 -07:00
|
|
|
name VARCHAR(64) DEFAULT "", // description
|
2015-07-20 00:09:47 -07:00
|
|
|
accessToken VARCHAR(128) NOT NULL UNIQUE,
|
2019-02-15 13:57:18 -08:00
|
|
|
identifier VARCHAR(128) NOT NULL, // resourceId: app id or user id
|
2015-07-20 00:09:47 -07:00
|
|
|
clientId VARCHAR(128),
|
2022-09-22 21:58:56 +02:00
|
|
|
scopeJson TEXT,
|
2016-06-03 10:07:30 -07:00
|
|
|
expires BIGINT NOT NULL, // FIXME: make this a timestamp
|
2021-03-15 12:47:57 -07:00
|
|
|
lastUsedTime TIMESTAMP NULL,
|
2025-03-07 11:53:03 +01:00
|
|
|
allowedIpRanges TEXT NULL,
|
2015-07-20 00:09:47 -07:00
|
|
|
PRIMARY KEY(accessToken));
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS apps(
|
|
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
2019-11-16 10:31:32 -08:00
|
|
|
appStoreId VARCHAR(128) NOT NULL, // empty for custom apps
|
2019-09-22 00:20:12 -07:00
|
|
|
installationState VARCHAR(512) NOT NULL, // the active task on the app
|
2019-09-22 22:07:14 -07:00
|
|
|
runState VARCHAR(512) NOT NULL, // if the app is stopped
|
2015-07-20 00:09:47 -07:00
|
|
|
health VARCHAR(128),
|
2019-02-12 16:03:12 -08:00
|
|
|
healthTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, // when the app last responded
|
2015-07-20 00:09:47 -07:00
|
|
|
containerId VARCHAR(128),
|
2015-11-13 10:15:27 +01:00
|
|
|
manifestJson TEXT,
|
2016-05-27 11:10:36 -07:00
|
|
|
accessRestrictionJson TEXT, // { users: [ ], groups: [ ] }
|
2018-12-03 13:39:52 +01:00
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, // when the app was installed
|
2024-06-25 16:56:30 +02:00
|
|
|
updateTime TIMESTAMP NULL DEFAULT NULL, // when the last app update was done . Without the first NULL, it comes current time when assigned null!
|
2018-06-26 18:09:04 -07:00
|
|
|
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, // when this db record was updated (useful for UI caching)
|
2016-02-05 15:03:45 +01:00
|
|
|
memoryLimit BIGINT DEFAULT 0,
|
2024-04-10 17:38:49 +02:00
|
|
|
cpuQuota INTEGER DEFAULT 100,
|
2016-07-14 15:04:52 +02:00
|
|
|
xFrameOptions VARCHAR(512),
|
2016-11-11 10:48:33 +05:30
|
|
|
sso BOOLEAN DEFAULT 1, // whether user chose to enable SSO
|
2024-12-05 13:47:59 +01:00
|
|
|
devicesJson TEXT,
|
2017-01-20 05:48:25 -08:00
|
|
|
debugModeJson TEXT, // options for development mode
|
2023-03-06 11:15:55 +01:00
|
|
|
reverseProxyConfigJson TEXT, // { robotsTxt, csp, hstsPreload }
|
2017-11-21 18:09:44 -08:00
|
|
|
enableBackup BOOLEAN DEFAULT 1, // misnomer: controls automatic daily backups
|
2018-12-07 09:03:28 -08:00
|
|
|
enableAutomaticUpdate BOOLEAN DEFAULT 1,
|
2021-03-16 22:38:59 -07:00
|
|
|
enableMailbox BOOLEAN DEFAULT 1, // whether sendmail addon is enabled
|
2020-03-30 22:18:39 -07:00
|
|
|
mailboxName VARCHAR(128), // mailbox of this app
|
2022-06-01 22:06:34 -07:00
|
|
|
mailboxDomain VARCHAR(128), // mailbox domain of this app
|
|
|
|
|
mailboxDisplayName VARCHAR(128), // mailbox display name
|
2021-10-01 12:09:13 -07:00
|
|
|
enableInbox BOOLEAN DEFAULT 0, // whether recvmail addon is enabled
|
|
|
|
|
inboxName VARCHAR(128), // mailbox of this app
|
2022-06-01 22:06:34 -07:00
|
|
|
inboxDomain VARCHAR(128), // mailbox domain of this app
|
2019-03-22 14:09:31 -07:00
|
|
|
label VARCHAR(128), // display name
|
2024-04-10 17:02:32 +02:00
|
|
|
notes TEXT, // free form notes for admins
|
2019-03-22 14:09:31 -07:00
|
|
|
tagsJson VARCHAR(2048), // array of tags
|
2022-06-01 22:44:52 -07:00
|
|
|
storageVolumeId VARCHAR(128),
|
|
|
|
|
storageVolumePrefix VARCHAR(128),
|
2019-08-26 14:12:36 -07:00
|
|
|
taskId INTEGER, // current task
|
2019-08-30 09:45:43 -07:00
|
|
|
errorJson TEXT,
|
2020-06-26 15:48:39 -07:00
|
|
|
servicesConfigJson TEXT, // app services configuration
|
2020-11-20 14:13:16 -08:00
|
|
|
containerIp VARCHAR(16) UNIQUE, // this is not-null because of ip allocation fails, user can 'repair'
|
2021-04-30 13:18:15 -07:00
|
|
|
appStoreIcon MEDIUMBLOB,
|
|
|
|
|
icon MEDIUMBLOB,
|
2021-12-03 11:40:55 -08:00
|
|
|
crontab TEXT,
|
2022-06-08 11:21:09 +02:00
|
|
|
upstreamUri VARCHAR(256) DEFAULT "",
|
2024-04-17 16:54:54 +02:00
|
|
|
checklistJson TEXT, // checklist for admins
|
2015-07-20 00:09:47 -07:00
|
|
|
|
2019-11-14 21:43:14 -08:00
|
|
|
FOREIGN KEY(mailboxDomain) REFERENCES domains(domain),
|
2024-02-27 13:45:08 +01:00
|
|
|
FOREIGN KEY(inboxDomain) REFERENCES domains(domain),
|
2019-08-26 14:12:36 -07:00
|
|
|
FOREIGN KEY(taskId) REFERENCES tasks(id),
|
2022-06-01 22:44:52 -07:00
|
|
|
FOREIGN KEY(storageVolumeId) REFERENCES volumes(id),
|
|
|
|
|
UNIQUE (storageVolumeId, storageVolumePrefix),
|
2015-07-20 00:09:47 -07:00
|
|
|
PRIMARY KEY(id));
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS appPortBindings(
|
|
|
|
|
hostPort INTEGER NOT NULL UNIQUE,
|
2018-08-12 22:08:19 -07:00
|
|
|
type VARCHAR(8) NOT NULL DEFAULT "tcp",
|
2015-07-20 00:09:47 -07:00
|
|
|
environmentVariable VARCHAR(128) NOT NULL,
|
|
|
|
|
appId VARCHAR(128) NOT NULL,
|
2024-07-16 22:21:36 +02:00
|
|
|
count INTEGER NOT NULL DEFAULT 1,
|
2015-07-20 00:09:47 -07:00
|
|
|
FOREIGN KEY(appId) REFERENCES apps(id),
|
|
|
|
|
PRIMARY KEY(hostPort));
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS settings(
|
|
|
|
|
name VARCHAR(128) NOT NULL UNIQUE,
|
2017-09-11 15:35:55 +02:00
|
|
|
value TEXT,
|
2021-04-29 15:46:11 -07:00
|
|
|
valueBlob MEDIUMBLOB,
|
2015-07-20 00:09:47 -07:00
|
|
|
PRIMARY KEY(name));
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS appAddonConfigs(
|
|
|
|
|
appId VARCHAR(128) NOT NULL,
|
|
|
|
|
addonId VARCHAR(32) NOT NULL,
|
2017-03-25 13:35:28 -07:00
|
|
|
name VARCHAR(128) NOT NULL,
|
2021-08-09 13:40:23 -07:00
|
|
|
value TEXT NOT NULL,
|
2015-07-20 00:09:47 -07:00
|
|
|
FOREIGN KEY(appId) REFERENCES apps(id));
|
|
|
|
|
|
2018-10-11 14:07:43 -07:00
|
|
|
CREATE TABLE IF NOT EXISTS appEnvVars(
|
|
|
|
|
appId VARCHAR(128) NOT NULL,
|
|
|
|
|
name TEXT NOT NULL,
|
|
|
|
|
value TEXT NOT NULL,
|
|
|
|
|
FOREIGN KEY(appId) REFERENCES apps(id));
|
|
|
|
|
|
2016-03-07 09:26:26 -08:00
|
|
|
CREATE TABLE IF NOT EXISTS backups(
|
2017-05-26 22:23:24 -07:00
|
|
|
id VARCHAR(128) NOT NULL,
|
2022-04-04 14:13:27 -07:00
|
|
|
remotePath VARCHAR(256) NOT NULL UNIQUE,
|
2022-04-02 17:09:08 -07:00
|
|
|
label VARCHAR(128) DEFAULT "",
|
2018-12-03 13:39:52 +01:00
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
2020-05-13 22:09:33 -07:00
|
|
|
packageVersion VARCHAR(128) NOT NULL, /* app version or box version */
|
|
|
|
|
encryptionVersion INTEGER, /* when null, unencrypted backup */
|
2016-03-07 09:26:26 -08:00
|
|
|
type VARCHAR(16) NOT NULL, /* 'box' or 'app' */
|
2020-06-14 11:29:07 -07:00
|
|
|
identifier VARCHAR(128) NOT NULL, /* 'box' or the app id */
|
2022-04-04 14:13:27 -07:00
|
|
|
dependsOnJson TEXT, /* comma separate list of objects this backup depends on */
|
2016-03-07 09:26:26 -08:00
|
|
|
state VARCHAR(16) NOT NULL,
|
2017-11-16 11:22:09 -08:00
|
|
|
manifestJson TEXT, /* to validate if the app can be installed in this version of box */
|
2017-10-12 17:46:15 -07:00
|
|
|
format VARCHAR(16) DEFAULT "tgz",
|
2019-04-13 17:09:15 -07:00
|
|
|
preserveSecs INTEGER DEFAULT 0,
|
2024-12-10 20:52:29 +01:00
|
|
|
appConfigJson TEXT, /* useful for clone and archive */
|
2016-03-07 09:26:26 -08:00
|
|
|
|
2021-05-17 07:06:11 -07:00
|
|
|
INDEX creationTime_index (creationTime),
|
2017-05-26 22:23:24 -07:00
|
|
|
PRIMARY KEY (id));
|
2016-04-29 23:28:54 -07:00
|
|
|
|
2024-12-10 10:06:52 +01:00
|
|
|
CREATE TABLE IF NOT EXISTS archives(
|
|
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
|
|
|
|
backupId VARCHAR(128) NOT NULL,
|
|
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
appStoreIcon MEDIUMBLOB,
|
|
|
|
|
icon MEDIUMBLOB,
|
|
|
|
|
|
|
|
|
|
FOREIGN KEY(backupId) REFERENCES backups(id),
|
|
|
|
|
PRIMARY KEY (id));
|
|
|
|
|
|
2016-04-29 23:28:54 -07:00
|
|
|
CREATE TABLE IF NOT EXISTS eventlog(
|
|
|
|
|
id VARCHAR(128) NOT NULL,
|
|
|
|
|
action VARCHAR(128) NOT NULL,
|
2021-11-17 12:21:46 -08:00
|
|
|
sourceJson TEXT, /* { userId, username, ip }. userId can be null for cron,sysadmin */
|
|
|
|
|
dataJson TEXT, /* free flowing json based on action */
|
2018-12-03 13:39:52 +01:00
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
2016-04-29 23:28:54 -07:00
|
|
|
|
2021-05-17 07:06:11 -07:00
|
|
|
INDEX creationTime_index (creationTime),
|
2016-04-29 23:28:54 -07:00
|
|
|
PRIMARY KEY (id));
|
2016-05-26 18:02:22 -07:00
|
|
|
|
2017-10-27 23:39:53 +02:00
|
|
|
CREATE TABLE IF NOT EXISTS domains(
|
2017-10-30 00:16:33 +01:00
|
|
|
domain VARCHAR(128) NOT NULL UNIQUE, /* if this needs to be larger, InnoDB has a limit of 767 bytes for PRIMARY KEY values! */
|
2017-10-27 23:39:53 +02:00
|
|
|
zoneName VARCHAR(128) NOT NULL, /* this mostly contains the domain itself again */
|
2018-01-09 14:46:38 -08:00
|
|
|
provider VARCHAR(16) NOT NULL,
|
2017-10-27 23:39:53 +02:00
|
|
|
configJson TEXT, /* JSON containing the dns backend provider config */
|
2018-01-31 16:51:53 +01:00
|
|
|
tlsConfigJson TEXT, /* JSON containing the tls provider config */
|
2020-12-23 15:34:23 -08:00
|
|
|
wellKnownJson TEXT, /* JSON containing well known docs for this domain */
|
2017-10-27 23:39:53 +02:00
|
|
|
|
2021-05-05 10:34:22 -07:00
|
|
|
fallbackCertificateJson MEDIUMTEXT,
|
2021-05-04 21:40:11 -07:00
|
|
|
|
2025-06-18 20:55:14 +02:00
|
|
|
PRIMARY KEY (domain));
|
2018-01-20 22:17:53 -08:00
|
|
|
|
2018-01-23 15:45:30 +01:00
|
|
|
CREATE TABLE IF NOT EXISTS mail(
|
2018-01-20 22:17:53 -08:00
|
|
|
domain VARCHAR(128) NOT NULL UNIQUE,
|
|
|
|
|
|
|
|
|
|
enabled BOOLEAN DEFAULT 0, /* MDA enabled */
|
|
|
|
|
mailFromValidation BOOLEAN DEFAULT 1,
|
|
|
|
|
catchAllJson TEXT,
|
|
|
|
|
relayJson TEXT,
|
2020-08-23 14:33:58 -07:00
|
|
|
bannerJson TEXT,
|
2018-01-20 22:17:53 -08:00
|
|
|
|
2021-10-11 19:51:29 -07:00
|
|
|
dkimKeyJson MEDIUMTEXT,
|
2019-06-10 12:23:29 -07:00
|
|
|
dkimSelector VARCHAR(128) NOT NULL DEFAULT "cloudron",
|
|
|
|
|
|
2018-01-20 22:17:53 -08:00
|
|
|
FOREIGN KEY(domain) REFERENCES domains(domain),
|
2025-06-18 20:55:14 +02:00
|
|
|
PRIMARY KEY(domain));
|
2018-01-20 22:17:53 -08:00
|
|
|
|
2024-12-03 16:33:59 +01:00
|
|
|
/* NOTE: this table contains only real mailboxes. And has unique constraint to handle
|
2018-12-06 21:08:19 -08:00
|
|
|
conflict with aliases and mailbox names
|
2018-02-10 21:29:10 -08:00
|
|
|
*/
|
|
|
|
|
CREATE TABLE IF NOT EXISTS mailboxes(
|
|
|
|
|
name VARCHAR(128) NOT NULL,
|
2018-04-07 19:12:07 -07:00
|
|
|
type VARCHAR(16) NOT NULL, /* 'mailbox', 'alias', 'list' */
|
2018-12-06 21:08:19 -08:00
|
|
|
ownerId VARCHAR(128) NOT NULL, /* user id */
|
2020-11-12 23:25:33 -08:00
|
|
|
ownerType VARCHAR(16) NOT NULL,
|
2020-04-19 18:44:16 -07:00
|
|
|
aliasName VARCHAR(128), /* the target name type is an alias */
|
|
|
|
|
aliasDomain VARCHAR(128), /* the target domain */
|
2019-09-11 12:44:15 -07:00
|
|
|
membersJson TEXT, /* members of a group. fully qualified */
|
2020-04-17 16:55:23 -07:00
|
|
|
membersOnly BOOLEAN DEFAULT false,
|
2018-12-03 13:39:52 +01:00
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
2018-02-10 21:29:10 -08:00
|
|
|
domain VARCHAR(128),
|
2021-04-14 22:37:01 -07:00
|
|
|
active BOOLEAN DEFAULT 1,
|
2021-10-08 10:15:48 -07:00
|
|
|
enablePop3 BOOLEAN DEFAULT 0,
|
2022-08-17 23:18:38 +02:00
|
|
|
storageQuota BIGINT DEFAULT 0,
|
|
|
|
|
messagesQuota BIGINT DEFAULT 0,
|
2018-02-10 21:29:10 -08:00
|
|
|
|
|
|
|
|
FOREIGN KEY(domain) REFERENCES mail(domain),
|
2020-04-19 18:44:16 -07:00
|
|
|
FOREIGN KEY(aliasDomain) REFERENCES mail(domain),
|
2018-02-10 21:29:10 -08:00
|
|
|
UNIQUE (name, domain));
|
2018-01-20 22:17:53 -08:00
|
|
|
|
2022-02-07 13:53:24 -08:00
|
|
|
CREATE TABLE IF NOT EXISTS locations(
|
2018-06-28 19:39:15 +02:00
|
|
|
appId VARCHAR(128) NOT NULL,
|
|
|
|
|
domain VARCHAR(128) NOT NULL,
|
|
|
|
|
subdomain VARCHAR(128) NOT NULL,
|
2022-01-14 22:40:51 -08:00
|
|
|
type VARCHAR(128) NOT NULL, /* primary, secondary, redirect, alias */
|
|
|
|
|
environmentVariable VARCHAR(128), /* only set for secondary */
|
2018-06-29 11:29:30 +02:00
|
|
|
|
2021-05-05 10:34:22 -07:00
|
|
|
certificateJson MEDIUMTEXT,
|
|
|
|
|
|
2018-06-28 19:39:15 +02:00
|
|
|
FOREIGN KEY(domain) REFERENCES domains(domain),
|
|
|
|
|
FOREIGN KEY(appId) REFERENCES apps(id),
|
2018-11-16 11:13:03 -08:00
|
|
|
UNIQUE (subdomain, domain));
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS tasks(
|
2018-12-08 18:50:06 -08:00
|
|
|
id int NOT NULL AUTO_INCREMENT,
|
2025-07-18 14:24:24 +02:00
|
|
|
type VARCHAR(32) NOT NULL, /* 32 prefix + 128 for any id */
|
2021-09-30 09:01:43 -07:00
|
|
|
argsJson TEXT,
|
2025-06-19 19:43:51 +02:00
|
|
|
pending BOOLEAN DEFAULT true,
|
2025-07-16 15:22:00 +02:00
|
|
|
completed BOOLEAN DEFAULT false,
|
2018-11-16 11:13:03 -08:00
|
|
|
percent INTEGER DEFAULT 0,
|
|
|
|
|
message TEXT,
|
2019-08-30 13:46:55 -07:00
|
|
|
errorJson TEXT,
|
|
|
|
|
resultJson TEXT,
|
2018-11-16 11:13:03 -08:00
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
2021-05-17 07:06:11 -07:00
|
|
|
|
|
|
|
|
INDEX creationTime_index (creationTime),
|
2018-11-16 11:13:03 -08:00
|
|
|
PRIMARY KEY (id));
|
2018-06-29 11:04:14 +02:00
|
|
|
|
2018-12-17 15:52:52 +01:00
|
|
|
CREATE TABLE IF NOT EXISTS notifications(
|
|
|
|
|
id int NOT NULL AUTO_INCREMENT,
|
2019-02-28 14:59:33 -08:00
|
|
|
eventId VARCHAR(128), // reference to eventlog. can be null
|
2023-09-22 17:58:13 +02:00
|
|
|
type VARCHAR(128) NOT NULL DEFAULT ""
|
2018-12-17 15:52:52 +01:00
|
|
|
title VARCHAR(512) NOT NULL,
|
|
|
|
|
message TEXT,
|
|
|
|
|
acknowledged BOOLEAN DEFAULT false,
|
|
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
2024-12-11 22:29:00 +01:00
|
|
|
context VARCHAR(128) DEFAULT "", // used along with "type" to create uniqueness
|
2021-05-17 07:06:11 -07:00
|
|
|
|
|
|
|
|
INDEX creationTime_index (creationTime),
|
2021-04-19 21:00:31 -07:00
|
|
|
FOREIGN KEY(eventId) REFERENCES eventlog(id),
|
2018-12-17 15:52:52 +01:00
|
|
|
PRIMARY KEY (id)
|
|
|
|
|
);
|
2018-11-16 11:13:03 -08:00
|
|
|
|
2020-01-31 15:28:42 -08:00
|
|
|
CREATE TABLE IF NOT EXISTS appPasswords(
|
|
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
|
|
|
|
name VARCHAR(128) NOT NULL,
|
|
|
|
|
userId VARCHAR(128) NOT NULL,
|
|
|
|
|
identifier VARCHAR(128) NOT NULL, // resourceId: app id or mail or webadmin
|
|
|
|
|
hashedPassword VARCHAR(1024) NOT NULL,
|
|
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
2021-04-19 21:02:14 -07:00
|
|
|
UNIQUE KEY appPasswords_name_appId_identifier (name, userId, identifier)
|
2020-01-31 15:28:42 -08:00
|
|
|
FOREIGN KEY(userId) REFERENCES users(id),
|
2020-05-30 12:57:25 -07:00
|
|
|
|
2020-01-31 15:28:42 -08:00
|
|
|
PRIMARY KEY (id)
|
|
|
|
|
);
|
|
|
|
|
|
2025-05-07 14:09:10 +02:00
|
|
|
CREATE TABLE IF NOT EXISTS dockerRegistries(
|
|
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
|
|
|
|
provider VARCHAR(16) NOT NULL,
|
|
|
|
|
serverAddress VARCHAR(128) NOT NULL,
|
|
|
|
|
username VARCHAR(128),
|
|
|
|
|
email VARCHAR(128),
|
|
|
|
|
password VARCHAR(128),
|
|
|
|
|
|
|
|
|
|
PRIMARY KEY (id)
|
|
|
|
|
);
|
|
|
|
|
|
2020-10-27 22:39:05 -07:00
|
|
|
CREATE TABLE IF NOT EXISTS volumes(
|
|
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
|
|
|
|
name VARCHAR(256) NOT NULL UNIQUE,
|
2025-06-19 18:10:11 +02:00
|
|
|
hostPath VARCHAR(768) NOT NULL UNIQUE, // computed hostPath . has to be < 768*4 (3072) bytes
|
2020-10-27 22:39:05 -07:00
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
2021-05-12 18:00:43 -07:00
|
|
|
mountType VARCHAR(16) DEFAULT "noop",
|
|
|
|
|
mountOptionsJson TEXT,
|
2020-10-27 22:39:05 -07:00
|
|
|
PRIMARY KEY (id)
|
|
|
|
|
);
|
|
|
|
|
|
2020-10-28 19:42:48 -07:00
|
|
|
CREATE TABLE IF NOT EXISTS appMounts(
|
2020-10-27 22:39:05 -07:00
|
|
|
appId VARCHAR(128) NOT NULL,
|
|
|
|
|
volumeId VARCHAR(128) NOT NULL,
|
2020-10-29 22:08:31 -07:00
|
|
|
readOnly BOOLEAN DEFAULT 1,
|
|
|
|
|
UNIQUE KEY appMounts_appId_volumeId (appId, volumeId),
|
2020-10-27 22:39:05 -07:00
|
|
|
FOREIGN KEY(appId) REFERENCES apps(id),
|
|
|
|
|
FOREIGN KEY(volumeId) REFERENCES volumes(id));
|
|
|
|
|
|
2021-04-30 22:26:51 -07:00
|
|
|
CREATE TABLE IF NOT EXISTS blobs(
|
|
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
2022-02-01 17:29:19 -08:00
|
|
|
value MEDIUMBLOB,
|
2021-04-30 22:26:51 -07:00
|
|
|
PRIMARY KEY(id));
|
2021-04-30 21:54:53 -07:00
|
|
|
|
2022-07-06 19:15:59 +02:00
|
|
|
CREATE TABLE IF NOT EXISTS appLinks(
|
|
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
|
|
|
|
accessRestrictionJson TEXT, // { users: [ ], groups: [ ] }
|
|
|
|
|
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, // when the app was installed
|
|
|
|
|
updateTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, // when the last app update was done
|
|
|
|
|
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, // when this db record was updated (useful for UI caching)
|
|
|
|
|
label VARCHAR(128), // display name
|
|
|
|
|
tagsJson VARCHAR(2048), // array of tags
|
|
|
|
|
icon MEDIUMBLOB,
|
|
|
|
|
upstreamUri VARCHAR(256) DEFAULT "",
|
|
|
|
|
|
|
|
|
|
PRIMARY KEY(id));
|
|
|
|
|
|
2023-03-16 15:37:03 +01:00
|
|
|
CREATE TABLE IF NOT EXISTS oidcClients(
|
|
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
|
|
|
|
secret VARCHAR(128) DEFAULT "",
|
2023-03-23 09:27:40 +01:00
|
|
|
appId VARCHAR(128) DEFAULT "",
|
|
|
|
|
name VARCHAR(128) DEFAULT "",
|
2023-03-17 11:29:03 +01:00
|
|
|
loginRedirectUri VARCHAR(256) DEFAULT "",
|
2023-04-04 15:38:45 +02:00
|
|
|
tokenSignatureAlgorithm VARCHAR(128) DEFAULT "",
|
2023-03-16 15:37:03 +01:00
|
|
|
PRIMARY KEY(id));
|
remove global lock
Currently, the update/apptask/fullbackup/platformstart take a
global lock and cannot run in parallel. This causes situations
where when a user tries to trigger an apptask, it says "waiting for
backup to finish..." etc
The solution is to let them run in parallel. We need a lock at the
app level as app operations running in parallel would be bad (tm).
In addition, the update task needs a lock just for the update part.
We also need multi-process locks. Running tasks as processes is core
to our "kill" strategy.
Various inter process locks were explored:
* node's IPC mechanism with process.send(). But this only works for direct node.js
children. taskworker is run via sudo and the IPC does not work.
* File lock using O_EXCL. Basic ideas to create lock files. While file creation
can be done atomically, it becomes complicated to clean up lock files when
the tasks crash. We need a way to know what locks were held by the crashing task.
flock and friends are not built-into node.js
* sqlite/redis were options but introduce additional deps
* Settled on MySQL based locking. Initial plan was to have row locks
or table locks. Each row is a kind of lock. While implementing, it was found that
we need many types of locks (and not just update lock and app locks). For example,
we need locks for each task type, so that only one task type is active at a time.
* Instead of rows, we can just lock table and have a json blob in it. This hit a road
block that LOCK TABLE is per session and our db layer cannot handle this easily! i.e
when issing two db.query() it might use two different connections from the pool. We have to
expose the connection, release connection etc.
* Next idea was atomic blob update of the blob checking if old blob was same. This approach,
was finally refined into a version field.
Phew!
2024-12-07 14:35:45 +01:00
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS locks(
|
|
|
|
|
id VARCHAR(128) NOT NULL UNIQUE,
|
|
|
|
|
dataJson TEXT,
|
|
|
|
|
version INT DEFAULT 1
|
|
|
|
|
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);
|
|
|
|
|
|