feat: initial schema migration — 9 tables + seed roles & plans
This commit is contained in:
168
backend/src/migrations/1710374400000-InitialSchema.ts
Normal file
168
backend/src/migrations/1710374400000-InitialSchema.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class InitialSchema1710374400000 implements MigrationInterface {
|
||||
name = "InitialSchema1710374400000";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// roles
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE roles (
|
||||
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
||||
slug VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
// subscription_plans
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE subscription_plans (
|
||||
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
||||
slug VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
level TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
priceInCents INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
features JSON NULL,
|
||||
isActive BOOLEAN NOT NULL DEFAULT TRUE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
// users
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE users (
|
||||
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
||||
superOAuthId VARCHAR(255) NOT NULL UNIQUE,
|
||||
email VARCHAR(255) NULL,
|
||||
nickname VARCHAR(100) NOT NULL,
|
||||
isActive BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
createdAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
updatedAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
INDEX idx_users_superOAuthId (superOAuthId),
|
||||
INDEX idx_users_email (email)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
// user_roles (pivot)
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE user_roles (
|
||||
userId VARCHAR(36) NOT NULL,
|
||||
roleId VARCHAR(36) NOT NULL,
|
||||
PRIMARY KEY (userId, roleId),
|
||||
CONSTRAINT fk_user_roles_user FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_user_roles_role FOREIGN KEY (roleId) REFERENCES roles(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
// user_subscriptions
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE user_subscriptions (
|
||||
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
||||
userId VARCHAR(36) NOT NULL,
|
||||
planId VARCHAR(36) NOT NULL,
|
||||
status ENUM('active','expired','cancelled','trial') NOT NULL DEFAULT 'active',
|
||||
startsAt DATETIME NOT NULL,
|
||||
endsAt DATETIME NULL,
|
||||
createdAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
INDEX idx_user_subscriptions_userId (userId),
|
||||
INDEX idx_user_subscriptions_status (status),
|
||||
CONSTRAINT fk_user_subscriptions_user FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_user_subscriptions_plan FOREIGN KEY (planId) REFERENCES subscription_plans(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
// videos
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE videos (
|
||||
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
description TEXT NULL,
|
||||
thumbnailUrl VARCHAR(500) NULL,
|
||||
duration INT UNSIGNED NULL,
|
||||
storageType ENUM('youtube','s3','local','external') NOT NULL,
|
||||
storageKey VARCHAR(500) NOT NULL,
|
||||
requiredLevel TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
isPublished BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
publishedAt DATETIME NULL,
|
||||
createdAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
updatedAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
INDEX idx_videos_requiredLevel (requiredLevel),
|
||||
INDEX idx_videos_isPublished (isPublished)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
// playlists
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE playlists (
|
||||
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
||||
ownerId VARCHAR(36) NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
description TEXT NULL,
|
||||
visibility ENUM('private','shared','public') NOT NULL DEFAULT 'private',
|
||||
createdAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
updatedAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
INDEX idx_playlists_ownerId (ownerId),
|
||||
INDEX idx_playlists_visibility (visibility),
|
||||
CONSTRAINT fk_playlists_owner FOREIGN KEY (ownerId) REFERENCES users(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
// playlist_videos (pivot ordonné)
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE playlist_videos (
|
||||
playlistId VARCHAR(36) NOT NULL,
|
||||
videoId VARCHAR(36) NOT NULL,
|
||||
position INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (playlistId, videoId),
|
||||
INDEX idx_playlist_videos_position (playlistId, position),
|
||||
CONSTRAINT fk_playlist_videos_playlist FOREIGN KEY (playlistId) REFERENCES playlists(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_playlist_videos_video FOREIGN KEY (videoId) REFERENCES videos(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
// playlist_shares
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE playlist_shares (
|
||||
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
||||
playlistId VARCHAR(36) NOT NULL,
|
||||
userId VARCHAR(36) NOT NULL,
|
||||
permission ENUM('view','edit') NOT NULL DEFAULT 'view',
|
||||
status ENUM('pending','active','revoked') NOT NULL DEFAULT 'pending',
|
||||
createdAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
updatedAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
UNIQUE KEY uq_playlist_shares (playlistId, userId),
|
||||
INDEX idx_playlist_shares_userId (userId),
|
||||
INDEX idx_playlist_shares_status (status),
|
||||
CONSTRAINT fk_playlist_shares_playlist FOREIGN KEY (playlistId) REFERENCES playlists(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_playlist_shares_user FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
// Données initiales — plans et rôles
|
||||
await queryRunner.query(`
|
||||
INSERT INTO roles (id, slug, name) VALUES
|
||||
(UUID(), 'user', 'Utilisateur'),
|
||||
(UUID(), 'moderator', 'Modérateur'),
|
||||
(UUID(), 'admin', 'Administrateur'),
|
||||
(UUID(), 'super_admin', 'Super Administrateur')
|
||||
`);
|
||||
|
||||
await queryRunner.query(`
|
||||
INSERT INTO subscription_plans (id, slug, name, level, priceInCents, features) VALUES
|
||||
(UUID(), 'free', 'Gratuit', 0, 0, JSON_OBJECT('maxPlaylists', 3)),
|
||||
(UUID(), 'basic', 'Basic', 1, 499, JSON_OBJECT('maxPlaylists', 20)),
|
||||
(UUID(), 'pro', 'Pro', 2, 999, JSON_OBJECT('maxPlaylists', 999)),
|
||||
(UUID(), 'enterprise', 'Enterprise', 3, 4999, JSON_OBJECT('maxPlaylists', 999, 'whiteLabel', true))
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS playlist_shares`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS playlist_videos`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS playlists`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS videos`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS user_subscriptions`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS user_roles`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS users`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS subscription_plans`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS roles`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user