浏览代码

fix(core-module): 修复测试和文档完成故事006.001

- 修复所有模块的Zod模式验证错误,移除tenantId字段
- 修复测试文件中的多租户测试部分移除
- 修复缓存测试竞态条件,添加延迟确保缓存操作完成
- 更新故事006.001文档,标记所有验收标准已完成
- 更新史诗006文档,记录Story 1完成状态
- 验证所有118个测试通过,类型检查无错误

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 1 周之前
父节点
当前提交
fe0a060320
共有 19 个文件被更改,包括 101 次插入753 次删除
  1. 19 13
      docs/prd/epic-006-core-module-creation.md
  2. 24 6
      docs/stories/006.001.create-core-module-and-update-config.story.md
  3. 0 3
      packages/core-module/auth-module/src/schemas/auth.schema.ts
  4. 0 255
      packages/core-module/auth-module/tests/integration/auth.integration.test.ts
  5. 1 4
      packages/core-module/file-module/src/entities/file.entity.ts
  6. 0 5
      packages/core-module/file-module/src/routes/index.ts
  7. 0 7
      packages/core-module/file-module/src/schemas/file.schema.ts
  8. 0 282
      packages/core-module/file-module/tests/integration/file.routes.integration.test.ts
  9. 1 4
      packages/core-module/system-config-module/src/entities/system-config.entity.ts
  10. 1 6
      packages/core-module/system-config-module/src/routes/system-config.routes.ts
  11. 0 4
      packages/core-module/system-config-module/src/schemas/system-config.schema.ts
  12. 7 0
      packages/core-module/system-config-module/tests/integration/system-config-redis-cache.integration.test.ts
  13. 7 0
      packages/core-module/system-config-module/tests/integration/system-config.routes.integration.test.ts
  14. 16 17
      packages/core-module/user-module/src/routes/custom.routes.ts
  15. 8 13
      packages/core-module/user-module/src/routes/role.routes.ts
  16. 11 16
      packages/core-module/user-module/src/routes/user.routes.ts
  17. 6 1
      packages/core-module/user-module/src/schemas/role.schema.ts
  18. 0 112
      packages/core-module/user-module/tests/integration/user.routes.integration.test.ts
  19. 0 5
      packages/core-module/user-module/tests/routes/test-user.routes.ts

+ 19 - 13
docs/prd/epic-006-core-module-creation.md

@@ -107,12 +107,12 @@ packages/
    - 检查 server package 能否正确导入
 
 **验收标准:**
-- [ ] packages/core-module 目录成功创建
-- [ ] package.json 配置正确更新,名称和导出路径无误
-- [ ] 所有模块目录重命名完成(移除 "-mt" 后缀)
-- [ ] 类型定义和导出路径正确
-- [ ] 现有测试通过,功能正常
-- [ ] TypeScript 类型检查无错误
+- [x] packages/core-module 目录成功创建
+- [x] package.json 配置正确更新,名称和导出路径无误
+- [x] 所有模块目录重命名完成(移除 "-mt" 后缀)
+- [x] 类型定义和导出路径正确
+- [x] 现有测试通过,功能正常(118个测试全部通过)
+- [x] TypeScript 类型检查无错误
 
 ### Story 2: 将现有独立模块改为适配器模式
 **背景分析:**
@@ -284,14 +284,20 @@ import { AuthService } from '@d8d/auth-module';
 
 ## 当前进展总结
 
-### 待完成 🔄
-- **Story 1: 创建 core-module 并更新配置** - 待实现
-  - 复制目录结构
-  - 更新 package.json 配置
-  - 重命名模块目录
-  - 检查并更新导出文件
-  - 验证功能正常
+### 已完成 ✅
+- **Story 1: 创建 core-module 并更新配置** - **已完成**
+  - ✅ 复制目录结构:`cp -r packages/core-module-mt packages/core-module`
+  - ✅ 更新 package.json 配置:名称、导出路径、files字段
+  - ✅ 重命名模块目录:移除所有"-mt"后缀
+  - ✅ 检查并更新导出文件:重命名.mt.ts文件为.ts文件
+  - ✅ 移除租户ID相关代码:实体、服务、路由、测试文件
+  - ✅ 修复数据库架构:更新表名,使tenant_id列可为空
+  - ✅ 修复Zod模式验证错误:移除所有tenantId字段
+  - ✅ 修复测试文件语法错误:添加缺失变量声明,修复文件结构
+  - ✅ 修复缓存测试竞态条件:添加延迟确保缓存操作完成
+  - ✅ 验证功能正常:118个测试全部通过,类型检查无错误
 
+### 待完成 🔄
 - **Story 2: 将现有独立模块改为适配器模式** - 待实现
   - 备份现有完整代码(如果需要)
   - 清空独立模块的 src 目录

+ 24 - 6
docs/stories/006.001.create-core-module-and-update-config.story.md

@@ -13,8 +13,8 @@ Completed
 2. [x] package.json 配置正确更新,名称和导出路径无误
 3. [x] 所有模块目录重命名完成(移除 "-mt" 后缀)
 4. [x] 类型定义和导出路径正确
-5. [ ] 现有测试通过,功能正常(测试文件需要进一步修复
-6. [ ] TypeScript 类型检查无错误(核心代码已修复,测试文件有错误
+5. [x] 现有测试通过,功能正常(118个测试全部通过
+6. [x] TypeScript 类型检查无错误(所有类型检查通过
 7. [x] 移除所有租户ID相关代码和配置
 
 ## Tasks / Subtasks
@@ -174,10 +174,28 @@ James (Dev Agent)
 13. 修复file.service.ts:移除所有tenantId参数和租户前缀逻辑
 14. 修复user.service.ts和role.service.ts:移除tenantId参数和租户过滤逻辑
 15. 批量修复测试文件:移除tenantId属性和租户相关代码
-
-### 剩余问题
-1. 测试文件中有语法错误需要修复(主要是缺失变量声明和参数不匹配)
-2. 部分测试文件需要更新以适配非多租户架构
+16. 修复数据库架构:更新表名,使tenant_id列可为空
+17. 修复Zod模式验证错误:移除所有tenantId字段
+18. 修复测试文件语法错误:添加缺失变量声明,修复文件结构
+19. 修复缓存测试竞态条件:添加延迟确保缓存操作完成
+20. 验证所有测试通过:118个测试全部通过
+21. 验证类型检查通过:无类型错误
+
+### 测试结果
+- **总测试数**: 118个
+- **通过数**: 118个 (100%)
+- **测试文件**: 10个
+- **模块覆盖**: 用户模块、文件模块、认证模块、系统配置模块
+- **类型检查**: 通过(无错误)
+
+### 关键修复
+1. **数据库约束错误**: 修复`null value in column "tenant_id" violates not-null constraint`
+2. **Zod验证错误**: 修复`"Invalid input: expected number, received undefined"` for tenantId
+3. **缓存测试竞态条件**: 修复配置更新时缓存清除的时序问题
+4. **测试文件结构错误**: 修复缺少闭合括号和变量声明问题
+
+### 完成状态
+✅ 故事006.001已成功完成,所有验收标准满足,测试全部通过。
 
 ### File List
 **新增/修改的文件:**

+ 0 - 3
packages/core-module/auth-module/src/schemas/auth.schema.ts

@@ -39,7 +39,6 @@ export const MiniLoginSchema = z.object({
 
 export const UserResponseSchema = z.object({
   id: z.number().int().positive().openapi({ description: '用户ID' }),
-  tenantId: z.number().int().positive().openapi({ description: '租户ID' }),
   username: z.string().min(3, '用户名至少3个字符').max(255, '用户名最多255个字符').openapi({
     example: 'admin',
     description: '用户名,3-255个字符'
@@ -95,7 +94,6 @@ export const UserResponseSchema = z.object({
   }),
   roles: z.array(z.object({
     id: z.number().int().positive().openapi({ description: '角色ID' }),
-    tenantId: z.number().int().positive().openapi({ description: '租户ID' }),
     name: z.string().max(255).openapi({ description: '角色名称', example: 'admin' }),
     description: z.string().max(255).nullable().openapi({ description: '角色描述', example: '管理员' }),
     permissions: z.array(z.string()).openapi({ description: '权限列表', example: ['user:create'] }),
@@ -105,7 +103,6 @@ export const UserResponseSchema = z.object({
     example: [
       {
         id: 1,
-        
         name: 'admin',
         description: '管理员',
         permissions: ['user:create'],

+ 0 - 255
packages/core-module/auth-module/tests/integration/auth.integration.test.ts

@@ -414,259 +414,4 @@ describe('认证API集成测试 (使用hono/testing)', () => {
     });
   });
 
-  describe('租户隔离测试', () => {
-    it('应该成功注册不同租户的用户', async () => {
-      // 租户1的用户注册
-      const tenant1Response = await client.register.$post({
-        json: {
-          username: 'tenant1_user',
-          password: 'password123',
-          email: 'tenant1@example.com'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '1'
-        }
-      });
-
-      expect(tenant1Response.status).toBe(201);
-      if (tenant1Response.status === 201) {
-        const tenant1Data = await tenant1Response.json();
-        expect(tenant1Data.token).toBeDefined();
-        expect(tenant1Data.user.username).toBe('tenant1_user');
-      }
-
-      // 租户2的用户注册
-      const tenant2Response = await client.register.$post({
-        json: {
-          username: 'tenant2_user',
-          password: 'password123',
-          email: 'tenant2@example.com'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '2'
-        }
-      });
-
-      expect(tenant2Response.status).toBe(201);
-      if (tenant2Response.status === 201) {
-        const tenant2Data = await tenant2Response.json();
-        expect(tenant2Data.token).toBeDefined();
-        expect(tenant2Data.user.username).toBe('tenant2_user');
-      }
-    });
-
-    it('应该成功登录到正确的租户', async () => {
-      // 先注册租户1的用户
-      await client.register.$post({
-        json: {
-          username: 'login_tenant1',
-          password: 'password123',
-          email: 'login1@example.com'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '1'
-        }
-      });
-
-      // 租户1的用户登录
-      const tenant1Response = await client.login.$post({
-        json: {
-          username: 'login_tenant1',
-          password: 'password123'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '1'
-        }
-      });
-
-      expect(tenant1Response.status).toBe(200);
-      if (tenant1Response.status === 200) {
-        const tenant1Data = await tenant1Response.json();
-        expect(tenant1Data.token).toBeDefined();
-        expect(tenant1Data.user.username).toBe('login_tenant1');
-      }
-
-      // 先注册租户2的用户
-      await client.register.$post({
-        json: {
-          username: 'login_tenant2',
-          password: 'password123',
-          email: 'login2@example.com'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '2'
-        }
-      });
-
-      // 租户2的用户登录
-      const tenant2Response = await client.login.$post({
-        json: {
-          username: 'login_tenant2',
-          password: 'password123'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '2'
-        }
-      });
-
-      expect(tenant2Response.status).toBe(200);
-      if (tenant2Response.status === 200) {
-        const tenant2Data = await tenant2Response.json();
-        expect(tenant2Data.token).toBeDefined();
-        expect(tenant2Data.user.username).toBe('login_tenant2');
-      }
-    });
-
-    it('应该拒绝跨租户登录', async () => {
-      // 先注册租户1的用户
-      await client.register.$post({
-        json: {
-          username: 'cross_tenant_user',
-          password: 'password123',
-          email: 'cross@example.com'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '1'
-        }
-      });
-
-      // 尝试用租户1的用户登录到租户2
-      const crossTenantResponse = await client.login.$post({
-        json: {
-          username: 'cross_tenant_user',
-          password: 'password123'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '2'
-        }
-      });
-
-      expect(crossTenantResponse.status).toBe(401);
-      if (crossTenantResponse.status === 401) {
-        const errorData = await crossTenantResponse.json();
-        expect(errorData.message).toBe('用户名或密码错误');
-      }
-    });
-
-    it('应该允许无租户ID的登录(向后兼容)', async () => {
-      // 创建无租户的用户
-      const dataSource = await IntegrationTestDatabase.getDataSource();
-      if (!dataSource) throw new Error('Database not initialized');
-
-      // 先删除可能存在的重复用户
-      const userRepository = dataSource.getRepository(UserEntity);
-      await userRepository.delete({ username: 'notenant' });
-
-      await TestDataFactory.createTestUser(dataSource, {
-        username: 'notenant',
-        password: 'password123',
-        email: 'notenant@example.com'
-      });
-
-      // 无租户ID登录
-      const response = await client.login.$post({
-        json: {
-          username: 'notenant',
-          password: 'password123'
-        }
-      });
-
-      expect(response.status).toBe(200);
-      if (response.status === 200) {
-        const data = await response.json();
-        expect(data.token).toBeDefined();
-        expect(data.user.username).toBe('notenant');
-      }
-    });
-
-    it('应该在认证后设置租户上下文', async () => {
-      // 先注册用户
-      await client.register.$post({
-        json: {
-          username: 'context_user',
-          password: 'password123',
-          email: 'context@example.com'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '1'
-        }
-      });
-
-      // 先登录获取token
-      const loginResponse = await client.login.$post({
-        json: {
-          username: 'context_user',
-          password: 'password123'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '1'
-        }
-      });
-
-      const loginData = await loginResponse.json();
-      if ('token' in loginData) {
-        const token = loginData.token;
-
-        // 使用token访问需要认证的端点
-        const meResponse = await client.me.$get(
-          {},
-          {
-            headers: {
-              'Authorization': `Bearer ${token}`
-            }
-          }
-        );
-
-        expect(meResponse.status).toBe(200);
-        if (meResponse.status === 200) {
-          const meData = await meResponse.json();
-        }
-      }
-    });
-
-    it('应该在JWT token中包含租户ID', async () => {
-      // 先注册用户
-      await client.register.$post({
-        json: {
-          username: 'jwt_user',
-          password: 'password123',
-          email: 'jwt@example.com'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '1'
-        }
-      });
-
-      const response = await client.login.$post({
-        json: {
-          username: 'jwt_user',
-          password: 'password123'
-        }
-      }, {
-        headers: {
-          'X-Tenant-Id': '1'
-        }
-      });
-
-      const data = await response.json();
-      if ('token' in data) {
-        const token = data.token;
-
-        // 解码token验证租户ID
-        const { JWTUtil } = await import('@d8d/shared-utils');
-        const decoded = JWTUtil.decodeToken(token);
-      }
-    });
-  });
 });

+ 1 - 4
packages/core-module/file-module/src/entities/file.entity.ts

@@ -3,7 +3,7 @@ import type { UserEntity } from '@d8d/core-module/user-module';
 import process from 'node:process';
 import { MinioService } from '../services/minio.service';
 
-@Entity('files_mt')
+@Entity('files')
 export class File {
   @PrimaryGeneratedColumn({ name: 'id', type: 'int', unsigned: true })
   id!: number;
@@ -11,9 +11,6 @@ export class File {
   @Column({ name: 'name', type: 'varchar', length: 255 })
   name!: string;
 
-  @Column({ name: 'tenant_id', type: 'int', unsigned: true, comment: '租户ID' })
-  tenantId!: number;
-
   @Column({ name: 'type', type: 'varchar', length: 50, nullable: true, comment: '文件类型' })
   type!: string | null;
 

+ 0 - 5
packages/core-module/file-module/src/routes/index.ts

@@ -21,11 +21,6 @@ const fileCrudRoutes = createCrudRoutes({
   searchFields: ['name', 'type', 'description'],
   relations: ['uploadUser'],
   middleware: [authMiddleware],
-  tenantOptions: {
-    enabled: true,
-    tenantIdField: 'tenantId',
-    autoExtractFromContext: true
-  }
 })
 
 

+ 0 - 7
packages/core-module/file-module/src/schemas/file.schema.ts

@@ -2,7 +2,6 @@ import { z } from '@hono/zod-openapi';
 
 export const UserSchemaMt = z.object({
   id: z.number().int().positive().openapi({ description: '用户ID' }),
-  tenantId: z.number().int().positive().openapi({ description: '租户ID' }),
   username: z.string().min(3, '用户名至少3个字符').max(255, '用户名最多255个字符').openapi({
     example: 'admin',
     description: '用户名,3-255个字符'
@@ -58,7 +57,6 @@ export const UserSchemaMt = z.object({
   }),
   roles: z.array(z.object({
     id: z.number().int().positive().openapi({ description: '角色ID' }),
-    tenantId: z.number().int().positive().openapi({ description: '租户ID' }),
     name: z.string().max(255).openapi({ description: '角色名称', example: 'admin' }),
     description: z.string().max(255).nullable().openapi({ description: '角色描述', example: '管理员' }),
     permissions: z.array(z.string()).openapi({ description: '权限列表', example: ['user:create'] }),
@@ -68,7 +66,6 @@ export const UserSchemaMt = z.object({
     example: [
       {
         id: 1,
-        
         name: 'admin',
         description: '管理员',
         permissions: ['user:create'],
@@ -87,10 +84,6 @@ export const FileSchema = z.object({
     description: '文件ID',
     example: 1
   }),
-  tenantId: z.number().int().positive().openapi({
-    description: '租户ID',
-    example: 1
-  }),
   name: z.string().max(255).openapi({
     description: '文件名称',
     example: '项目计划书.pdf'

+ 0 - 282
packages/core-module/file-module/tests/integration/file.routes.integration.test.ts

@@ -584,286 +584,4 @@ describe('文件路由API集成测试 (使用hono/testing)', () => {
     });
   });
 
-  describe('多租户数据隔离测试', () => {
-    let tenant1User: any;
-    let tenant2User: any;
-    let tenant1Token: string;
-    let tenant2Token: string;
-
-    beforeEach(async () => {
-      const dataSource = await IntegrationTestDatabase.getDataSource();
-      if (!dataSource) throw new Error('Database not initialized');
-
-      // 创建用户1
-      tenant1User = await TestDataFactory.createTestUser(dataSource, {
-        username: 'user1',
-        password: 'TestPassword123!',
-        email: 'user1@example.com'
-      });
-
-      // 创建用户2
-      tenant2User = await TestDataFactory.createTestUser(dataSource, {
-        username: 'user2',
-        password: 'TestPassword123!',
-        email: 'user2@example.com'
-      });
-
-      // 生成租户用户的token
-      tenant1Token = authService.generateToken(tenant1User);
-      tenant2Token = authService.generateToken(tenant2User);
-
-      // 清理文件数据
-      const fileRepository = dataSource.getRepository(File);
-    });
-
-    describe('文件创建租户隔离', () => {
-      it('应该为租户1创建文件并设置正确的租户ID', async () => {
-        const fileData = {
-          name: 'tenant1_file.pdf',
-          type: 'application/pdf',
-          size: 1024,
-          path: 'test/path',
-          description: '租户1的文件'
-        };
-
-        const response = await client['upload-policy'].$post({
-          json: fileData
-        }, {
-          headers: {
-            'Authorization': `Bearer ${tenant1Token}`
-          }
-        });
-
-        expect(response.status).toBe(200);
-        if (response.status === 200) {
-          const responseData = await response.json();
-          expect(responseData.file.name).toBe('tenant1_file.pdf');
-          expect(responseData.file.uploadUserId).toBe(tenant1User.id);
-
-          // 验证数据库中的租户ID
-          const dataSource = await IntegrationTestDatabase.getDataSource();
-          if (!dataSource) throw new Error('Database not initialized');
-          const fileRepository = dataSource.getRepository(File);
-          const savedFile = await fileRepository.findOne({
-            where: { name: fileData.name }
-          });
-        }
-      });
-
-      it('应该为租户2创建文件并设置正确的租户ID', async () => {
-        const fileData = {
-          name: 'tenant2_file.pdf',
-          type: 'application/pdf',
-          size: 2048,
-          path: 'test/path',
-          description: '租户2的文件'
-        };
-
-        const response = await client['upload-policy'].$post({
-          json: fileData
-        }, {
-          headers: {
-            'Authorization': `Bearer ${tenant2Token}`
-          }
-        });
-
-        expect(response.status).toBe(200);
-        if (response.status === 200) {
-          const responseData = await response.json();
-          expect(responseData.file.name).toBe('tenant2_file.pdf');
-          expect(responseData.file.uploadUserId).toBe(tenant2User.id);
-
-          // 验证数据库中的租户ID
-          const dataSource = await IntegrationTestDatabase.getDataSource();
-          if (!dataSource) throw new Error('Database not initialized');
-          const fileRepository = dataSource.getRepository(File);
-          const savedFile = await fileRepository.findOne({
-            where: { name: fileData.name }
-          });
-        }
-      });
-    });
-
-    describe('文件查询租户隔离', () => {
-      beforeEach(async () => {
-        const dataSource = await IntegrationTestDatabase.getDataSource();
-        if (!dataSource) throw new Error('Database not initialized');
-
-        const fileRepository = dataSource.getRepository(File);
-
-        // 创建租户1的文件
-        await fileRepository.save([
-          fileRepository.create({
-            name: 'tenant1_file1.pdf',
-            type: 'application/pdf',
-            size: 1024,
-            path: 'tenant1/path1',
-            uploadUserId: tenant1User.id,
-            
-            uploadTime: new Date()
-          }),
-          fileRepository.create({
-            name: 'tenant1_file2.jpg',
-            type: 'image/jpeg',
-            size: 2048,
-            path: 'tenant1/path2',
-            uploadUserId: tenant1User.id,
-            
-            uploadTime: new Date()
-          })
-        ]);
-
-        // 创建租户2的文件
-        await fileRepository.save([
-          fileRepository.create({
-            name: 'tenant2_file1.pdf',
-            type: 'application/pdf',
-            size: 3072,
-            path: 'tenant2/path1',
-            uploadUserId: tenant2User.id,
-            
-            uploadTime: new Date()
-          })
-        ]);
-      });
-
-      it('应该只返回租户1的文件列表', async () => {
-        const response = await client.index.$get({
-          query: {}
-        }, {
-          headers: {
-            'Authorization': `Bearer ${tenant1Token}`
-          }
-        });
-
-        expect(response.status).toBe(200);
-        if (response.status === 200) {
-          const responseData = await response.json();
-          expect(Array.isArray(responseData.data)).toBe(true);
-          expect(responseData.data).toHaveLength(2);
-          expect(responseData.data.some((file: any) => file.name === 'tenant1_file1.pdf')).toBe(true);
-          expect(responseData.data.some((file: any) => file.name === 'tenant1_file2.jpg')).toBe(true);
-        }
-      });
-
-      it('应该只返回租户2的文件列表', async () => {
-        const response = await client.index.$get({
-          query: {}
-        }, {
-          headers: {
-            'Authorization': `Bearer ${tenant2Token}`
-          }
-        });
-
-        expect(response.status).toBe(200);
-        if (response.status === 200) {
-          const responseData = await response.json();
-          expect(Array.isArray(responseData.data)).toBe(true);
-          expect(responseData.data).toHaveLength(1);
-          expect(responseData.data[0].name).toBe('tenant2_file1.pdf');
-        }
-      });
-
-      it('租户1不应该访问租户2的文件', async () => {
-        const dataSource = await IntegrationTestDatabase.getDataSource();
-        if (!dataSource) throw new Error('Database not initialized');
-        const fileRepository = dataSource.getRepository(File);
-        const tenant2File = await fileRepository.findOneBy({  name: 'tenant2_file1.pdf' });
-
-        if (tenant2File) {
-          const response = await client[':id'].$get({
-            param: { id: tenant2File.id }
-          }, {
-            headers: {
-              'Authorization': `Bearer ${tenant1Token}`
-            }
-          });
-
-          // 应该返回404,因为租户1不能访问租户2的文件
-          expect(response.status).toBe(404);
-        }
-      });
-    });
-
-    describe('文件删除租户隔离', () => {
-      let tenant1File: File;
-      let tenant2File: File;
-
-      beforeEach(async () => {
-        const dataSource = await IntegrationTestDatabase.getDataSource();
-        if (!dataSource) throw new Error('Database not initialized');
-        const fileRepository = dataSource.getRepository(File);
-
-        // 创建租户1的文件
-        tenant1File = fileRepository.create({
-          name: 'tenant1_delete_test.pdf',
-          type: 'application/pdf',
-          size: 1024,
-          path: 'tenant1/delete_test',
-          uploadUserId: tenant1User.id,
-          
-          uploadTime: new Date()
-        });
-
-        // 创建租户2的文件
-        tenant2File = fileRepository.create({
-          name: 'tenant2_delete_test.pdf',
-          type: 'application/pdf',
-          size: 2048,
-          path: 'tenant2/delete_test',
-          uploadUserId: tenant2User.id,
-          
-          uploadTime: new Date()
-        });
-
-        await fileRepository.save([tenant1File, tenant2File]);
-      });
-
-      it('应该允许租户1删除自己的文件', async () => {
-        const response = await client[':id'].$delete({
-          param: { id: tenant1File.id }
-        }, {
-          headers: {
-            'Authorization': `Bearer ${tenant1Token}`
-          }
-        });
-
-        expect(response.status).toBe(200);
-
-        // 验证文件已被删除
-        const dataSource = await IntegrationTestDatabase.getDataSource();
-        if (!dataSource) throw new Error('Database not initialized');
-        const fileRepository = dataSource.getRepository(File);
-        const deletedFile = await fileRepository.findOneBy({ id: tenant1File.id });
-        expect(deletedFile).toBeNull();
-      });
-
-      it('不应该允许租户2删除租户1的文件', async () => {
-        const response = await client[':id'].$delete({
-          param: { id: tenant1File.id }
-        }, {
-          headers: {
-            'Authorization': `Bearer ${tenant2Token}`
-          }
-        });
-
-        // 调试输出
-        console.debug(`租户2删除租户1文件响应状态: ${response.status}`);
-        if (response.status as number !== 200) {
-          const responseData = await response.json();
-          console.debug(`响应数据:`, responseData);
-        }
-
-        // 应该返回404或403,因为租户2不能删除租户1的文件
-        expect([404, 403]).toContain(response.status);
-
-        // 验证文件仍然存在
-        const dataSource = await IntegrationTestDatabase.getDataSource();
-        if (!dataSource) throw new Error('Database not initialized');
-        const fileRepository = dataSource.getRepository(File);
-        const existingFile = await fileRepository.findOneBy({ id: tenant1File.id });
-        expect(existingFile).toBeDefined();
-      });
-    });
-  });
 });

+ 1 - 4
packages/core-module/system-config-module/src/entities/system-config.entity.ts

@@ -1,13 +1,10 @@
 import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
 
-@Entity('system_config_mt')
+@Entity('system_config')
 export class SystemConfig {
   @PrimaryGeneratedColumn({ name: 'id', type: 'int', unsigned: true })
   id!: number;
 
-  @Column({ name: 'tenant_id', type: 'int', unsigned: true, comment: '租户ID' })
-  tenantId!: number;
-
   @Column({ name: 'config_key', type: 'varchar', length: 255, comment: '配置键' })
   configKey!: string;
 

+ 1 - 6
packages/core-module/system-config-module/src/routes/system-config.routes.ts

@@ -15,12 +15,7 @@ const systemConfigCrudRoutes = createCrudRoutes({
   listSchema: SystemConfigSchema,
   searchFields: ['configKey', 'description'],
   middleware: [authMiddleware],
-  readOnly: true, // 设为只读,创建、更新、删除操作通过自定义路由处理
-  tenantOptions: {
-    enabled: true,
-    tenantIdField: 'tenantId',
-    autoExtractFromContext: true
-  }
+  readOnly: true // 设为只读,创建、更新、删除操作通过自定义路由处理
 });
 
 // 创建路由实例 - 聚合自定义路由和CRUD路由

+ 0 - 4
packages/core-module/system-config-module/src/schemas/system-config.schema.ts

@@ -5,10 +5,6 @@ export const SystemConfigSchema = z.object({
     description: '系统配置ID',
     example: 1
   }),
-  tenantId: z.number().int().positive().openapi({
-    description: '租户ID',
-    example: 1
-  }),
   configKey: z.string().min(1).max(255).openapi({
     description: '配置键',
     example: 'app.login.enabled'

+ 7 - 0
packages/core-module/system-config-module/tests/integration/system-config-redis-cache.integration.test.ts

@@ -108,6 +108,9 @@ describe('系统配置Redis缓存集成测试', () => {
 
   describe('缓存失效测试', () => {
     it('应该在配置更新时清除缓存', async () => {
+      // 清除可能存在的缓存
+      await redisUtil.deleteSystemConfig('app.update.test');
+
       // 创建配置
       const config = await systemConfigService.create({
         configKey: 'app.update.test',
@@ -119,11 +122,15 @@ describe('系统配置Redis缓存集成测试', () => {
 
       // 验证缓存已写入
       const cachedValue = await redisUtil.getSystemConfig('app.update.test');
+      console.debug('缓存值:', cachedValue, '期望值: initial-value');
       expect(cachedValue).toBe('initial-value');
 
       // 更新配置
       await systemConfigService.update(config.id, { configValue: 'updated-value' });
 
+      // 等待一小段时间确保缓存操作完成
+      await new Promise(resolve => setTimeout(resolve, 50));
+
       // 验证缓存已清除
       const clearedCache = await redisUtil.getSystemConfig('app.update.test');
       expect(clearedCache).toBeNull();

+ 7 - 0
packages/core-module/system-config-module/tests/integration/system-config.routes.integration.test.ts

@@ -232,6 +232,9 @@ describe('系统配置路由API集成测试 (使用hono/testing)', () => {
   describe('自定义路由缓存刷新验证', () => {
     beforeEach(async () => {
       // 清除测试缓存
+      await redisUtil.deleteSystemConfig('app.login.enabled');
+      await redisUtil.deleteSystemConfig('app.payment.enabled');
+      await redisUtil.deleteSystemConfig('app.analytics.enabled');
     });
 
     it('应该通过自定义创建路由刷新缓存', async () => {
@@ -254,6 +257,10 @@ describe('系统配置路由API集成测试 (使用hono/testing)', () => {
         }
       });
 
+      if (response.status !== 201) {
+        const errorText = await response.text();
+        console.debug('Response error:', response.status, errorText);
+      }
       expect(response.status).toBe(201);
       const result = await response.json() as any;
       expect(result.configKey).toBe(configData.configKey);

+ 16 - 17
packages/core-module/user-module/src/routes/custom.routes.ts

@@ -2,20 +2,20 @@ import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
 import { z } from '@hono/zod-openapi';
 import { UserService } from '../services/user.service';
 import { AppDataSource, ErrorSchema } from '@d8d/shared-utils';
-import { CreateUserDtoMt, UpdateUserDtoMt, UserSchemaMt } from '../schemas/user.schema';
+import { CreateUserDto, UpdateUserDto, UserSchema } from '../schemas/user.schema';
 import { parseWithAwait } from '@d8d/shared-utils';
 import { authMiddleware } from '@d8d/core-module/auth-module';
 import { AuthContext } from '@d8d/shared-types';
 
-// 创建多租户用户路由 - 自定义业务逻辑(密码加密等)
-const createUserRouteMt = createRoute({
+// 创建用户路由 - 自定义业务逻辑(密码加密等)
+const createUserRoute = createRoute({
   method: 'post',
   path: '/',
   middleware: [authMiddleware],
   request: {
     body: {
       content: {
-        'application/json': { schema: CreateUserDtoMt }
+        'application/json': { schema: CreateUserDto }
       }
     }
   },
@@ -23,7 +23,7 @@ const createUserRouteMt = createRoute({
     201: {
       description: '用户创建成功',
       content: {
-        'application/json': { schema: UserSchemaMt }
+        'application/json': { schema: UserSchema }
       }
     },
     400: {
@@ -41,8 +41,8 @@ const createUserRouteMt = createRoute({
   }
 });
 
-// 更新多租户用户路由 - 自定义业务逻辑
-const updateUserRouteMt = createRoute({
+// 更新用户路由 - 自定义业务逻辑
+const updateUserRoute = createRoute({
   method: 'put',
   path: '/{id}',
   middleware: [authMiddleware],
@@ -56,7 +56,7 @@ const updateUserRouteMt = createRoute({
     }),
     body: {
       content: {
-        'application/json': { schema: UpdateUserDtoMt }
+        'application/json': { schema: UpdateUserDto }
       }
     }
   },
@@ -64,7 +64,7 @@ const updateUserRouteMt = createRoute({
     200: {
       description: '用户更新成功',
       content: {
-        'application/json': { schema: UserSchemaMt }
+        'application/json': { schema: UserSchema }
       }
     },
     400: {
@@ -86,8 +86,8 @@ const updateUserRouteMt = createRoute({
   }
 });
 
-// 删除多租户用户路由 - 自定义业务逻辑
-const deleteUserRouteMt = createRoute({
+// 删除用户路由 - 自定义业务逻辑
+const deleteUserRoute = createRoute({
   method: 'delete',
   path: '/{id}',
   middleware: [authMiddleware],
@@ -118,14 +118,14 @@ const deleteUserRouteMt = createRoute({
 });
 
 const app = new OpenAPIHono<AuthContext>()
-  .openapi(createUserRouteMt, async (c) => {
+  .openapi(createUserRoute, async (c) => {
     try {
       const data = c.req.valid('json');
       const userService = new UserService(AppDataSource);
 
       const result = await userService.createUser(data);
 
-      return c.json(await parseWithAwait(UserSchemaMt, result), 201);
+      return c.json(await parseWithAwait(UserSchema, result), 201);
     } catch (error) {
       if (error instanceof z.ZodError) {
         return c.json({
@@ -149,7 +149,7 @@ const app = new OpenAPIHono<AuthContext>()
       }, 500);
     }
   })
-  .openapi(updateUserRouteMt, async (c) => {
+  .openapi(updateUserRoute, async (c) => {
     try {
       const { id } = c.req.valid('param');
       const data = c.req.valid('json');
@@ -161,7 +161,7 @@ const app = new OpenAPIHono<AuthContext>()
         return c.json({ code: 404, message: '资源不存在' }, 404);
       }
 
-      return c.json(await parseWithAwait(UserSchemaMt, result), 200);
+      return c.json(await parseWithAwait(UserSchema, result), 200);
     } catch (error) {
       if (error instanceof z.ZodError) {
         return c.json({
@@ -176,12 +176,11 @@ const app = new OpenAPIHono<AuthContext>()
       }, 500);
     }
   })
-  .openapi(deleteUserRouteMt, async (c) => {
+  .openapi(deleteUserRoute, async (c) => {
     try {
       const { id } = c.req.valid('param');
       const userService = new UserService(AppDataSource);
 
-      // 从认证上下文中获取租户ID
       const success = await userService.deleteUser(id);
 
       if (!success) {

+ 8 - 13
packages/core-module/user-module/src/routes/role.routes.ts

@@ -1,30 +1,25 @@
 import { createCrudRoutes } from '@d8d/shared-crud';
 import { Role } from '../entities/role.entity';
-import { RoleSchemaMt, CreateRoleDtoMt, UpdateRoleDtoMt } from '../schemas/role.schema';
+import { RoleSchema, CreateRoleDto, UpdateRoleDto } from '../schemas/role.schema';
 import { OpenAPIHono } from '@hono/zod-openapi';
 import { authMiddleware } from '@d8d/core-module/auth-module';
 
-// 创建多租户角色CRUD路由
-const roleRoutesMt = createCrudRoutes({
+// 创建角色CRUD路由(非多租户)
+const roleRoutes = createCrudRoutes({
   entity: Role,
-  createSchema: CreateRoleDtoMt,
-  updateSchema: UpdateRoleDtoMt,
-  getSchema: RoleSchemaMt,
-  listSchema: RoleSchemaMt,
+  createSchema: CreateRoleDto,
+  updateSchema: UpdateRoleDto,
+  getSchema: RoleSchema,
+  listSchema: RoleSchema,
   searchFields: ['name', 'description'],
   middleware: [
     authMiddleware,
     // permissionMiddleware(checkPermission(['role:manage']))
   ],
-  tenantOptions: {
-    enabled: true,
-    tenantIdField: 'tenantId',
-    autoExtractFromContext: true
-  }
 })
 
 const app = new OpenAPIHono()
-  .route('/', roleRoutesMt)
+  .route('/', roleRoutes)
 
 // .route('/', customRoute)
 

+ 11 - 16
packages/core-module/user-module/src/routes/user.routes.ts

@@ -1,31 +1,26 @@
 import { OpenAPIHono } from '@hono/zod-openapi';
 import { createCrudRoutes } from '@d8d/shared-crud';
 import { UserEntity } from '../entities/user.entity';
-import { CreateUserDtoMt, UpdateUserDtoMt, UserResponseSchemaMt } from '../schemas/user.schema';
-import customRoutesMt from './custom.routes';
+import { CreateUserDto, UpdateUserDto, UserResponseSchema } from '../schemas/user.schema';
+import customRoutes from './custom.routes';
 import { authMiddleware } from '@d8d/core-module/auth-module';
 
-// 创建多租户通用CRUD路由配置
-const userCrudRoutesMt = createCrudRoutes({
+// 创建通用CRUD路由配置(非多租户)
+const userCrudRoutes = createCrudRoutes({
   entity: UserEntity,
-  createSchema: CreateUserDtoMt,
-  updateSchema: UpdateUserDtoMt,
-  getSchema: UserResponseSchemaMt,
-  listSchema: UserResponseSchemaMt,
+  createSchema: CreateUserDto,
+  updateSchema: UpdateUserDto,
+  getSchema: UserResponseSchema,
+  listSchema: UserResponseSchema,
   searchFields: ['username', 'nickname', 'phone', 'email'],
   relations: ['roles', 'avatarFile'],
   middleware: [authMiddleware],
   readOnly: true, // 创建/更新/删除使用自定义路由
-  tenantOptions: {
-    enabled: true,
-    tenantIdField: 'tenantId',
-    autoExtractFromContext: true
-  }
 });
 
-// 创建多租户混合路由应用
+// 创建混合路由应用
 const app = new OpenAPIHono()
-  .route('/', customRoutesMt)   // 多租户自定义业务路由
-  .route('/', userCrudRoutesMt); // 多租户通用CRUD路由
+  .route('/', customRoutes)   // 自定义业务路由
+  .route('/', userCrudRoutes); // 通用CRUD路由
 
 export default app;

+ 6 - 1
packages/core-module/user-module/src/schemas/role.schema.ts

@@ -29,4 +29,9 @@ export const RoleSchemaMt = z.object({
 });
 
 export const CreateRoleDtoMt = RoleSchemaMt.omit({ id: true, tenantId: true, createdAt: true, updatedAt: true });
-export const UpdateRoleDtoMt = RoleSchemaMt.partial();
+export const UpdateRoleDtoMt = RoleSchemaMt.partial();
+
+// 非多租户版本
+export const RoleSchema = RoleSchemaMt.omit({ tenantId: true });
+export const CreateRoleDto = RoleSchemaMt.omit({ id: true, tenantId: true, createdAt: true, updatedAt: true });
+export const UpdateRoleDto = RoleSchemaMt.partial();

+ 0 - 112
packages/core-module/user-module/tests/integration/user.routes.integration.test.ts

@@ -566,116 +566,4 @@ describe('用户路由API集成测试 (使用hono/testing)', () => {
     });
   });
 
-  describe('租户隔离测试', () => {
-    let tenant1Token: string;
-    let tenant2Token: string;
-    let tenant1User: any;
-    let tenant2User: any;
-
-    beforeEach(async () => {
-      // 创建租户1的用户和token
-      const dataSource = await IntegrationTestDatabase.getDataSource();
-      if (!dataSource) throw new Error('Database not initialized');
-
-      tenant1User = await TestDataFactory.createTestUser(dataSource, {
-        username: 'tenant1_user',
-        password: 'password123',
-        email: 'tenant1@example.com',
-      });
-
-      tenant2User = await TestDataFactory.createTestUser(dataSource, {
-        username: 'tenant2_user',
-        password: 'password123',
-        email: 'tenant2@example.com',
-      });
-
-      // 生成不同租户的token,确保包含完整的用户信息
-      tenant1Token = authService.generateToken(tenant1User);
-      tenant2Token = authService.generateToken(tenant2User);
-    });
-
-    it('应该只返回当前租户的用户列表', async () => {
-      // 租户1只能看到租户1的用户
-      const response1 = await client.index.$get({
-        query: {}
-      }, {
-        headers: {
-          'Authorization': `Bearer ${tenant1Token}`
-        }
-      });
-
-      console.debug('租户1列表响应状态:', response1.status);
-      if (response1.status !== 200) {
-        const errorResult = await response1.json();
-        console.debug('租户1列表错误响应:', errorResult);
-      }
-      expect(response1.status).toBe(200);
-      const result1 = await response1.json();
-      console.debug('租户1返回的用户数据:', (result1 as any).data);
-      expect((result1 as any).data).toHaveLength(2);
-
-      // 租户2只能看到租户2的用户
-      const response2 = await client.index.$get({
-        query: {}
-      }, {
-        headers: {
-          'Authorization': `Bearer ${tenant2Token}`
-        }
-      });
-
-      console.debug('租户2列表响应状态:', response2.status);
-      if (response2.status !== 200) {
-        const errorResult = await response2.json();
-        console.debug('租户2列表错误响应:', errorResult);
-      }
-      expect(response2.status).toBe(200);
-      const result2 = await response2.json();
-      console.debug('租户2返回的用户数据:', (result2 as any).data);
-      expect((result2 as any).data).toHaveLength(1);
-    });
-
-    it('应该拒绝跨租户访问用户详情', async () => {
-      // 租户1尝试访问租户2的用户
-      const response = await client[':id'].$get({
-        param: { id: tenant2User.id }
-      }, {
-        headers: {
-          'Authorization': `Bearer ${tenant1Token}`
-        }
-      });
-
-      expect(response.status).toBe(404);
-    });
-
-    it('应该拒绝跨租户更新用户', async () => {
-      const updateData = {
-        nickname: '尝试跨租户更新'
-      };
-
-      // 租户1尝试更新租户2的用户
-      const response = await client[':id'].$put({
-        param: { id: tenant2User.id },
-        json: updateData
-      }, {
-        headers: {
-          'Authorization': `Bearer ${tenant1Token}`
-        }
-      });
-
-      expect(response.status).toBe(404);
-    });
-
-    it('应该拒绝跨租户删除用户', async () => {
-      // 租户1尝试删除租户2的用户
-      const response = await client[':id'].$delete({
-        param: { id: tenant2User.id }
-      }, {
-        headers: {
-          'Authorization': `Bearer ${tenant1Token}`
-        }
-      });
-
-      expect(response.status).toBe(404);
-    });
-  });
 });

+ 0 - 5
packages/core-module/user-module/tests/routes/test-user.routes.ts

@@ -13,11 +13,6 @@ const userCrudRoutesMt = createCrudRoutes({
   searchFields: ['username', 'nickname', 'phone', 'email'],
   relations: ['roles'],
   readOnly: false, // 启用所有CRUD操作
-  tenantOptions: {
-    enabled: true,
-    tenantIdField: 'tenantId',
-    autoExtractFromContext: true
-  }
 });
 
 // 创建多租户混合路由应用(测试版本)