refactor: 迁移后台身份权限与平台配置

This commit is contained in:
sunlei 2026-06-15 02:01:54 +08:00
parent c5f42251bc
commit 51f05acf55
6 changed files with 234 additions and 9 deletions

View File

@ -754,6 +754,11 @@ git -C D:\MyFiles\KT commit -m "docs: 记录第三期基础层迁移"
## Batch 2: Admin/Auth/Platform Config
Reusable guardrail for later module batches: route contract tests must prove both
decorator route compatibility and module graph reachability. If a route remains
available through an imported legacy module, assert the importing module metadata
and assert that the imported controller is not also registered directly.
### Task 2.1: Build new Admin module boundary
**Files:**
@ -763,19 +768,21 @@ git -C D:\MyFiles\KT commit -m "docs: 记录第三期基础层迁移"
- Modify: `D:\MyFiles\KT\Node\kt-template-online-api\src\app.module.ts`
- Test: `D:\MyFiles\KT\Node\kt-template-online-api\test\modules\admin\admin-contract.spec.ts`
- [ ] **Step 1: Write RED route compatibility test**
- [x] **Step 1: Write RED route compatibility test**
Create assertions for login, menu, user, role, dept, dict, notice controller paths using `test/helpers/controller-route.helper.ts`.
- [ ] **Step 2: Create module shell**
- [x] **Step 2: Create module shell**
Create `src/modules/admin/admin.module.ts` with controllers and providers grouped by `identity` and `platform-config`.
- [ ] **Step 3: Move one domain at a time**
- [x] **Step 3: Move one domain at a time**
Move identity first, then menu/permission, then dict/component/notice. After each move, run the related Jest file.
- [ ] **Step 4: Verify**
Actual: Batch 2 kept legacy `src/admin/**` files in place and created the new shell boundary by grouping identity and platform-config controllers/providers. Dict and notice remain reachable through imported legacy modules to avoid duplicate controller registration.
- [x] **Step 4: Verify**
Run:
@ -794,15 +801,19 @@ Expected: PASS.
- Modify: `D:\MyFiles\KT\Vue\kt-template-admin\apps\web-antdv-next\src\api\system\*.ts`
- Modify: `D:\MyFiles\KT\Vue\kt-template-admin\apps\web-antdv-next\src\views\system\**`
- [ ] **Step 1: Update API types to string IDs**
- [x] **Step 1: Update API types to string IDs**
All ID fields crossing the API boundary use `string`.
- [ ] **Step 2: Ensure route page roots are stable**
Actual: no Admin frontend edit was needed. The targeted `core` and `system` API wrappers already use string IDs for user, role, menu, dept, dict, and notice contracts; the only `id: number` scan hit is the local `SystemKtTableDemo` demo row type, not a backend contract.
- [x] **Step 2: Ensure route page roots are stable**
Every changed route page has a single stable root element.
- [ ] **Step 3: Verify Admin typecheck**
Actual: targeted system pages already use a single `Page` root, with modal/drawer children inside the page root.
- [x] **Step 3: Verify Admin typecheck**
Run:
@ -812,10 +823,12 @@ pnpm --dir D:\MyFiles\KT\Vue\kt-template-admin -F @vben/web-antdv-next run typec
Expected: PASS.
- [ ] **Step 4: Run local login/menu smoke**
- [x] **Step 4: Run local login/menu smoke**
Start API and Admin only for this smoke. Save evidence under `.kt-workspace/test-artifacts/admin-system/<date>/`.
Actual: because Admin frontend had no code diff in this batch, full dev-server login was not started. The interface smoke used a local Nest TestingModule HTTP server with real Admin boundary controllers from `ADMIN_IDENTITY_CONTROLLERS` and `ADMIN_PLATFORM_CONFIG_CONTROLLERS`, then called `GET /auth/password-public-key`, `GET /menu/all`, `GET /dict/codes`, and `GET /system/notice/list` successfully.
### Task 2.3: Commit Batch 2
Run:
@ -829,6 +842,8 @@ git -C D:\MyFiles\KT add TASKS.md
git -C D:\MyFiles\KT commit -m "docs: 记录第三期系统管理迁移"
```
Actual: Admin repo remained clean after Task 2.2 verification, so Batch 2 creates no Admin commit.
## Batch 3: Blog/WordPress/Asset
### Task 3.1: Build Blog, WordPress, and Asset modules

View File

@ -14,7 +14,7 @@ import {
createPinoLoggerParams,
SaveBodyInterceptor,
} from './common';
import { AdminModule } from './admin/admin.module';
import { AdminModule } from './modules/admin/admin.module';
import { BlogModule } from './blog/blog.module';
import { WordpressModule } from './wordpress/wordpress.module';
import { QqbotModule } from './qqbot/qqbot.module';

View File

@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { AdminIdentityModule } from './identity/admin-identity.module';
import { AdminPlatformConfigModule } from './platform-config/admin-platform-config.module';
@Module({
imports: [AdminIdentityModule, AdminPlatformConfigModule],
})
export class AdminModule {}

View File

@ -0,0 +1,45 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AdminAuthGuardModule } from '@/admin/auth/admin-auth-guard.module';
import { AdminAuthController } from '@/admin/auth/admin-auth.controller';
import { AdminDeptController } from '@/admin/dept/admin-dept.controller';
import { AdminDept } from '@/admin/dept/admin-dept.entity';
import { AdminDeptService } from '@/admin/dept/admin-dept.service';
import { AdminMenuController } from '@/admin/menu/admin-menu.controller';
import { AdminMenu } from '@/admin/menu/admin-menu.entity';
import { AdminMenuService } from '@/admin/menu/admin-menu.service';
import { AdminRoleController } from '@/admin/role/admin-role.controller';
import { AdminRole } from '@/admin/role/admin-role.entity';
import { AdminRoleService } from '@/admin/role/admin-role.service';
import { AdminUserManageController } from '@/admin/user/admin-user-manage.controller';
import { AdminUserController } from '@/admin/user/admin-user.controller';
import { AdminUser } from '@/admin/user/admin-user.entity';
import { AdminUserService } from '@/admin/user/admin-user.service';
import { WordpressModule } from '@/wordpress/wordpress.module';
export const ADMIN_IDENTITY_CONTROLLERS = [
AdminAuthController,
AdminUserController,
AdminUserManageController,
AdminMenuController,
AdminRoleController,
AdminDeptController,
];
export const ADMIN_IDENTITY_PROVIDERS = [
AdminUserService,
AdminMenuService,
AdminRoleService,
AdminDeptService,
];
@Module({
imports: [
TypeOrmModule.forFeature([AdminUser, AdminRole, AdminMenu, AdminDept]),
AdminAuthGuardModule,
WordpressModule,
],
controllers: ADMIN_IDENTITY_CONTROLLERS,
providers: ADMIN_IDENTITY_PROVIDERS,
})
export class AdminIdentityModule {}

View File

@ -0,0 +1,53 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AdminAuthGuardModule } from '@/admin/auth/admin-auth-guard.module';
import { ComponentController } from '@/admin/component/component.controller';
import { Component } from '@/admin/component/component.entity';
import { ComponentService } from '@/admin/component/component.service';
import { DictController } from '@/admin/dict/dict.controller';
import { DictModule } from '@/admin/dict/dict.module';
import { AdminNoticeController } from '@/admin/notice/admin-notice.controller';
import { NoticeModule } from '@/admin/notice/notice.module';
import { SystemLogController } from '@/admin/system-log/system-log.controller';
import { SystemLogService } from '@/admin/system-log/system-log.service';
import { AdminTimezoneController } from '@/admin/timezone/admin-timezone.controller';
import { AdminTimezoneService } from '@/admin/timezone/admin-timezone.service';
import { AdminUser } from '@/admin/user/admin-user.entity';
import { AdminExampleController } from '@/admin/example/admin-example.controller';
import { MinioClientModule } from '@/minio/minio.module';
export const ADMIN_PLATFORM_CONFIG_DIRECT_CONTROLLERS = [
ComponentController,
SystemLogController,
AdminTimezoneController,
AdminExampleController,
];
export const ADMIN_PLATFORM_CONFIG_IMPORTED_CONTROLLERS = [
DictController,
AdminNoticeController,
];
export const ADMIN_PLATFORM_CONFIG_CONTROLLERS = [
...ADMIN_PLATFORM_CONFIG_DIRECT_CONTROLLERS,
...ADMIN_PLATFORM_CONFIG_IMPORTED_CONTROLLERS,
];
export const ADMIN_PLATFORM_CONFIG_PROVIDERS = [
ComponentService,
SystemLogService,
AdminTimezoneService,
];
@Module({
imports: [
TypeOrmModule.forFeature([Component, AdminUser]),
AdminAuthGuardModule,
DictModule,
NoticeModule,
MinioClientModule,
],
controllers: ADMIN_PLATFORM_CONFIG_DIRECT_CONTROLLERS,
providers: ADMIN_PLATFORM_CONFIG_PROVIDERS,
})
export class AdminPlatformConfigModule {}

View File

@ -0,0 +1,104 @@
import { MODULE_METADATA } from '@nestjs/common/constants';
import { DictController } from '../../../src/admin/dict/dict.controller';
import { DictModule } from '../../../src/admin/dict/dict.module';
import { AdminNoticeController } from '../../../src/admin/notice/admin-notice.controller';
import { NoticeModule } from '../../../src/admin/notice/notice.module';
import { AdminModule } from '../../../src/modules/admin/admin.module';
import {
ADMIN_IDENTITY_CONTROLLERS,
AdminIdentityModule,
} from '../../../src/modules/admin/identity/admin-identity.module';
import {
ADMIN_PLATFORM_CONFIG_DIRECT_CONTROLLERS,
ADMIN_PLATFORM_CONFIG_CONTROLLERS,
ADMIN_PLATFORM_CONFIG_IMPORTED_CONTROLLERS,
AdminPlatformConfigModule,
} from '../../../src/modules/admin/platform-config/admin-platform-config.module';
import {
collectControllerRoutes,
routeKey,
} from '../../helpers/controller-route.helper';
const getModuleMetadata = <T>(moduleClass: unknown, key: string): T[] => {
return Reflect.getMetadata(key, moduleClass) || [];
};
describe('Admin module route contract', () => {
it('keeps legacy Admin route paths available from the new module boundary', () => {
const routes = collectControllerRoutes([
...ADMIN_IDENTITY_CONTROLLERS,
...ADMIN_PLATFORM_CONFIG_CONTROLLERS,
]);
expect(routes.map(routeKey)).toEqual(
expect.arrayContaining([
'GET /auth/password-public-key',
'POST /auth/login',
'POST /auth/refresh',
'POST /auth/logout',
'GET /auth/codes',
'GET /menu/all',
'GET /user/info',
'PUT /user/profile',
'GET /system/user/list',
'POST /system/user',
'PUT /system/user/:id',
'DELETE /system/user/:id',
'GET /system/menu/list',
'GET /system/menu/name-exists',
'GET /system/menu/path-exists',
'POST /system/menu',
'PUT /system/menu/:id',
'DELETE /system/menu/:id',
'GET /system/role/list',
'POST /system/role',
'PUT /system/role/:id',
'DELETE /system/role/:id',
'GET /system/dept/list',
'POST /system/dept',
'PUT /system/dept/:id',
'DELETE /system/dept/:id',
'GET /dict/list',
'GET /dict/tree',
'GET /dict/groups',
'GET /dict/codes',
'GET /dict/getDictByKey',
'GET /dict/getComponentDictByType',
'POST /dict/save',
'POST /dict/update',
'DELETE /dict/:id',
'POST /dict/toggle',
'GET /system/notice/list',
'GET /system/notice/detail/:id',
'DELETE /system/notice/:id',
'POST /system/notice/toggle',
'POST /system/notice/top',
]),
);
});
it('keeps dict and notice reachable through platform-config module imports', () => {
expect(getModuleMetadata(AdminModule, MODULE_METADATA.IMPORTS)).toEqual(
expect.arrayContaining([AdminIdentityModule, AdminPlatformConfigModule]),
);
expect(
getModuleMetadata(AdminPlatformConfigModule, MODULE_METADATA.IMPORTS),
).toEqual(expect.arrayContaining([DictModule, NoticeModule]));
const directControllers = getModuleMetadata(
AdminPlatformConfigModule,
MODULE_METADATA.CONTROLLERS,
);
expect(directControllers).toEqual(
expect.arrayContaining(ADMIN_PLATFORM_CONFIG_DIRECT_CONTROLLERS),
);
expect(directControllers).not.toEqual(
expect.arrayContaining([DictController, AdminNoticeController]),
);
expect(ADMIN_PLATFORM_CONFIG_IMPORTED_CONTROLLERS).toEqual(
expect.arrayContaining([DictController, AdminNoticeController]),
);
});
});