Files
catherine-league/infra/db/admin_auth.sql
2026-03-31 16:09:03 +09:00

43 lines
1.8 KiB
SQL

-- Admin users and sessions for the Next.js admin area.
-- Run after catherine_league schema exists: mysql ... < admin_auth.sql
USE `catherine_league`;
-- Passwords stored as bcrypt hashes (e.g. from bcryptjs), never plaintext.
CREATE TABLE IF NOT EXISTS `admin_users` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`email` VARCHAR(255) NOT NULL,
`password_hash` VARCHAR(255) NOT NULL,
`is_approved` TINYINT(1) NOT NULL DEFAULT 0,
`is_admin` TINYINT(1) NOT NULL DEFAULT 0,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_admin_users_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Opaque session tokens: store SHA-256 hex of the cookie value; never store raw tokens.
CREATE TABLE IF NOT EXISTS `admin_sessions` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT UNSIGNED NOT NULL,
`token_hash` CHAR(64) NOT NULL,
`expires_at` DATETIME NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_admin_sessions_token_hash` (`token_hash`),
KEY `idx_admin_sessions_user_id` (`user_id`),
KEY `idx_admin_sessions_expires_at` (`expires_at`),
CONSTRAINT `fk_admin_sessions_user`
FOREIGN KEY (`user_id`) REFERENCES `admin_users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Seed: first admin (change password immediately in production).
-- Default password: ChangeMeOnFirstLogin!
INSERT INTO `admin_users` (`email`, `password_hash`, `is_approved`, `is_admin`)
SELECT
'admin@localhost',
'$2b$12$H6Y71zX/nmefp33e0MaMaOOBGSiVwxVE3L.Ie3Pfq1/6QZdLR7bTa',
1,
1
WHERE NOT EXISTS (SELECT 1 FROM `admin_users` WHERE `email` = 'admin@localhost' LIMIT 1);