bf7be65b03
Jenkins Production Deployment
Reviewed-on: #12 Co-authored-by: Patrick Müller <mail@pmueller.me> Co-committed-by: Patrick Müller <mail@pmueller.me>
151 lines
7.2 KiB
SQL
151 lines
7.2 KiB
SQL
-- nachklang_admin: identity, sessions and per-app permissions for every
|
|
-- *.nachklang.art app.
|
|
--
|
|
-- The better-auth tables below (user, session, account, verification, passkey,
|
|
-- rateLimit) mirror what better-auth 1.7.2 derives from the configuration in
|
|
-- src/models/admin/admin.auth.ts, including the `disabled` additionalField on
|
|
-- `user` and the `rateLimit` table that rateLimit.storage='database' requires.
|
|
-- On every better-auth upgrade: re-derive the table list, diff it against this
|
|
-- file, and add a numbered migration - never edit this one in place.
|
|
--
|
|
-- Table and column names are better-auth's own ("camel" casing, so `rateLimit`
|
|
-- and `userId`). MariaDB on Linux compares table names case-sensitively, so the
|
|
-- casing here is load-bearing. The two Nachklang-owned tables at the bottom use
|
|
-- the snake_case convention of the rest of this repo's SQL.
|
|
|
|
CREATE TABLE IF NOT EXISTS `user` (
|
|
`id` VARCHAR(36) NOT NULL,
|
|
`name` VARCHAR(255) NOT NULL,
|
|
`email` VARCHAR(255) NOT NULL,
|
|
`emailVerified` TINYINT(1) NOT NULL DEFAULT 0,
|
|
`image` TEXT DEFAULT NULL,
|
|
`createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`updatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
-- Nachklang addition, declared through better-auth's additionalFields so
|
|
-- the adapter knows about it. Disabling also revokes the user's sessions.
|
|
`disabled` TINYINT(1) NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `user_email` (`email`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
CREATE TABLE IF NOT EXISTS `session` (
|
|
`id` VARCHAR(36) NOT NULL,
|
|
`expiresAt` DATETIME NOT NULL,
|
|
`token` VARCHAR(255) NOT NULL,
|
|
`createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`updatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`ipAddress` VARCHAR(255) DEFAULT NULL,
|
|
`userAgent` TEXT DEFAULT NULL,
|
|
`userId` VARCHAR(36) NOT NULL,
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `session_token` (`token`),
|
|
KEY `session_user` (`userId`),
|
|
CONSTRAINT `session_user_fk` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
CREATE TABLE IF NOT EXISTS `account` (
|
|
`id` VARCHAR(36) NOT NULL,
|
|
-- 1.7 addition: distinguishes a local credential account
|
|
-- ("local:credential") from an OAuth issuer. Written by better-auth.
|
|
`issuer` VARCHAR(255) NOT NULL,
|
|
`accountId` VARCHAR(255) NOT NULL,
|
|
`providerId` VARCHAR(255) NOT NULL,
|
|
`userId` VARCHAR(36) NOT NULL,
|
|
`accessToken` TEXT DEFAULT NULL,
|
|
`refreshToken` TEXT DEFAULT NULL,
|
|
`idToken` TEXT DEFAULT NULL,
|
|
`accessTokenExpiresAt` DATETIME DEFAULT NULL,
|
|
`refreshTokenExpiresAt` DATETIME DEFAULT NULL,
|
|
`scope` TEXT DEFAULT NULL,
|
|
`password` TEXT DEFAULT NULL,
|
|
`createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`updatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (`id`),
|
|
KEY `account_user` (`userId`),
|
|
KEY `account_provider` (`providerId`, `accountId`),
|
|
CONSTRAINT `account_user_fk` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- Password-reset and e-mail-verification tokens.
|
|
CREATE TABLE IF NOT EXISTS `verification` (
|
|
`id` VARCHAR(36) NOT NULL,
|
|
`identifier` VARCHAR(255) NOT NULL,
|
|
`value` TEXT NOT NULL,
|
|
`expiresAt` DATETIME NOT NULL,
|
|
`createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`updatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (`id`),
|
|
KEY `verification_identifier` (`identifier`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
CREATE TABLE IF NOT EXISTS `passkey` (
|
|
`id` VARCHAR(36) NOT NULL,
|
|
`name` VARCHAR(255) DEFAULT NULL,
|
|
`publicKey` TEXT NOT NULL,
|
|
`userId` VARCHAR(36) NOT NULL,
|
|
`credentialID` VARCHAR(255) NOT NULL,
|
|
`counter` INT NOT NULL DEFAULT 0,
|
|
`deviceType` VARCHAR(255) NOT NULL,
|
|
`backedUp` TINYINT(1) NOT NULL DEFAULT 0,
|
|
`transports` VARCHAR(255) DEFAULT NULL,
|
|
`createdAt` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
`aaguid` VARCHAR(255) DEFAULT NULL,
|
|
PRIMARY KEY (`id`),
|
|
KEY `passkey_user` (`userId`),
|
|
KEY `passkey_credential` (`credentialID`),
|
|
CONSTRAINT `passkey_user_fk` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- Required by rateLimit.storage = 'database' in admin.auth.ts. Passenger may
|
|
-- run several API instances, and an in-memory limiter would give each of them
|
|
-- its own budget.
|
|
CREATE TABLE IF NOT EXISTS `rateLimit` (
|
|
`id` VARCHAR(36) NOT NULL,
|
|
`key` VARCHAR(255) NOT NULL,
|
|
`count` INT NOT NULL DEFAULT 0,
|
|
-- Epoch milliseconds, not a DATETIME: better-auth stores a number here.
|
|
`lastRequest` BIGINT NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `rate_limit_key` (`key`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Nachklang-owned tables
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
-- Which apps a user may administer. `admin` is just another app: holding it is
|
|
-- what lets someone manage users and invitations. A permission is (app, role);
|
|
-- `access` is the only role today, and the key admits several per app so finer
|
|
-- ones can be added by inserting rows rather than by migrating this table.
|
|
CREATE TABLE IF NOT EXISTS `user_app_permissions` (
|
|
`user_id` VARCHAR(36) NOT NULL,
|
|
`app` ENUM('calendar','feedback','tickets','admin') NOT NULL,
|
|
-- One row per (user, app, role). `access` means "may use this app at all"
|
|
-- and is the only role today; the key allows several per app so a finer
|
|
-- permission can be added later by inserting rows, not by migrating.
|
|
`role` VARCHAR(32) NOT NULL DEFAULT 'access',
|
|
`granted_by` VARCHAR(36) DEFAULT NULL,
|
|
`granted_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
-- (user_id, app) is the leftmost prefix of this key, so the per-request
|
|
-- permission lookup needs no separate index.
|
|
PRIMARY KEY (`user_id`, `app`, `role`),
|
|
CONSTRAINT `uap_user_fk` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- The only route to a new account: there is no public sign-up. Only the
|
|
-- SHA-256 of the token is stored, so a dump of this table hands out no access.
|
|
CREATE TABLE IF NOT EXISTS `invitations` (
|
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
|
`email` VARCHAR(255) NOT NULL,
|
|
`name` VARCHAR(255) NOT NULL,
|
|
`token_hash` CHAR(64) NOT NULL,
|
|
`permissions` JSON NOT NULL,
|
|
`invited_by` VARCHAR(36) DEFAULT NULL,
|
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`expires_at` DATETIME NOT NULL,
|
|
`accepted_at` DATETIME DEFAULT NULL,
|
|
`revoked_at` DATETIME DEFAULT NULL,
|
|
UNIQUE KEY `inv_token_hash` (`token_hash`),
|
|
KEY `inv_email` (`email`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|