Просмотр исходного кода

Remove obsolete Prisma schema files and migration lock for MySQL, cleaning up unused models and seed scripts.

Dave 3 месяцев назад
Родитель
Сommit
2541e3393b

+ 8 - 0
action-plans/20251220-ACT-02.md

@@ -1,11 +1,15 @@
 # 2025-12-20 ACT-02: MySQL → Mongo naming alignment
+
 ## Objectives
+
 1. Keep existing `prisma/mysql/schema` files intact except for the explicitly deleted schema.
 2. Align Prisma/Mongo naming so Mongo side reads `sys_*` but retains the original MySQL table names.
 3. Drop unused `ImageConfig` schema once business confirms no dependency.
 
 ## Tasks
+
 ### A. Schema naming / retention
+
 - Keep the existing MySQL Prisma files (`user.prisma`, `role.prisma`, etc.) under `prisma/mysql/schema`.
 - When creating the Mongo-facing equivalents, rename as follows (with `@@map` to the original table names):
   - `sys-user.prisma` → maps to `sys_user`.
@@ -20,19 +24,23 @@
   - `sys-cache-sync-action.prisma` → `sys_cacheSyncAction`.
 
 ### B. Additional collection splits
+
 - Extract `ProviderVideoSync` from `prisma/mysql/schema/main.prisma` into a dedicated `sys-providerVideoSync.prisma` whose `@@map` is `sys_providerVideoSync`.
 - Ensure `cache-sync-action.prisma` becomes `sys-cache-sync-action.prisma` while mapping the table to `sys_cacheSyncAction` and preserving BigInt PK/indices.
 - Do not migrate `sys_quota_log`; keep the MySQL schema file untouched and leave it out of Mongo plan.
 
 ### C. Clean-up rules
+
 - Delete only `image-config.prisma` to remove the unused `image_config` table once the service no longer depends on it; do not touch other MySQL schema files.
 - Update documentation to reflect new Mongo schema filenames and their MySQL table mappings.
 
 ### D. Verification & follow-up
+
 - Draft a migration checklist enumerating which mgnt services still depend on each schema to ensure feature parity.
 - Schedule follow-up on Mongo auto-increment/counters once naming is stabilized.
 
 ### E. Coding action plan
+
 1. Add new Mongo-focused Prisma schema files under `prisma/mongo/schema/` using the `sys-*.prisma` names listed above, each importing the matching model definition and adding `@@map("<original_table>")` to preserve the existing table name; keep the existing MySQL files untouched for reference/use.
 2. For `ProviderVideoSync`, move the model definition out of `prisma/mysql/schema/main.prisma` into `prisma/mongo/schema/sys-providerVideoSync.prisma` and ensure it maps to `sys_providerVideoSync`; update any import/usage in the Mongo Prisma client config if needed.
 3. Replace `cache-sync-action.prisma` with `prisma/mongo/schema/sys-cache-sync-action.prisma` that maps to `sys_cacheSyncAction` while retaining the `id`, indexes, and payload JSON semantics; update Mongo Prisma client instantiation to load the new schema file.

+ 0 - 236
prisma/mysql/migrations/20251210035343_db_init/migration.sql

@@ -1,236 +0,0 @@
--- CreateTable
-CREATE TABLE `sys_api_permission` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `menu_id` INTEGER NOT NULL,
-    `path` VARCHAR(191) NOT NULL,
-    `method` VARCHAR(191) NOT NULL,
-    `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-
-    UNIQUE INDEX `sys_api_permission_menu_id_path_method_key`(`menu_id`, `path`, `method`),
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `CacheSyncAction` (
-    `id` BIGINT NOT NULL AUTO_INCREMENT,
-    `entityType` VARCHAR(50) NOT NULL,
-    `entityId` BIGINT NULL,
-    `operation` VARCHAR(50) NOT NULL,
-    `status` VARCHAR(20) NOT NULL,
-    `attempts` INTEGER NOT NULL DEFAULT 0,
-    `nextAttemptAt` BIGINT NULL,
-    `lastError` VARCHAR(500) NULL,
-    `payload` JSON NULL,
-    `createdAt` BIGINT NOT NULL,
-    `updatedAt` BIGINT NOT NULL,
-
-    INDEX `CacheSyncAction_status_nextAttemptAt_idx`(`status`, `nextAttemptAt`),
-    INDEX `CacheSyncAction_entityType_entityId_idx`(`entityType`, `entityId`),
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `image_config` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `channel_id` INTEGER NULL,
-    `provider_decode_base` VARCHAR(191) NULL,
-    `local_base_url` VARCHAR(191) NULL,
-    `s3_base_url` VARCHAR(191) NULL,
-    `preferred_source` ENUM('PROVIDER', 'LOCAL_ONLY', 'S3_ONLY', 'S3_AND_LOCAL') NOT NULL DEFAULT 'PROVIDER',
-    `status` INTEGER NOT NULL DEFAULT 1,
-    `create_at` BIGINT NOT NULL DEFAULT 0,
-    `update_at` BIGINT NOT NULL DEFAULT 0,
-
-    INDEX `idx_image_config_channel_id`(`channel_id`),
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `sys_login_log` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `type` ENUM('LOGIN', 'LOGOUT') NOT NULL,
-    `status` ENUM('SUCCESS', 'USERNAME_OR_PASSWORD_ERROR', 'USER_DISABLED', 'IP_LIMITED', 'TWO_FA_CODE_ERROR', 'TWO_FA_NOT_ENABLED', 'TWO_FA_REQUIRED') NOT NULL,
-    `username` VARCHAR(191) NOT NULL,
-    `ip_address` VARCHAR(191) NOT NULL,
-    `user_agent` VARCHAR(191) NOT NULL,
-    `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `ProviderVideoSync` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `providerCode` VARCHAR(191) NOT NULL,
-    `providerVideoId` VARCHAR(191) NOT NULL,
-    `videoMediaId` VARCHAR(191) NOT NULL,
-    `lastProviderUpdatedAt` BIGINT NOT NULL,
-    `lastSyncedAt` BIGINT NOT NULL,
-    `syncStatus` INTEGER NOT NULL DEFAULT 0,
-    `lastError` VARCHAR(500) NULL,
-
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `sys_menu` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `parent_id` INTEGER NULL,
-    `title` VARCHAR(191) NOT NULL,
-    `status` BOOLEAN NOT NULL DEFAULT true,
-    `type` ENUM('DIRECTORY', 'MENU', 'SUBMENU', 'BUTTON') NOT NULL,
-    `order` INTEGER NOT NULL,
-    `frontend_auth` VARCHAR(191) NULL,
-    `path` VARCHAR(191) NULL,
-    `name` VARCHAR(191) NULL,
-    `icon` VARCHAR(191) NULL,
-    `redirect` VARCHAR(191) NULL,
-    `component_key` VARCHAR(191) NULL,
-    `meta` JSON NULL,
-    `canView` INTEGER NOT NULL DEFAULT 0,
-    `canCreate` INTEGER NOT NULL DEFAULT 0,
-    `canUpdate` INTEGER NOT NULL DEFAULT 0,
-    `canDelete` INTEGER NOT NULL DEFAULT 0,
-    `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-
-    UNIQUE INDEX `sys_menu_frontend_auth_key`(`frontend_auth`),
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `sys_operation_log` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `username` VARCHAR(191) NULL,
-    `menu_id` INTEGER NULL,
-    `description` VARCHAR(191) NOT NULL,
-    `type` ENUM('CREATE', 'READ', 'UPDATE', 'DELETE') NOT NULL,
-    `status` BOOLEAN NOT NULL,
-    `method` VARCHAR(191) NOT NULL,
-    `path` VARCHAR(191) NOT NULL,
-    `body` JSON NULL,
-    `response` JSON NULL,
-    `ip_address` VARCHAR(191) NOT NULL,
-    `call_method` VARCHAR(191) NOT NULL,
-    `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `sys_quota_log` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `username` VARCHAR(191) NOT NULL,
-    `op_username` VARCHAR(191) NOT NULL,
-    `amount` BIGINT NOT NULL,
-    `is_inc` BOOLEAN NOT NULL,
-    `quota` BIGINT NOT NULL,
-    `remark` VARCHAR(191) NULL,
-    `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `sys_role_api_permission` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `role_id` INTEGER NOT NULL,
-    `api_permission_id` INTEGER NOT NULL,
-    `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-
-    UNIQUE INDEX `sys_role_api_permission_role_id_api_permission_id_key`(`role_id`, `api_permission_id`),
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `sys_role_menu` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `role_id` INTEGER NOT NULL,
-    `menu_id` INTEGER NOT NULL,
-    `canView` INTEGER NOT NULL DEFAULT 0,
-    `canCreate` INTEGER NOT NULL DEFAULT 0,
-    `canUpdate` INTEGER NOT NULL DEFAULT 0,
-    `canDelete` INTEGER NOT NULL DEFAULT 0,
-    `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-
-    UNIQUE INDEX `sys_role_menu_role_id_menu_id_key`(`role_id`, `menu_id`),
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `sys_role` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `name` VARCHAR(191) NOT NULL,
-    `status` BOOLEAN NOT NULL DEFAULT true,
-    `remark` VARCHAR(191) NULL,
-    `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-
-    UNIQUE INDEX `sys_role_name_key`(`name`),
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `sys_user_role` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `user_id` INTEGER NOT NULL,
-    `role_id` INTEGER NOT NULL,
-    `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-
-    UNIQUE INDEX `sys_user_role_user_id_role_id_key`(`user_id`, `role_id`),
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- CreateTable
-CREATE TABLE `sys_user` (
-    `id` INTEGER NOT NULL AUTO_INCREMENT,
-    `username` VARCHAR(191) NOT NULL,
-    `password` VARCHAR(191) NOT NULL,
-    `status` INTEGER NOT NULL DEFAULT 1,
-    `nick` VARCHAR(100) NULL,
-    `photo` VARCHAR(1024) NULL,
-    `remark` VARCHAR(256) NULL,
-    `twoFA` VARCHAR(256) NULL,
-    `twoFALastUsedStep` INTEGER NULL,
-    `twoFARecoveryCodes` JSON NULL,
-    `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-    `allowIps` JSON NULL,
-    `jwtToken` VARCHAR(1024) NULL,
-    `oAuthJwtToken` VARCHAR(1024) NULL,
-    `lastLoginTime` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
-
-    UNIQUE INDEX `sys_user_username_key`(`username`),
-    PRIMARY KEY (`id`)
-) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
--- AddForeignKey
-ALTER TABLE `sys_api_permission` ADD CONSTRAINT `sys_api_permission_menu_id_fkey` FOREIGN KEY (`menu_id`) REFERENCES `sys_menu`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE `sys_menu` ADD CONSTRAINT `sys_menu_parent_id_fkey` FOREIGN KEY (`parent_id`) REFERENCES `sys_menu`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE `sys_role_api_permission` ADD CONSTRAINT `sys_role_api_permission_role_id_fkey` FOREIGN KEY (`role_id`) REFERENCES `sys_role`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE `sys_role_api_permission` ADD CONSTRAINT `sys_role_api_permission_api_permission_id_fkey` FOREIGN KEY (`api_permission_id`) REFERENCES `sys_api_permission`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE `sys_role_menu` ADD CONSTRAINT `sys_role_menu_role_id_fkey` FOREIGN KEY (`role_id`) REFERENCES `sys_role`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE `sys_role_menu` ADD CONSTRAINT `sys_role_menu_menu_id_fkey` FOREIGN KEY (`menu_id`) REFERENCES `sys_menu`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE `sys_user_role` ADD CONSTRAINT `sys_user_role_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `sys_user`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE `sys_user_role` ADD CONSTRAINT `sys_user_role_role_id_fkey` FOREIGN KEY (`role_id`) REFERENCES `sys_role`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

+ 0 - 3
prisma/mysql/migrations/migration_lock.toml

@@ -1,3 +0,0 @@
-# Please do not edit this file manually
-# It should be added in your version-control system (i.e. Git)
-provider = "mysql"

+ 0 - 14
prisma/mysql/schema/api-permission.prisma

@@ -1,14 +0,0 @@
-model ApiPermission {
-  id         Int      @id @default(autoincrement())
-  menuId     Int      @map("menu_id")
-  path       String
-  method     String
-  createTime DateTime @default(now()) @map("create_time")
-  updateTime DateTime @default(now()) @updatedAt @map("update_time")
-
-  menu               Menu                @relation(fields: [menuId], references: [id])
-  roleApiPermissions RoleApiPermission[]
-
-  @@unique([menuId, path, method])
-  @@map("sys_api_permission")
-}

+ 0 - 31
prisma/mysql/schema/cache-sync-action.prisma

@@ -1,31 +0,0 @@
-model CacheSyncAction {
-  id           BigInt   @id @default(autoincrement()) @db.BigInt
-
-  // e.g. 'AD', 'AD_POOL', 'CHANNEL', 'CATEGORY', 'VIDEO_LIST'
-  entityType   String   @db.VarChar(50)
-
-  // optional: when operation targets a specific entity
-  entityId     BigInt?  @db.BigInt
-
-  // e.g. 'REFRESH', 'INVALIDATE', 'REBUILD_POOL', 'REFRESH_ALL'
-  operation    String   @db.VarChar(50)
-
-  // 'PENDING' | 'SUCCESS' | 'FAILED' | 'GAVE_UP'
-  status       String   @db.VarChar(20)
-
-  attempts     Int      @default(0)
-
-  // epoch millis as BigInt (your preference)
-  nextAttemptAt BigInt? @db.BigInt
-
-  lastError    String?  @db.VarChar(500)
-
-  // for extra info, like { "type": "BANNER" }
-  payload      Json?
-
-  createdAt    BigInt   @db.BigInt
-  updatedAt    BigInt   @db.BigInt
-
-  @@index([status, nextAttemptAt])
-  @@index([entityType, entityId])
-}

+ 0 - 27
prisma/mysql/schema/login-log.prisma

@@ -1,27 +0,0 @@
-enum LoginType {
-  LOGIN
-  LOGOUT
-}
-
-enum LoginStatus {
-  SUCCESS
-  USERNAME_OR_PASSWORD_ERROR
-  USER_DISABLED
-  IP_LIMITED
-  TWO_FA_CODE_ERROR
-  TWO_FA_NOT_ENABLED
-  TWO_FA_REQUIRED
-}
-
-model LoginLog {
-  id         Int         @id @default(autoincrement())
-  type       LoginType
-  status     LoginStatus
-  username   String
-  ipAddress  String      @map("ip_address")
-  userAgent  String      @map("user_agent")
-  createTime DateTime    @default(now()) @map("create_time")
-  updateTime DateTime    @default(now()) @updatedAt @map("update_time")
-
-  @@map("sys_login_log")
-}

+ 0 - 12
prisma/mysql/schema/main.prisma

@@ -1,12 +0,0 @@
-// prisma/mysql/schema/main.schema
-generator client {
-  provider        = "prisma-client-js"
-  output          = "./../../../node_modules/@prisma/mysql/client"
-  previewFeatures = ["prismaSchemaFolder"]
-}
-
-datasource db {
-  provider = "mysql"
-  url      = env("MYSQL_URL")
-}
-

+ 0 - 16
prisma/mysql/schema/main.prisma.md

@@ -1,16 +0,0 @@
-generator client {
-  provider        = "prisma-client-js"
-  output          = "../../node_modules/@prisma/mysql/client"
-  previewFeatures = ["prismaSchemaFolder"]
-}
-
-datasource db {
-  provider = "mysql"
-  url      = env("MYSQL_URL")
-}
-
-
-
-
-
-

+ 0 - 42
prisma/mysql/schema/menu.prisma

@@ -1,42 +0,0 @@
-enum MenuType {
-  DIRECTORY
-  MENU
-  SUBMENU
-  BUTTON
-}
-
-model Menu {
-  id           Int       @id @default(autoincrement())
-  parentId     Int?      @map("parent_id")
-  title        String
-  status       Boolean   @default(true)
-  type         MenuType
-  order        Int
-
-  // existing
-  frontendAuth String?   @unique @map("frontend_auth")
-
-  // NEW (optional, all nullable)
-  parent       Menu?      @relation("MenuToChildren", fields: [parentId], references: [id])
-  children     Menu[]     @relation("MenuToChildren")
-  path         String?   @map("path")           // route.path (full)
-  name         String?   @map("name")           // route.name
-  icon         String?   @map("icon")           // meta.icon
-  redirect     String?   @map("redirect")
-  component_key  String? @map("component_key")
-  meta         Json?
-
-  // action flags (0,1,2)
-  canView      Int @default(0)
-  canCreate    Int @default(0)
-  canUpdate    Int @default(0)
-  canDelete    Int @default(0)
-
-  roleMenus      RoleMenu[]
-  apiPermissions ApiPermission[]
-
-  createTime   DateTime @default(now()) @map("create_time")
-  updateTime   DateTime @default(now()) @updatedAt @map("update_time")
-
-  @@map("sys_menu")
-}

+ 0 - 25
prisma/mysql/schema/operation-log.prisma

@@ -1,25 +0,0 @@
-enum OperationType {
-  CREATE
-  READ
-  UPDATE
-  DELETE
-}
-
-model OperationLog {
-  id          Int           @id @default(autoincrement())
-  username    String?
-  menuId      Int?          @map("menu_id")
-  description String
-  type        OperationType
-  status      Boolean
-  method      String
-  path        String
-  body        Json?
-  response    Json?
-  ipAddress   String        @map("ip_address")
-  callMethod  String        @map("call_method")
-  createTime  DateTime      @default(now()) @map("create_time")
-  updateTime  DateTime      @default(now()) @updatedAt @map("update_time")
-
-  @@map("sys_operation_log")
-}

+ 0 - 13
prisma/mysql/schema/quota-log.prisma

@@ -1,13 +0,0 @@
-model QuotaLog {
-  id         Int      @id @default(autoincrement())
-  username   String
-  opUsername String   @map("op_username")
-  amount     BigInt /// 操作额度
-  isInc      Boolean  @map("is_inc") /// 是否增加额度
-  quota      BigInt /// 变更后额度
-  remark     String?
-  createTime DateTime @default(now()) @map("create_time")
-  updateTime DateTime @default(now()) @updatedAt @map("update_time")
-
-  @@map("sys_quota_log")
-}

+ 0 - 13
prisma/mysql/schema/role-api-permission.prisma

@@ -1,13 +0,0 @@
-model RoleApiPermission {
-  id              Int      @id @default(autoincrement())
-  roleId          Int      @map("role_id")
-  apiPermissionId Int      @map("api_permission_id")
-  createTime      DateTime @default(now()) @map("create_time")
-  updateTime      DateTime @default(now()) @updatedAt @map("update_time")
-
-  role          Role          @relation(fields: [roleId], references: [id])
-  apiPermission ApiPermission @relation(fields: [apiPermissionId], references: [id])
-
-  @@unique([roleId, apiPermissionId])
-  @@map("sys_role_api_permission")
-}

+ 0 - 20
prisma/mysql/schema/role-menu.prisma

@@ -1,20 +0,0 @@
-model RoleMenu {
-  id         Int      @id @default(autoincrement())
-  roleId     Int      @map("role_id")
-  menuId     Int      @map("menu_id")
-
-  // add 查增删改  0: disabled; 1: enabled; 2: NOT applicable
-  canView      Int @default(0)
-  canCreate    Int @default(0)
-  canUpdate    Int @default(0)
-  canDelete    Int @default(0)
-
-  createTime DateTime @default(now()) @map("create_time") @db.DateTime(3)
-  updateTime DateTime @default(now()) @updatedAt @map("update_time") @db.DateTime(3)
-
-  role Role @relation(fields: [roleId], references: [id])
-  menu Menu @relation(fields: [menuId], references: [id])
-
-  @@unique([roleId, menuId])
-  @@map("sys_role_menu")
-}

+ 0 - 14
prisma/mysql/schema/role.prisma

@@ -1,14 +0,0 @@
-model Role {
-  id         Int      @id @default(autoincrement())
-  name       String   @unique
-  status     Boolean  @default(true)
-  remark     String?
-  createTime DateTime @default(now()) @map("create_time")
-  updateTime DateTime @default(now()) @updatedAt @map("update_time")
-
-  userRoles       UserRole[]
-  roleMenus       RoleMenu[]
-  rolePermissions RoleApiPermission[]
-
-  @@map("sys_role")
-}

+ 0 - 371
prisma/mysql/schema/seeds/SEED_REVIEW.md

@@ -1,371 +0,0 @@
-# Menu Seed Files Review
-
-## ✅ Overall Assessment: **GOOD WITH RECOMMENDATIONS**
-
-Your seed files are **structurally correct** and will work with the database schema. However, there are some improvements recommended for production use.
-
----
-
-## 📋 Current Status
-
-### ✅ What's Working:
-
-- All required Prisma fields are present
-- Data types match schema definitions
-- Parent-child relationship logic is correct
-- Multi-pass insertion handles dependencies properly
-- MenuType enum values are valid (DIRECTORY, MENU, SUBMENU, BUTTON)
-- Error handling for circular dependencies exists
-
-### ⚠️ What Needs Attention:
-
-#### 1. **frontendAuth Field (Important for RBAC)**
-
-**Current:** All set to `null`
-
-```typescript
-frontendAuth: null, // ❌ This is a unique field in your schema
-```
-
-**Recommended:** Derive from path or create unique identifiers
-
-```typescript
-// In seed-menu.ts, update the create data:
-frontendAuth: (seed.path, // Use path as unique identifier
-  // OR create a dedicated field in menu-seeds.ts:
-  {
-    legacyId: 16,
-    title: '系统用户',
-    frontendAuth: '/system/users', // ✅ Add this
-    // ... rest
-  });
-```
-
-**Why:** Your `OperationLog` decorator uses `frontendAuth` to link backend operations to frontend menus. Without it, you can't track which menu triggered which operation.
-
----
-
-#### 2. **Action Flags (Permissions)**
-
-**Current:** All set to `0` (no permissions)
-
-```typescript
-canView: 0,    // ❌ User can't even view
-canCreate: 0,
-canUpdate: 0,
-canDelete: 0,
-```
-
-**Recommended:** Set defaults based on menu type
-
-```typescript
-// Helper function in seed-menu.ts:
-function getDefaultPermissions(type: MenuType) {
-  switch (type) {
-    case 'DIRECTORY':
-      return { canView: 1, canCreate: 0, canUpdate: 0, canDelete: 0 };
-    case 'MENU':
-      return { canView: 1, canCreate: 1, canUpdate: 1, canDelete: 1 };
-    case 'SUBMENU':
-      return { canView: 1, canCreate: 1, canUpdate: 1, canDelete: 1 };
-    case 'BUTTON':
-      return { canView: 0, canCreate: 1, canUpdate: 0, canDelete: 0 };
-    default:
-      return { canView: 0, canCreate: 0, canUpdate: 0, canDelete: 0 };
-  }
-}
-
-// Then use it:
-const permissions = getDefaultPermissions(seed.type);
-const created = await prisma.menu.create({
-  data: {
-    // ... other fields
-    ...permissions,
-  },
-});
-```
-
-**Action Flag Values:**
-
-- `0` = Not available
-- `1` = Available
-- `2` = Required (must be checked in frontend)
-
----
-
-#### 3. **component_key Field**
-
-**Current:** All set to `null`
-
-```typescript
-component_key: null, // ❌ Frontend might need this for routing
-```
-
-**Recommended:** Add to menu-seeds.ts and use it
-
-```typescript
-// In menu-seeds.ts:
-export interface SeedMenu {
-  // ... existing fields
-  componentKey?: string; // Add this
-}
-
-// Example data:
-{
-  legacyId: 16,
-  title: '系统用户',
-  componentKey: 'SystemUsers', // ✅ For Vue/React component routing
-  // ... rest
-}
-
-// In seed-menu.ts:
-component_key: seed.componentKey ?? null,
-```
-
----
-
-#### 4. **redirect Field Usage**
-
-**Current:** All set to `null`
-
-```typescript
-redirect: null, // Might be needed for DIRECTORY types
-```
-
-**Recommended:** Set for DIRECTORY types to redirect to first child
-
-```typescript
-// Example for directories:
-{
-  legacyId: 1,
-  type: 'DIRECTORY',
-  path: '/marketing',
-  redirect: '/marketing/videos', // ✅ Redirect to first child
-  // ... rest
-}
-```
-
----
-
-## 🔧 Recommended Updates
-
-### Option 1: Quick Fix (Minimal Changes)
-
-Update `seed-menu.ts` to derive `frontendAuth` from path:
-
-```typescript
-const created = await prisma.menu.create({
-  data: {
-    parentId,
-    title: seed.title,
-    status: true,
-    type: seed.type,
-    order: seed.order,
-
-    frontendAuth: seed.path, // ✅ Use path as unique identifier
-
-    path: seed.path,
-    name: seed.name,
-    icon: seed.icon,
-    redirect: null,
-    component_key: null,
-    meta: seed.meta ?? undefined,
-
-    // ✅ Set default permissions based on type
-    ...getDefaultPermissions(seed.type),
-  },
-});
-```
-
----
-
-### Option 2: Complete Fix (Production-Ready)
-
-1. **Update `menu-seeds.ts` interface:**
-
-```typescript
-export interface SeedMenu {
-  legacyId: number;
-  legacyParentId: number | null;
-  title: string;
-  type: MenuType;
-  name: string;
-  path: string;
-  icon: string | null;
-  order: number;
-  frontendAuth?: string; // ✅ Add
-  componentKey?: string; // ✅ Add
-  redirect?: string; // ✅ Add
-  permissions?: {
-    // ✅ Add
-    canView?: number;
-    canCreate?: number;
-    canUpdate?: number;
-    canDelete?: number;
-  };
-  meta?: Prisma.JsonValue;
-}
-```
-
-2. **Update seed data with these values:**
-
-```typescript
-{
-  legacyId: 16,
-  title: '系统用户',
-  type: 'MENU',
-  name: 'systemUsers',
-  path: '/system/users',
-  frontendAuth: '/system/users',  // ✅
-  componentKey: 'SystemUsers',     // ✅
-  permissions: {                   // ✅
-    canView: 1,
-    canCreate: 1,
-    canUpdate: 1,
-    canDelete: 1,
-  },
-  // ... rest
-}
-```
-
-3. **Update `seed-menu.ts` to use these values:**
-
-```typescript
-const defaultPerms = getDefaultPermissions(seed.type);
-
-const created = await prisma.menu.create({
-  data: {
-    parentId,
-    title: seed.title,
-    status: true,
-    type: seed.type,
-    order: seed.order,
-
-    frontendAuth: seed.frontendAuth ?? seed.path,
-    path: seed.path,
-    name: seed.name,
-    icon: seed.icon,
-    redirect: seed.redirect ?? null,
-    component_key: seed.componentKey ?? null,
-    meta: seed.meta ?? undefined,
-
-    canView: seed.permissions?.canView ?? defaultPerms.canView,
-    canCreate: seed.permissions?.canCreate ?? defaultPerms.canCreate,
-    canUpdate: seed.permissions?.canUpdate ?? defaultPerms.canUpdate,
-    canDelete: seed.permissions?.canDelete ?? defaultPerms.canDelete,
-  },
-});
-```
-
----
-
-## 🎯 Priority Recommendations
-
-### High Priority:
-
-1. ✅ Add `frontendAuth` values (use path if nothing else)
-2. ✅ Set proper action flags (at least `canView: 1` for visible menus)
-
-### Medium Priority:
-
-3. ✅ Add `componentKey` for frontend routing
-4. ✅ Set `redirect` for DIRECTORY types
-
-### Low Priority:
-
-5. Consider adding more metadata to `meta` field
-6. Add validation in seed script
-
----
-
-## 📊 Data Integrity Checks
-
-Your seed script should pass these checks:
-
-### ✅ Already Passing:
-
-- [x] All parent IDs reference valid menus
-- [x] No circular dependencies
-- [x] All required fields present
-- [x] MenuType enum values valid
-- [x] Order numbers unique within parent
-
-### ⚠️ Should Add:
-
-- [ ] frontendAuth uniqueness validation
-- [ ] Path format validation (/kebab-case)
-- [ ] Name format validation (camelCase)
-
----
-
-## 🚀 Quick Test Script
-
-Add this to verify your seed data before running:
-
-```typescript
-// Add to seed-menu.ts before the main seeding loop:
-function validateSeeds() {
-  const paths = new Set<string>();
-  const legacyIds = new Set<number>();
-
-  for (const seed of MENU_SEEDS) {
-    // Check unique paths
-    if (paths.has(seed.path)) {
-      throw new Error(`Duplicate path: ${seed.path}`);
-    }
-    paths.add(seed.path);
-
-    // Check unique legacy IDs
-    if (legacyIds.has(seed.legacyId)) {
-      throw new Error(`Duplicate legacyId: ${seed.legacyId}`);
-    }
-    legacyIds.add(seed.legacyId);
-
-    // Check parent exists (except for roots)
-    if (seed.legacyParentId !== null) {
-      const parentExists = MENU_SEEDS.some(
-        (s) => s.legacyId === seed.legacyParentId,
-      );
-      if (!parentExists) {
-        throw new Error(
-          `Invalid parent ${seed.legacyParentId} for menu ${seed.legacyId}`,
-        );
-      }
-    }
-  }
-
-  console.log('✅ Seed data validation passed');
-}
-
-// Call before seeding:
-validateSeeds();
-```
-
----
-
-## 📝 Summary
-
-**Current State:** Your seed files are **functional and will work**, but they create menus with minimal permissions and missing RBAC links.
-
-**Recommended State:** Add the suggested fields to make the system production-ready with proper permissions and frontend integration.
-
-**Estimated Time:**
-
-- Quick Fix: ~15 minutes
-- Complete Fix: ~1 hour
-
-**Risk Level:** Low - All changes are additive, won't break existing structure
-
----
-
-## 💡 Next Steps
-
-1. Decide between Quick Fix or Complete Fix
-2. Update seed files accordingly
-3. Test with: `pnpm run prisma:seed:box-admin:admin` (when DB is accessible)
-4. Verify in database that menus have proper permissions
-5. Test frontend routing with new component keys
-
----
-
-Last Updated: November 17, 2025

+ 0 - 435
prisma/mysql/schema/seeds/menu-seeds.ts

@@ -1,435 +0,0 @@
-import type { Prisma, MenuType } from '@prisma/mysql/client';
-
-export interface SeedMenu {
-  legacyId: number;
-  legacyParentId: number | null;
-  title: string; // Chinese display title
-  type: MenuType; // DIRECTORY | MENU | SUBMENU | BUTTON
-  name: string; // English, camelCase
-  path: string; // English, /kebab-case/route
-  icon: string | null; // Iconify / material-symbols / mdi
-  order: number; // Sort order
-  meta?: Prisma.JsonValue;
-}
-
-/**
- * Hybrid style:
- * - title: Chinese (for UI)
- * - name/path/icon: English & structured
- */
-export const MENU_SEEDS: SeedMenu[] = [
-  // ======================
-  // 营销中心 (Marketing)
-  // ======================
-  {
-    legacyId: 1,
-    legacyParentId: null,
-    title: '营销中心',
-    type: 'DIRECTORY',
-    name: 'marketingRoot',
-    path: '/marketing',
-    icon: 'material-symbols-light:campaign',
-    order: 100,
-    meta: {
-      title: '营销中心',
-      i18n: 'route.marketing.root',
-      icon: 'material-symbols-light:campaign',
-    },
-  },
-  {
-    legacyId: 2,
-    legacyParentId: 1,
-    title: '视频管理',
-    type: 'MENU',
-    name: 'marketingVideos',
-    path: '/marketing/videos',
-    icon: 'material-symbols-light:notifications-active-outline',
-    order: 1,
-    meta: {
-      title: '视频管理',
-      i18n: 'route.marketing.videos',
-      icon: 'material-symbols-light:notifications-active-outline',
-    },
-  },
-  {
-    legacyId: 3,
-    legacyParentId: 1,
-    title: '分类管理',
-    type: 'MENU',
-    name: 'marketingCategories',
-    path: '/marketing/categories',
-    icon: 'material-symbols-light:ads-click-rounded',
-    order: 2,
-    meta: {
-      title: '分类管理',
-      i18n: 'route.marketing.categories',
-      icon: 'material-symbols-light:ads-click-rounded',
-    },
-  },
-  {
-    legacyId: 4,
-    legacyParentId: 1,
-    title: '标签管理',
-    type: 'MENU',
-    name: 'marketingTags',
-    path: '/marketing/tags',
-    icon: 'material-symbols-light:label-outline',
-    order: 3,
-    meta: {
-      title: '标签管理',
-      i18n: 'route.marketing.tags',
-      icon: 'material-symbols-light:label-outline',
-    },
-  },
-  {
-    legacyId: 5,
-    legacyParentId: 1,
-    title: '广告管理',
-    type: 'MENU',
-    name: 'marketingAds',
-    path: '/marketing/ads',
-    icon: 'material-symbols-light:group-outline',
-    order: 4,
-    meta: {
-      title: '广告管理',
-      i18n: 'route.marketing.ads',
-      icon: 'material-symbols-light:group-outline',
-    },
-  },
-  {
-    legacyId: 6,
-    legacyParentId: 1,
-    title: '参数管理',
-    type: 'MENU',
-    name: 'marketingParams',
-    path: '/marketing/params',
-    icon: 'material-symbols-light:format-quote',
-    order: 5,
-    meta: {
-      title: '参数管理',
-      i18n: 'route.marketing.params',
-      icon: 'material-symbols-light:format-quote',
-    },
-  },
-
-  // ======================
-  // 数据中心 (Data Center)
-  // ======================
-  {
-    legacyId: 7,
-    legacyParentId: null,
-    title: '数据中心',
-    type: 'DIRECTORY',
-    name: 'dataCenterRoot',
-    path: '/data',
-    icon: 'material-symbols-light:monitoring',
-    order: 200,
-    meta: {
-      title: '数据中心',
-      i18n: 'route.data.root',
-      icon: 'material-symbols-light:monitoring',
-    },
-  },
-  {
-    legacyId: 8,
-    legacyParentId: 7,
-    title: 'APP访问记录',
-    type: 'MENU',
-    name: 'dataAppAccessLogs',
-    path: '/data/app-access-logs',
-    icon: 'material-symbols-light:smartphone',
-    order: 1,
-    meta: {
-      title: 'APP访问记录',
-      i18n: 'route.data.appAccessLogs',
-      icon: 'material-symbols-light:smartphone',
-    },
-  },
-  {
-    legacyId: 9,
-    legacyParentId: 7,
-    title: '广告点击记录',
-    type: 'MENU',
-    name: 'dataAdsClickLogs',
-    path: '/data/ads-click-logs',
-    icon: 'mdi:bank-transfer',
-    order: 2,
-    meta: {
-      title: '广告点击记录',
-      i18n: 'route.data.adsClickLogs',
-      icon: 'mdi:bank-transfer',
-    },
-  },
-
-  // ======================
-  // 统计中心 (Stats Center)
-  // ======================
-  {
-    legacyId: 10,
-    legacyParentId: null,
-    title: '统计中心',
-    type: 'DIRECTORY',
-    name: 'statsCenterRoot',
-    path: '/stats',
-    icon: 'material-symbols-light:query-stats',
-    order: 300,
-    meta: {
-      title: '统计中心',
-      i18n: 'route.stats.root',
-      icon: 'material-symbols-light:query-stats',
-    },
-  },
-  {
-    legacyId: 11,
-    legacyParentId: 10,
-    title: '每日统计',
-    type: 'MENU',
-    name: 'statsDaily',
-    path: '/stats/daily',
-    icon: 'material-symbols-light:today',
-    order: 1,
-    meta: {
-      title: '每日统计',
-      i18n: 'route.stats.daily',
-      icon: 'material-symbols-light:today',
-    },
-  },
-  {
-    legacyId: 12,
-    legacyParentId: 10,
-    title: '广告统计',
-    type: 'MENU',
-    name: 'statsAds',
-    path: '/stats/ads',
-    icon: 'material-symbols-light:insights',
-    order: 2,
-    meta: {
-      title: '广告统计',
-      i18n: 'route.stats.ads',
-      icon: 'material-symbols-light:insights',
-    },
-  },
-  {
-    legacyId: 13,
-    legacyParentId: 10,
-    title: '广告汇总',
-    type: 'MENU',
-    name: 'statsAdsSummary',
-    path: '/stats/ads-summary',
-    icon: 'material-symbols-light:stacked-line-chart',
-    order: 3,
-    meta: {
-      title: '广告汇总',
-      i18n: 'route.stats.adsSummary',
-      icon: 'material-symbols-light:stacked-line-chart',
-    },
-  },
-  {
-    legacyId: 14,
-    legacyParentId: 10,
-    title: '网站统计',
-    type: 'MENU',
-    name: 'statsSite',
-    path: '/stats/site',
-    icon: 'material-symbols-light:language',
-    order: 4,
-    meta: {
-      title: '网站统计',
-      i18n: 'route.stats.site',
-      icon: 'material-symbols-light:language',
-    },
-  },
-
-  // ======================
-  // 账号管理 (Account)
-  // ======================
-  {
-    legacyId: 15,
-    legacyParentId: null,
-    title: '系统管理',
-    type: 'DIRECTORY',
-    name: 'systemRoot',
-    path: '/system',
-    icon: 'ic:round-manage-accounts',
-    order: 400,
-    meta: {
-      title: '系统管理',
-      i18n: 'route.system.root',
-      icon: 'ic:round-manage-accounts',
-    },
-  },
-  {
-    legacyId: 16,
-    legacyParentId: 15,
-    title: '系统用户',
-    type: 'MENU',
-    name: 'systemUsers',
-    path: '/system/users',
-    icon: 'mdi:account-multiple-outline',
-    order: 1,
-    meta: {
-      title: '系统用户',
-      i18n: 'route.system.users',
-      icon: 'mdi:account-multiple-outline',
-    },
-  },
-  {
-    legacyId: 17,
-    legacyParentId: 15,
-    title: '角色列表',
-    type: 'MENU',
-    name: 'systemRoles',
-    path: '/system/roles',
-    icon: 'mdi:account-tie-hat',
-    order: 20,
-    meta: {
-      title: '角色列表',
-      i18n: 'route.system.roles',
-      icon: 'mdi:account-tie-hat',
-    },
-  },
-  {
-    legacyId: 18,
-    legacyParentId: 15,
-    title: '菜单管理',
-    type: 'MENU',
-    name: 'systemMenus',
-    path: '/system/menus',
-    icon: 'mdi:menu-open',
-    order: 30,
-    meta: {
-      title: '菜单管理',
-      i18n: 'route.system.menus',
-      icon: 'mdi:menu-open',
-    },
-  },
-  {
-    legacyId: 19,
-    legacyParentId: 15,
-    title: '操作日志',
-    type: 'MENU',
-    name: 'systemOperationLogs',
-    path: '/system/operation-logs',
-    icon: 'mdi:history',
-    order: 40,
-    meta: {
-      title: '操作日志',
-      i18n: 'route.system.operationLogs',
-      icon: 'mdi:history',
-    },
-  },
-
-  // ======================
-  // SUBMENUs under Roles
-  // ======================
-  {
-    legacyId: 20,
-    legacyParentId: 17,
-    title: '角色列表',
-    type: 'SUBMENU',
-    name: 'systemRoleList',
-    path: '/system/roles/list',
-    icon: 'mdi:account-tie-hat',
-    order: 1,
-    meta: {
-      title: '角色列表',
-      i18n: 'route.system.role.list',
-      sidebar: false,
-      breadcrumb: false,
-      cache: ['systemRoleCreate', 'systemRoleEdit'],
-    },
-  },
-  {
-    legacyId: 21,
-    legacyParentId: 17,
-    title: '新增角色',
-    type: 'SUBMENU',
-    name: 'systemRoleCreate',
-    path: '/system/roles/create',
-    icon: 'material-symbols-light:add-circle-outline',
-    order: 2,
-    meta: {
-      title: '新增角色',
-      i18n: 'route.system.role.create',
-      sidebar: false,
-      cache: true,
-      activeMenu: '/system/roles',
-      noCache: 'systemRoleList',
-    },
-  },
-  {
-    legacyId: 22,
-    legacyParentId: 17,
-    title: '编辑角色',
-    type: 'SUBMENU',
-    name: 'systemRoleEdit',
-    path: '/system/roles/:id/edit',
-    icon: 'material-symbols-light:edit',
-    order: 3,
-    meta: {
-      title: '编辑角色',
-      i18n: 'route.system.role.edit',
-      sidebar: false,
-      cache: true,
-      activeMenu: '/system/roles',
-      noCache: 'systemRoleList',
-    },
-  },
-
-  // ======================
-  // SUBMENUs under Menus
-  // ======================
-  {
-    legacyId: 23,
-    legacyParentId: 18,
-    title: '菜单列表',
-    type: 'SUBMENU',
-    name: 'systemMenuList',
-    path: '/system/menus/list',
-    icon: 'mdi:menu-open',
-    order: 1,
-    meta: {
-      title: '菜单列表',
-      i18n: 'route.system.menu.list',
-      sidebar: false,
-      breadcrumb: false,
-      cache: ['systemMenuCreate', 'systemMenuEdit'],
-    },
-  },
-  {
-    legacyId: 24,
-    legacyParentId: 18,
-    title: '新增菜单',
-    type: 'SUBMENU',
-    name: 'systemMenuCreate',
-    path: '/system/menus/create',
-    icon: 'material-symbols-light:add-circle-outline',
-    order: 2,
-    meta: {
-      title: '新增菜单',
-      i18n: 'route.system.menu.create',
-      sidebar: false,
-      cache: true,
-      activeMenu: '/system/menus',
-      noCache: 'systemMenuList',
-    },
-  },
-  {
-    legacyId: 25,
-    legacyParentId: 18,
-    title: '编辑菜单',
-    type: 'SUBMENU',
-    name: 'systemMenuEdit',
-    path: '/system/menus/:id/edit',
-    icon: 'material-symbols-light:edit',
-    order: 3,
-    meta: {
-      title: '编辑菜单',
-      i18n: 'route.system.menu.edit',
-      sidebar: false,
-      cache: true,
-      activeMenu: '/system/menus',
-      noCache: 'systemMenuList',
-    },
-  },
-];

+ 0 - 115
prisma/mysql/schema/seeds/seed-menu.ts

@@ -1,115 +0,0 @@
-// prisma/seed-menu.ts
-import { PrismaClient } from '@prisma/mysql/client';
-// If you are actually using @prisma/client instead, change to:
-// import { PrismaClient } from '@prisma/client';
-
-import { MENU_SEEDS, SeedMenu } from './menu-seeds';
-
-const prisma = new PrismaClient();
-
-async function seedMenus() {
-  console.log('Seeding menus...');
-
-  // ⚠ Optional: wipe existing menus – ONLY if you are sure there are no FK dependencies
-  // await prisma.menu.deleteMany();
-
-  const legacyIdToNewId = new Map<number, number>();
-  const inserted = new Set<number>();
-
-  // Generic multi-pass insertion:
-  // - Insert records whose parent is either null or already inserted
-  // - Repeat until all are inserted, or no progress (meaning bad parent links)
-  let remaining = MENU_SEEDS.length;
-
-  while (inserted.size < MENU_SEEDS.length) {
-    let progress = false;
-
-    for (const seed of MENU_SEEDS) {
-      if (inserted.has(seed.legacyId)) {
-        continue;
-      }
-
-      // If has a parent, but parent not inserted yet → skip this round
-      if (
-        seed.legacyParentId !== null &&
-        !legacyIdToNewId.has(seed.legacyParentId)
-      ) {
-        continue;
-      }
-
-      const parentId =
-        seed.legacyParentId === null
-          ? null
-          : legacyIdToNewId.get(seed.legacyParentId)!;
-
-      const created = await prisma.menu.create({
-        data: {
-          parentId,
-          title: seed.title,
-          status: true, // from original dump (1 = true)
-          type: seed.type,
-          order: seed.order,
-
-          frontendAuth: null, // or derive something if you decide later
-
-          path: seed.path,
-          name: seed.name,
-          icon: seed.icon,
-          redirect: null, // can be filled per menu if needed
-          component_key: null, // your Prisma field is `component_key`
-          meta: seed.meta ?? undefined,
-
-          // default action flags; adjust if needed
-          canView: 0,
-          canCreate: 0,
-          canUpdate: 0,
-          canDelete: 0,
-
-          // createTime / updateTime are handled by defaults / @updatedAt
-        },
-      });
-
-      legacyIdToNewId.set(seed.legacyId, created.id);
-      inserted.add(seed.legacyId);
-      remaining -= 1;
-      progress = true;
-
-      console.log(
-        `Inserted menu [legacyId=${seed.legacyId}, newId=${created.id}, name=${seed.name}]`,
-      );
-    }
-
-    if (!progress) {
-      // Nothing could be inserted in this pass -> some parentId is invalid or cyclic
-      const pending = MENU_SEEDS.filter((s) => !inserted.has(s.legacyId)).map(
-        (s) => ({
-          legacyId: s.legacyId,
-          legacyParentId: s.legacyParentId,
-        }),
-      );
-
-      console.error(
-        'Could not resolve parents for the following menus:',
-        pending,
-      );
-      throw new Error(
-        'Menu seeding aborted: unresolved parent relationships. Check legacyParentId values.',
-      );
-    }
-  }
-
-  console.log('Menu seeding completed successfully.');
-}
-
-async function main() {
-  try {
-    await seedMenus();
-  } catch (err) {
-    console.error('Error during menu seeding:', err);
-    process.exitCode = 1;
-  } finally {
-    await prisma.$disconnect();
-  }
-}
-
-void main();

+ 0 - 46
prisma/mysql/schema/seeds/seed-user.ts

@@ -1,46 +0,0 @@
-import { MenuType, PrismaClient } from '@prisma/mysql/client';
-
-const prisma = new PrismaClient();
-
-async function createUsers() {
-  const role = await prisma.role.create({
-    data: {
-      name: '管理员',
-      remark: '管理员专用',
-    },
-  });
-
-  const adminUser = await prisma.user.create({
-    data: {
-      username: 'admin',
-      password: '$2b$12$iS0UJ1YqSal0N3uwin/OvOABUINAclcZGjHNyGFC7mlwRYTFjGQ26',
-      // $2b$12$W9.5wXqjTtHgBilPFpPx2.lpIvrY.HpnHSrEURg9YBiV3e/8tfn3m
-      remark: '默认拥有所有菜单权限,不需要配置角色',
-      // allowIps: ['127.0.0.1'],
-      // quota: 1000000,
-    },
-  });
-
-  await prisma.userRole.create({
-    data: {
-      userId: adminUser.id,
-      roleId: role.id,
-    },
-  });
-}
-
-async function main() {
-  console.log('开始初始化数据库...');
-  await createUsers();
-  console.log('数据库初始化完成');
-}
-
-main()
-  .then(async () => {
-    await prisma.$disconnect();
-  })
-  .catch(async (e) => {
-    console.error(e);
-    await prisma.$disconnect();
-    process.exit(1);
-  });

+ 0 - 13
prisma/mysql/schema/user-role.prisma

@@ -1,13 +0,0 @@
-model UserRole {
-  id         Int      @id @default(autoincrement())
-  userId     Int      @map("user_id")
-  roleId     Int      @map("role_id")
-  createTime DateTime @default(now()) @map("create_time")
-  updateTime DateTime @default(now()) @updatedAt @map("update_time")
-
-  user User @relation(fields: [userId], references: [id])
-  role Role @relation(fields: [roleId], references: [id])
-
-  @@unique([userId, roleId])
-  @@map("sys_user_role")
-}

+ 0 - 27
prisma/mysql/schema/user.prisma

@@ -1,27 +0,0 @@
-model User {
-  id                  Int      @id @default(autoincrement())
-  username            String   @unique
-  password            String
-  status              Int      @default(1)
-  nick                String?  @db.VarChar(100)
-  photo               String?  @db.VarChar(1024)
-  remark              String?  @db.VarChar(256)
-  twoFA               String?  @db.VarChar(256)
-  twoFALastUsedStep   Int?     /// prevent same 30-sec TOTP from being reused.
-  twoFARecoveryCodes  Json?    /// array of hashed backup codes.
-
-  createTime          DateTime @default(now()) @map("create_time")
-  updateTime          DateTime @default(now()) @updatedAt @map("update_time")
-  allowIps            Json? /// 允许访问的IP列表
-
-  // add user latest jwt token, update when user login, jwt guard to check if use current session jwt token matched then allow operations
-  jwtToken            String? @db.VarChar(1024)
-  oAuthJwtToken       String? @db.VarChar(1024)
-
-  userRoles           UserRole[]
-
-  // add user last login date time
-  lastLoginTime       DateTime @default(now()) @map("lastLoginTime")
-
-  @@map("sys_user")
-}