2
0
Эх сурвалжийг харах

Merge remote-tracking branch 'upstream/bmad-method' into bmad-method

yourname 2 сар өмнө
parent
commit
5d09d108c8
33 өөрчлөгдсөн 29 нэмэгдсэн , 46 устгасан
  1. 2 1
      .claude/settings.local.json
  2. 2 0
      CLAUDE.md
  3. 1 1
      package.json
  4. 1 0
      src/client/__test_utils__/test-render.tsx
  5. 0 2
      src/client/admin/components/ErrorPage.tsx
  6. 0 1
      src/client/admin/components/NotFoundPage.tsx
  7. 3 3
      src/client/admin/hooks/AuthProvider.tsx
  8. 0 1
      src/client/admin/pages/Dashboard.tsx
  9. 0 4
      src/client/admin/pages/__tests__/Users.test.tsx
  10. 0 1
      src/client/admin/routes.tsx
  11. 0 2
      src/client/home/components/ErrorPage.tsx
  12. 0 1
      src/client/home/components/NotFoundPage.tsx
  13. 3 3
      src/client/home/hooks/AuthProvider.tsx
  14. 0 1
      src/client/home/index.tsx
  15. 0 1
      src/client/home/layouts/MainLayout.tsx
  16. 1 3
      src/client/home/pages/LoginPage.tsx
  17. 0 1
      src/client/home/pages/MemberPage.tsx
  18. 1 2
      src/client/home/pages/RegisterPage.tsx
  19. 1 2
      src/client/home/routes.tsx
  20. 1 1
      src/server/__test_utils__/service-mocks.ts
  21. 2 3
      src/server/api.ts
  22. 1 1
      src/server/api/auth/__tests__/auth.integration.test.ts
  23. 0 1
      src/server/api/auth/sso-verify.ts
  24. 0 1
      src/server/api/roles/index.ts
  25. 2 2
      src/server/api/users/__tests__/users.integration.test.ts
  26. 1 1
      src/server/modules/users/role.service.ts
  27. 0 1
      src/server/renderer.tsx
  28. 0 2
      src/server/utils/__tests__/backup.test.ts
  29. 0 1
      src/server/utils/__tests__/restore.test.ts
  30. 4 0
      src/server/utils/generic-crud.routes.ts
  31. 1 1
      src/server/utils/generic-crud.service.ts
  32. 1 1
      src/server/utils/parseWithAwait.ts
  33. 1 0
      src/test/test-utils.ts

+ 2 - 1
.claude/settings.local.json

@@ -28,7 +28,8 @@
       "Bash(node:*)",
       "Bash(pnpm run db:backup:latest:*)",
       "Bash(done)",
-      "Bash(do sed -i '8d' \"$file\")"
+      "Bash(do sed -i '8d' \"$file\")",
+      "Bash(pnpm typecheck)"
     ],
     "deny": [],
     "ask": []

+ 2 - 0
CLAUDE.md

@@ -11,7 +11,9 @@
 - use pnpm
 - 数据库在同一容器组的另一个容器中,需要运行 psql -h 127.0.0.1 -U postgres 来访问
 - vitest中,只有console.debug会显示,其他的都屏蔽了
+- vitest中,用import 来配合 vi.mocked,而不是require
 - e2e测试平常只运行 pnpm test:e2e:chromium 就行
 - e2e测试失败时先查看页面结构 test-results/**/error-context.md
+- 前端是 hono/client  hc  rpc 的,不是直接fetch
 - bmad-core dir is in .bmad-core
 - 必须用中文回答

+ 1 - 1
package.json

@@ -30,7 +30,7 @@
     "test:analyze": "node scripts/analyze-test-results.js",
     "lint": "eslint . --ext .ts,.tsx",
     "lint:fix": "eslint . --ext .ts,.tsx --fix",
-    "typecheck": "tsc --noEmit"
+    "typecheck": "tsc --noEmit --project ."
   },
   "dependencies": {
     "@ant-design/icons": "^6.0.0",

+ 1 - 0
src/client/__test_utils__/test-render.tsx

@@ -3,6 +3,7 @@ import { BrowserRouter } from 'react-router-dom';
 import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
 import { ThemeProvider } from 'next-themes';
 import { AuthProvider } from '@/client/admin/hooks/AuthProvider';
+import { vi } from 'vitest';
 
 /**
  * 创建测试用的QueryClient

+ 0 - 2
src/client/admin/components/ErrorPage.tsx

@@ -1,4 +1,3 @@
-import React from 'react';
 import { useRouteError, useNavigate } from 'react-router';
 import { Alert, AlertDescription, AlertTitle } from '@/client/components/ui/alert';
 import { Button } from '@/client/components/ui/button';
@@ -7,7 +6,6 @@ import { AlertCircle } from 'lucide-react';
 export const ErrorPage = () => {
   const navigate = useNavigate();
   const error = useRouteError() as any;
-  const errorMessage = error?.statusText || error?.message || '未知错误';
   
   return (
     <div className="flex flex-col items-center justify-center flex-grow p-4">

+ 0 - 1
src/client/admin/components/NotFoundPage.tsx

@@ -1,4 +1,3 @@
-import React from 'react';
 import { useNavigate } from 'react-router';
 import { Button } from '@/client/components/ui/button';
 

+ 3 - 3
src/client/admin/hooks/AuthProvider.tsx

@@ -1,4 +1,4 @@
-import React, { useState, useEffect, createContext, useContext } from 'react';
+import React, { useState, createContext, useContext } from 'react';
 
 import {
   useQuery,
@@ -10,7 +10,7 @@ import type {
   AuthContextType
 } from '@/share/types';
 import { authClient } from '@/client/api';
-import type { InferResponseType, InferRequestType } from 'hono/client';
+import type { InferResponseType } from 'hono/client';
 
 type User = InferResponseType<typeof authClient.me.$get, 200>;
 
@@ -80,7 +80,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
     retry: false
   });
 
-  const handleLogin = async (username: string, password: string, latitude?: number, longitude?: number): Promise<void> => {
+  const handleLogin = async (username: string, password: string): Promise<void> => {
     try {
       // 使用AuthAPI登录
       const response = await authClient.login.$post({

+ 0 - 1
src/client/admin/pages/Dashboard.tsx

@@ -1,4 +1,3 @@
-import React from 'react';
 import { useNavigate } from 'react-router';
 import { Users, Bell, Eye, TrendingUp, TrendingDown, Activity } from 'lucide-react';
 import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/client/components/ui/card';

+ 0 - 4
src/client/admin/pages/__tests__/Users.test.tsx

@@ -421,8 +421,6 @@ describe('UsersPage Component', () => {
   });
 
   it.skip('应该处理删除用户操作', async () => {
-    const user = userEvent.setup();
-
     // 模拟删除成功
     (userClient[':id']['$delete'] as any).mockResolvedValue({
       status: 204,
@@ -450,8 +448,6 @@ describe('UsersPage Component', () => {
   });
 
   it.skip('应该处理编辑用户操作', async () => {
-    const user = userEvent.setup();
-
     // 模拟更新成功
     (userClient[':id']['$put'] as any).mockResolvedValue({
       status: 200,

+ 0 - 1
src/client/admin/routes.tsx

@@ -1,4 +1,3 @@
-import React from 'react';
 import { createBrowserRouter, Navigate } from 'react-router';
 import { ProtectedRoute } from './components/ProtectedRoute';
 import { MainLayout } from './layouts/MainLayout';

+ 0 - 2
src/client/home/components/ErrorPage.tsx

@@ -1,4 +1,3 @@
-import React from 'react';
 import { useRouteError, useNavigate } from 'react-router';
 import { AlertCircle, RotateCcw, Home } from 'lucide-react';
 import { Button } from '@/client/components/ui/button';
@@ -8,7 +7,6 @@ import { Alert, AlertDescription, AlertTitle } from '@/client/components/ui/aler
 export const ErrorPage = () => {
   const navigate = useNavigate();
   const error = useRouteError() as any;
-  const errorMessage = error?.statusText || error?.message || '未知错误';
   
   return (
     <div className="flex flex-col items-center justify-center min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800 p-4">

+ 0 - 1
src/client/home/components/NotFoundPage.tsx

@@ -1,4 +1,3 @@
-import React from 'react';
 import { useNavigate } from 'react-router';
 import { ArrowLeft, Home } from 'lucide-react';
 import { Button } from '@/client/components/ui/button';

+ 3 - 3
src/client/home/hooks/AuthProvider.tsx

@@ -1,4 +1,4 @@
-import React, { useState, useEffect, createContext, useContext } from 'react';
+import React, { useState, createContext, useContext } from 'react';
 
 import {
   useQuery,
@@ -10,7 +10,7 @@ import type {
   AuthContextType
 } from '@/share/types';
 import { authClient } from '@/client/api';
-import type { InferResponseType, InferRequestType } from 'hono/client';
+import type { InferResponseType } from 'hono/client';
 
 export type User = InferResponseType<typeof authClient.me.$get, 200>;
 
@@ -80,7 +80,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
     retry: false
   });
 
-  const handleLogin = async (username: string, password: string, latitude?: number, longitude?: number): Promise<void> => {
+  const handleLogin = async (username: string, password: string): Promise<void> => {
     try {
       // 使用AuthAPI登录
       const response = await authClient.login.$post({

+ 0 - 1
src/client/home/index.tsx

@@ -1,5 +1,4 @@
 import { createRoot } from 'react-dom/client'
-import { getGlobalConfig } from '../utils/utils'
 import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
 import { AuthProvider } from './hooks/AuthProvider'
 import { RouterProvider } from 'react-router-dom'

+ 0 - 1
src/client/home/layouts/MainLayout.tsx

@@ -1,4 +1,3 @@
-import React, { useState, useEffect, useMemo } from 'react';
 import {
   Outlet
 } from 'react-router';

+ 1 - 3
src/client/home/pages/LoginPage.tsx

@@ -1,4 +1,3 @@
-import React from 'react';
 import { useForm } from 'react-hook-form';
 import { zodResolver } from '@hookform/resolvers/zod';
 import { z } from 'zod';
@@ -8,10 +7,9 @@ import { toast } from 'sonner';
 
 import { Button } from '@/client/components/ui/button';
 import { Input } from '@/client/components/ui/input';
-import { Label } from '@/client/components/ui/label';
 import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/client/components/ui/card';
 import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/client/components/ui/form';
-import { Eye, EyeOff, User, Lock } from 'lucide-react';
+import { User, Lock } from 'lucide-react';
 
 const loginSchema = z.object({
   username: z.string().min(3, '用户名至少3个字符'),

+ 0 - 1
src/client/home/pages/MemberPage.tsx

@@ -4,7 +4,6 @@ import { useAuth } from '@/client/home/hooks/AuthProvider';
 import { Button } from '@/client/components/ui/button';
 import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/client/components/ui/card';
 import { Avatar, AvatarFallback, AvatarImage } from '@/client/components/ui/avatar';
-import { Badge } from '@/client/components/ui/badge';
 import { Separator } from '@/client/components/ui/separator';
 import { 
   User, 

+ 1 - 2
src/client/home/pages/RegisterPage.tsx

@@ -1,4 +1,3 @@
-import React from 'react';
 import { useForm } from 'react-hook-form';
 import { zodResolver } from '@hookform/resolvers/zod';
 import { z } from 'zod';
@@ -11,7 +10,7 @@ import { Button } from '@/client/components/ui/button';
 import { Input } from '@/client/components/ui/input';
 import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/client/components/ui/card';
 import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/client/components/ui/form';
-import { Eye, EyeOff, User, Lock } from 'lucide-react';
+import { User, Lock } from 'lucide-react';
 
 const registerSchema = z.object({
   username: z.string()

+ 1 - 2
src/client/home/routes.tsx

@@ -1,5 +1,4 @@
-import React from 'react';
-import { createBrowserRouter, Navigate } from 'react-router';
+import { createBrowserRouter } from 'react-router';
 import { ProtectedRoute } from './components/ProtectedRoute';
 import { ErrorPage } from './components/ErrorPage';
 import { NotFoundPage } from './components/NotFoundPage';

+ 1 - 1
src/server/__test_utils__/service-mocks.ts

@@ -133,7 +133,7 @@ export class ServiceMocks {
       if (service && typeof service === 'object') {
         Object.values(service).forEach(mock => {
           if (mock && typeof mock === 'function' && 'mockClear' in mock) {
-            mock.mockClear();
+            (mock as any).mockClear();
           }
         });
       }

+ 2 - 3
src/server/api.ts

@@ -25,8 +25,7 @@ const api = new OpenAPIHono<AuthContext>()
 api.onError(errorHandler)
 
 // Rate limiting
-api.use('/api/v1/*', async (c, next) => {
-  const ip = c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip')
+api.use('/api/v1/*', async (_, next) => {
   // 实现速率限制逻辑
   await next()
 })
@@ -85,7 +84,7 @@ if(1){
   app.get('/ui', swaggerUI({
     url: '/doc',
     persistAuthorization: true,
-    manuallySwaggerUIHtml: (asset) => `
+    manuallySwaggerUIHtml: () => `
       <div>
         <div id="swagger-ui"></div>
         <link rel="stylesheet" href="https://ai-oss.d8d.fun/swagger-ui-dist/swagger-ui.css" />

+ 1 - 1
src/server/api/auth/__tests__/auth.integration.test.ts

@@ -1,4 +1,4 @@
-import { describe, it, expect, beforeEach, afterEach } from 'vitest';
+import { describe, it, expect, beforeEach } from 'vitest';
 import { testClient } from 'hono/testing';
 import {
   IntegrationTestDatabase,

+ 0 - 1
src/server/api/auth/sso-verify.ts

@@ -3,7 +3,6 @@ import { AuthService } from '@/server/modules/auth/auth.service'
 import { UserService } from '@/server/modules/users/user.service'
 import { ErrorSchema } from '@/server/utils/errorHandler'
 import { AppDataSource } from '@/server/data-source'
-import { AuthContext } from '@/server/types/context'
 
 const userService = new UserService(AppDataSource)
 const authService = new AuthService(userService)

+ 0 - 1
src/server/api/roles/index.ts

@@ -2,7 +2,6 @@ import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
 import { Role } from '@/server/modules/users/role.entity';
 import { RoleSchema, CreateRoleDto, UpdateRoleDto } from '@/server/modules/users/role.schema';
 import { authMiddleware } from '@/server/middleware/auth.middleware';
-import { checkPermission, permissionMiddleware } from '@/server/middleware/permission.middleware';
 import { OpenAPIHono } from '@hono/zod-openapi';
 
 // 创建角色CRUD路由

+ 2 - 2
src/server/api/users/__tests__/users.integration.test.ts

@@ -1,4 +1,4 @@
-import { describe, it, expect, beforeEach, afterEach } from 'vitest';
+import { describe, it, expect, beforeEach } from 'vitest';
 import { testClient } from 'hono/testing';
 import {
   IntegrationTestDatabase,
@@ -75,7 +75,7 @@ describe('用户API集成测试 (使用hono/testing)', () => {
       if (!dataSource) throw new Error('Database not initialized');
 
       // 先创建一个用户
-      const existingUser = await TestDataFactory.createTestUser(dataSource, {
+      await TestDataFactory.createTestUser(dataSource, {
         username: 'duplicate_user'
       });
 

+ 1 - 1
src/server/modules/users/role.service.ts

@@ -1,4 +1,4 @@
-import { DataSource, Repository } from 'typeorm';
+import { DataSource } from 'typeorm';
 import { Role } from './role.entity';
 import { GenericCrudService } from '@/server/utils/generic-crud.service';
 

+ 0 - 1
src/server/renderer.tsx

@@ -1,5 +1,4 @@
 import { GlobalConfig } from '@/share/types'
-import { reactRenderer } from '@hono/react-renderer'
 // import { Script, Link } from 'hono-vite-react-stack-node/components'
 import process from 'node:process'
 

+ 0 - 2
src/server/utils/__tests__/backup.test.ts

@@ -1,6 +1,5 @@
 import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
 import { DatabaseBackup } from '../backup'
-import { promises as fs } from 'fs'
 import path from 'path'
 
 // Mock pg-dump-restore
@@ -179,7 +178,6 @@ describe('DatabaseBackup', () => {
 
   describe('startScheduledBackups', () => {
     it('应该启动定时备份任务', async () => {
-      const cron = await import('node-cron')
       const { logger } = await import('../logger')
 
       backup.startScheduledBackups()

+ 0 - 1
src/server/utils/__tests__/restore.test.ts

@@ -1,6 +1,5 @@
 import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
 import { DatabaseRestore } from '../restore'
-import { promises as fs } from 'fs'
 import path from 'path'
 
 // Mock pg-dump-restore

+ 4 - 0
src/server/utils/generic-crud.routes.ts

@@ -267,6 +267,7 @@ export function createCrudRoutes<
           }, 500);
         }
       })
+      // @ts-ignore
       .openapi(createRouteDef, async (c: any) => {
         try {
           const data = c.req.valid('json');
@@ -288,6 +289,7 @@ export function createCrudRoutes<
           }, 500);
         }
       })
+      // @ts-ignore
       .openapi(getRouteDef, async (c: any) => {
         try {
           const { id } = c.req.valid('param');
@@ -314,6 +316,7 @@ export function createCrudRoutes<
           }, 500);
         }
       })
+      // @ts-ignore
       .openapi(updateRouteDef, async (c: any) => {
         try {
           const { id } = c.req.valid('param');
@@ -423,6 +426,7 @@ export function createCrudRoutes<
           }, 500);
         }
       })
+      // @ts-ignore
       .openapi(getRouteDef, async (c: any) => {
         try {
           const { id } = c.req.valid('param');

+ 1 - 1
src/server/utils/generic-crud.service.ts

@@ -198,7 +198,7 @@ export abstract class GenericCrudService<T extends ObjectLiteral> {
   /**
    * 处理关联字段
    */
-  private async handleRelationFields(data: any, entity: T, isUpdate: boolean = false): Promise<void> {
+  private async handleRelationFields(data: any, entity: T, _isUpdate: boolean = false): Promise<void> {
     if (!this.relationFields) return;
 
     for (const [fieldName, config] of Object.entries(this.relationFields)) {

+ 1 - 1
src/server/utils/parseWithAwait.ts

@@ -26,7 +26,7 @@ export async function parseWithAwait<T>(schema: z.ZodSchema<T>, data: unknown):
   }  
     
   async function resolvePromisesByPath(data: any, promiseErrors: any[]): Promise<any> {  
-    const clonedData = JSON.parse(JSON.stringify(data, (key, value) => {  
+    const clonedData = JSON.parse(JSON.stringify(data, (_, value) => {  
       // 保留 Promise 对象,不进行序列化  
       return typeof value?.then === 'function' ? value : value;  
     }));  

+ 1 - 0
src/test/test-utils.ts

@@ -1,5 +1,6 @@
 import { OpenAPIHono } from '@hono/zod-openapi';
 import { Hono } from 'hono';
+import { vi } from 'vitest';
 
 /**
  * 创建测试服务器实例