create-pardx-scaffold 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/.cursor/worktrees.json +37 -0
- package/template/.dockerignore +49 -0
- package/template/.mcp.json +26 -0
- package/template/.nvmrc +1 -0
- package/template/CLAUDE.md +85 -0
- package/template/apps/api/libs/domain/services/index.ts +7 -0
- package/template/apps/api/libs/{infra/shared-services → domain/services}/ip-info/ip-info.module.ts +2 -0
- package/template/apps/api/libs/{infra/shared-services → domain/services}/ip-info/ip-info.service.ts +2 -0
- package/template/apps/api/libs/infra/clients/internal/file-storage/dto/file.dto.ts +1 -1
- package/template/apps/api/libs/infra/shared-services/email/email.module.ts +0 -2
- package/template/apps/api/libs/infra/shared-services/file-storage/bucket-resolver.ts +1 -1
- package/template/apps/api/libs/infra/shared-services/file-storage/file-storage.module.ts +1 -1
- package/template/apps/api/libs/infra/shared-services/sms/sms.module.ts +0 -2
- package/template/apps/api/package.json +15 -15
- package/template/apps/api/prisma/migrations/migration_lock.toml +3 -0
- package/template/apps/api/src/app.module.ts +1 -1
- package/template/apps/web/.env.example +6 -4
- package/template/apps/web/components/error-boundary.tsx +166 -0
- package/template/apps/web/components/index.ts +10 -0
- package/template/apps/web/components.json +20 -0
- package/template/apps/web/config.ts +115 -0
- package/template/apps/web/eslint.config.mjs +4 -0
- package/template/apps/web/lib/api/avatar-upload.ts +1 -0
- package/template/apps/web/lib/api/contracts/client.ts +51 -30
- package/template/apps/web/lib/api/contracts/hooks/index.ts +0 -3
- package/template/apps/web/lib/api/contracts/hooks/notification.ts +42 -124
- package/template/apps/web/lib/api.ts +24 -1
- package/template/apps/web/lib/dynamic-import.tsx +121 -0
- package/template/apps/web/lib/logger.ts +113 -0
- package/template/apps/web/lib/upload/api.ts +37 -105
- package/template/apps/web/lib/upload/batch-uploader.ts +7 -74
- package/template/apps/web/lib/upload/uploader.ts +10 -74
- package/template/apps/web/locales/zh-CN/assessment.json +5 -0
- package/template/apps/web/locales/zh-CN/chat.json +6 -0
- package/template/apps/web/locales/zh-CN/common.json +38 -0
- package/template/apps/web/locales/zh-CN/creative.json +5 -0
- package/template/apps/web/locales/zh-CN/daily-challenge.json +6 -0
- package/template/apps/web/locales/zh-CN/errors.json +16 -0
- package/template/apps/web/locales/zh-CN/forms.json +18 -0
- package/template/apps/web/locales/zh-CN/memory.json +5 -0
- package/template/apps/web/locales/zh-CN/navigation.json +12 -0
- package/template/apps/web/locales/zh-CN/recommendation.json +5 -0
- package/template/apps/web/locales/zh-CN/recruitment.json +5 -0
- package/template/apps/web/locales/zh-CN/settings.json +7 -0
- package/template/apps/web/locales/zh-CN/subscription.json +6 -0
- package/template/apps/web/locales/zh-CN/validation.json +8 -0
- package/template/apps/web/package.json +14 -15
- package/template/apps/web/postcss.config.mjs +1 -0
- package/template/apps/web/proxy.ts +102 -0
- package/template/apps/web/public/logo.svg +21 -0
- package/template/apps/web/vitest.config.ts +69 -0
- package/template/apps/web/vitest.setup.ts +80 -0
- package/template/package.json +7 -7
- package/template/packages/constants/package.json +3 -1
- package/template/packages/constants/tsconfig.build.esm.json +8 -0
- package/template/packages/contracts/package.json +2 -2
- package/template/packages/contracts/src/schemas/uploader.schema.ts +33 -10
- package/template/packages/ui/.storybook/main.ts +28 -0
- package/template/packages/ui/.storybook/preview.ts +40 -0
- package/template/packages/ui/eslint.config.js +3 -0
- package/template/packages/ui/package.json +15 -2
- package/template/packages/ui/src/components/button.stories.tsx +171 -0
- package/template/packages/ui/src/styles/globals.css +1 -1
- package/template/packages/ui/tsconfig.json +1 -1
- package/template/packages/utils/package.json +2 -2
- package/template/packages/utils/tsconfig.build.esm.json +8 -0
- package/template/packages/validators/package.json +1 -1
- package/template/pnpm-lock.yaml +2263 -999
- package/template/scripts/export-scaffold-for-create.js +65 -0
- package/template/apps/api/libs/infra/utils/download.ts +0 -21
- package/template/apps/web/lib/api/client.ts +0 -649
- package/template/apps/web/lib/audio-buffer-queue.ts +0 -273
- package/template/apps/web/lib/upload/folder-utils.ts +0 -295
- /package/template/apps/api/libs/{infra/shared-services → domain/services}/ip-info/index.ts +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"setup-worktree": [
|
|
3
|
+
"npm install",
|
|
4
|
+
"npx prisma generate",
|
|
5
|
+
"npx prisma migrate dev",
|
|
6
|
+
"npx prisma migrate deploy",
|
|
7
|
+
"npx prisma migrate push",
|
|
8
|
+
"npx prisma migrate reset",
|
|
9
|
+
"npx prisma migrate resolve",
|
|
10
|
+
"npx prisma migrate status",
|
|
11
|
+
"npx prisma migrate up",
|
|
12
|
+
"npx prisma migrate down",
|
|
13
|
+
"pnpm dev",
|
|
14
|
+
"pnpm build",
|
|
15
|
+
"pnpm start",
|
|
16
|
+
"pnpm test",
|
|
17
|
+
"pnpm lint",
|
|
18
|
+
"pnpm format",
|
|
19
|
+
"pnpm type-check",
|
|
20
|
+
"pnpm clean",
|
|
21
|
+
"pnpm db:generate",
|
|
22
|
+
"pnpm db:migrate:dev",
|
|
23
|
+
"pnpm db:migrate:deploy",
|
|
24
|
+
"pnpm db:push",
|
|
25
|
+
"pnpm db:format",
|
|
26
|
+
"pnpm db:migrate:reset",
|
|
27
|
+
"pnpm db:migrate:resolve",
|
|
28
|
+
"pnpm db:migrate:status",
|
|
29
|
+
"pnpm db:migrate:up",
|
|
30
|
+
"pnpm db:migrate:down",
|
|
31
|
+
"pnpm db:migrate:latest",
|
|
32
|
+
"pnpm db:migrate:rollback",
|
|
33
|
+
"pnpm db:migrate:status",
|
|
34
|
+
"pnpm db:migrate:up",
|
|
35
|
+
"pnpm db:migrate:down"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# 依赖目录
|
|
2
|
+
node_modules
|
|
3
|
+
**/node_modules
|
|
4
|
+
|
|
5
|
+
# 构建输出
|
|
6
|
+
dist
|
|
7
|
+
**/dist
|
|
8
|
+
.next
|
|
9
|
+
**/.next
|
|
10
|
+
build
|
|
11
|
+
**/build
|
|
12
|
+
|
|
13
|
+
# 日志
|
|
14
|
+
logs
|
|
15
|
+
*.log
|
|
16
|
+
npm-debug.log*
|
|
17
|
+
pnpm-debug.log*
|
|
18
|
+
|
|
19
|
+
# 测试
|
|
20
|
+
coverage
|
|
21
|
+
**/.coverage
|
|
22
|
+
|
|
23
|
+
# 环境变量
|
|
24
|
+
.env
|
|
25
|
+
.env.local
|
|
26
|
+
.env.*.local
|
|
27
|
+
|
|
28
|
+
# IDE
|
|
29
|
+
.vscode
|
|
30
|
+
.idea
|
|
31
|
+
*.swp
|
|
32
|
+
*.swo
|
|
33
|
+
*~
|
|
34
|
+
|
|
35
|
+
# Git
|
|
36
|
+
.git
|
|
37
|
+
.gitignore
|
|
38
|
+
|
|
39
|
+
# 其他
|
|
40
|
+
.DS_Store
|
|
41
|
+
*.pem
|
|
42
|
+
**/.env.production
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"CopilotKit MCP": {
|
|
4
|
+
"command": "npx",
|
|
5
|
+
"args": [
|
|
6
|
+
"mcp-remote",
|
|
7
|
+
"https://mcp.copilotkit.ai"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
"fs": {
|
|
11
|
+
"command": "npx",
|
|
12
|
+
"args": [
|
|
13
|
+
"-y",
|
|
14
|
+
"@modelcontextprotocol/server-filesystem",
|
|
15
|
+
"/Users/techwu/Documents/codes/xica.ai/full.xica.ai"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"next-devtools": {
|
|
19
|
+
"command": "npx",
|
|
20
|
+
"args": [
|
|
21
|
+
"-y",
|
|
22
|
+
"next-devtools-mcp@latest"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
package/template/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
22
|
package/template/CLAUDE.md
CHANGED
|
@@ -133,6 +133,7 @@ pardx-ai/
|
|
|
133
133
|
- **State Management**: React Query (@tanstack/react-query)
|
|
134
134
|
- **Styling**: Tailwind CSS 4 + class-variance-authority
|
|
135
135
|
- **API Client**: ts-rest + React Query
|
|
136
|
+
- **Validation**: Zod 4 (see Zod 4 Usage Guidelines below)
|
|
136
137
|
|
|
137
138
|
**Backend:**
|
|
138
139
|
- **Framework**: NestJS 11 with Fastify
|
|
@@ -141,6 +142,11 @@ pardx-ai/
|
|
|
141
142
|
- **Queue**: RabbitMQ + BullMQ
|
|
142
143
|
- **Auth**: Passport (JWT, OAuth2)
|
|
143
144
|
- **API Contract**: ts-rest
|
|
145
|
+
- **Validation**: Zod 4 (see Zod 4 Usage Guidelines below)
|
|
146
|
+
|
|
147
|
+
**Shared:**
|
|
148
|
+
- **Validation Library**: Zod 4.x (NOT Zod 3.x)
|
|
149
|
+
- **API Contract**: ts-rest 3.53.x (supports Zod 4)
|
|
144
150
|
|
|
145
151
|
### Build Configuration
|
|
146
152
|
|
|
@@ -507,6 +513,85 @@ Code shared between frontend and backend goes in `packages/`:
|
|
|
507
513
|
|
|
508
514
|
Next.js 16 App Router is used. Client components must include `'use client'` directive.
|
|
509
515
|
|
|
516
|
+
## 🔷 Zod 4 Usage Guidelines
|
|
517
|
+
|
|
518
|
+
**IMPORTANT: This project uses Zod 4.x (NOT Zod 3.x). All code MUST follow Zod 4 patterns.**
|
|
519
|
+
|
|
520
|
+
### Import Statement
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
// ✅ Correct: Import from 'zod' (uses Zod 4 classic mode)
|
|
524
|
+
import { z } from 'zod';
|
|
525
|
+
|
|
526
|
+
// ❌ Wrong: Do NOT use zod/v3 compatibility layer
|
|
527
|
+
import { z } from 'zod/v3';
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Key Differences from Zod 3
|
|
531
|
+
|
|
532
|
+
1. **Object Schema Definition**
|
|
533
|
+
```typescript
|
|
534
|
+
// Zod 4 uses $strip instead of strip() for object mode
|
|
535
|
+
const schema = z.object({
|
|
536
|
+
name: z.string(),
|
|
537
|
+
age: z.number(),
|
|
538
|
+
}); // Default is $strip mode
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
2. **Error Handling**
|
|
542
|
+
```typescript
|
|
543
|
+
// Zod 4 error structure
|
|
544
|
+
const result = schema.safeParse(data);
|
|
545
|
+
if (!result.success) {
|
|
546
|
+
// Use result.error.issues for error details
|
|
547
|
+
console.log(result.error.issues);
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
3. **Type Inference**
|
|
552
|
+
```typescript
|
|
553
|
+
// Both work in Zod 4
|
|
554
|
+
type User = z.infer<typeof UserSchema>;
|
|
555
|
+
type User = z.output<typeof UserSchema>;
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### ts-rest Compatibility
|
|
559
|
+
|
|
560
|
+
This project uses **ts-rest 3.53.x** which supports Zod 4. The contract definitions work the same way:
|
|
561
|
+
|
|
562
|
+
```typescript
|
|
563
|
+
import { initContract } from '@ts-rest/core';
|
|
564
|
+
import { z } from 'zod';
|
|
565
|
+
|
|
566
|
+
const c = initContract();
|
|
567
|
+
|
|
568
|
+
export const userContract = c.router({
|
|
569
|
+
getUser: {
|
|
570
|
+
method: 'GET',
|
|
571
|
+
path: '/user/:id',
|
|
572
|
+
pathParams: z.object({
|
|
573
|
+
id: z.string().uuid(),
|
|
574
|
+
}),
|
|
575
|
+
responses: {
|
|
576
|
+
200: z.object({
|
|
577
|
+
id: z.string(),
|
|
578
|
+
name: z.string(),
|
|
579
|
+
}),
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
});
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
### Migration Notes
|
|
586
|
+
|
|
587
|
+
If you encounter code using Zod 3 patterns, update to Zod 4:
|
|
588
|
+
|
|
589
|
+
| Zod 3 | Zod 4 |
|
|
590
|
+
|-------|-------|
|
|
591
|
+
| `z.object({}).strip()` | `z.object({})` (default is strip) |
|
|
592
|
+
| `z.object({}).passthrough()` | `z.looseObject({})` or `z.object({}).passthrough()` |
|
|
593
|
+
| `z.object({}).strict()` | `z.strictObject({})` or `z.object({}).strict()` |
|
|
594
|
+
|
|
510
595
|
## 📋 Code Quality Standards
|
|
511
596
|
|
|
512
597
|
All code MUST follow these quality standards:
|
|
@@ -45,7 +45,7 @@ export const GetObjectOptionsSchema = z.object({
|
|
|
45
45
|
// Presigned Put URL Object Schema
|
|
46
46
|
export const PresignedPutUrlObjectSchema = z.object({
|
|
47
47
|
url: z.string(),
|
|
48
|
-
headers: z.record(z.string()),
|
|
48
|
+
headers: z.record(z.string(), z.string()),
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
// Listed Object Entry Schema
|
|
@@ -9,7 +9,6 @@ import { HttpModule } from '@nestjs/axios';
|
|
|
9
9
|
import { RedisModule } from '@app/redis';
|
|
10
10
|
import { RabbitmqModule } from '@app/rabbitmq';
|
|
11
11
|
import { VerifyModule } from '@app/clients/internal/verify';
|
|
12
|
-
import { SystemTaskQueueModule } from '@app/db';
|
|
13
12
|
import { EmailService } from './email.service';
|
|
14
13
|
|
|
15
14
|
@Module({
|
|
@@ -19,7 +18,6 @@ import { EmailService } from './email.service';
|
|
|
19
18
|
RedisModule,
|
|
20
19
|
RabbitmqModule,
|
|
21
20
|
VerifyModule,
|
|
22
|
-
SystemTaskQueueModule,
|
|
23
21
|
],
|
|
24
22
|
providers: [EmailService],
|
|
25
23
|
exports: [EmailService],
|
|
@@ -16,7 +16,7 @@ import { Logger } from 'winston';
|
|
|
16
16
|
import { FileBucketVendor } from '@prisma/client';
|
|
17
17
|
|
|
18
18
|
import { PardxUploader } from '@app/clients/internal/file-storage';
|
|
19
|
-
import { IpInfoService } from '@app/
|
|
19
|
+
import { IpInfoService } from '@app/services/ip-info';
|
|
20
20
|
import { AppConfig } from '@/config/validation';
|
|
21
21
|
import arrayUtil from '@/utils/array.util';
|
|
22
22
|
import enviromentUtil from '@/utils/enviroment.util';
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { Module } from '@nestjs/common';
|
|
13
13
|
import { ConfigModule } from '@nestjs/config';
|
|
14
14
|
import { HttpModule } from '@nestjs/axios';
|
|
15
|
-
import { IpInfoServiceModule } from '@app/
|
|
15
|
+
import { IpInfoServiceModule } from '@app/services/ip-info';
|
|
16
16
|
import { RedisModule } from '@app/redis';
|
|
17
17
|
import { FileStorageService } from './file-storage.service';
|
|
18
18
|
import { FileStorageClientFactory } from './file-storage.factory';
|
|
@@ -9,7 +9,6 @@ import { HttpModule } from '@nestjs/axios';
|
|
|
9
9
|
import { RedisModule } from '@app/redis';
|
|
10
10
|
import { RabbitmqModule } from '@app/rabbitmq';
|
|
11
11
|
import { VerifyModule } from '@app/clients/internal/verify';
|
|
12
|
-
import { SystemTaskQueueModule } from '@app/db';
|
|
13
12
|
import { SmsService } from './sms.service';
|
|
14
13
|
|
|
15
14
|
@Module({
|
|
@@ -19,7 +18,6 @@ import { SmsService } from './sms.service';
|
|
|
19
18
|
RedisModule,
|
|
20
19
|
RabbitmqModule,
|
|
21
20
|
VerifyModule,
|
|
22
|
-
SystemTaskQueueModule,
|
|
23
21
|
],
|
|
24
22
|
providers: [SmsService],
|
|
25
23
|
exports: [SmsService],
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"glob": "^11.0.1",
|
|
62
62
|
"jest": "^29.7.0",
|
|
63
63
|
"prettier": "^3.3.3",
|
|
64
|
-
"prisma": "7.
|
|
64
|
+
"prisma": "7.3.0",
|
|
65
65
|
"rimraf": "^6.0.1",
|
|
66
66
|
"source-map-support": "^0.5.21",
|
|
67
67
|
"supertest": "^7.1.1",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"ts-node": "^10.9.2",
|
|
71
71
|
"tsconfig-paths": "^4.2.0",
|
|
72
72
|
"tsconfig-paths-webpack-plugin": "^4.2.0",
|
|
73
|
-
"turbo": "^2.
|
|
73
|
+
"turbo": "^2.8.0",
|
|
74
74
|
"typescript": "^5.4.5",
|
|
75
75
|
"webpack": "^5.98.0",
|
|
76
76
|
"webpack-cli": "^6.0.1",
|
|
@@ -82,8 +82,8 @@
|
|
|
82
82
|
"@alicloud/nls-filetrans-2018-08-17": "^1.0.0",
|
|
83
83
|
"@alicloud/openapi-client": "^0.4.15",
|
|
84
84
|
"@alicloud/pop-core": "^1.8.0",
|
|
85
|
-
"@aws-sdk/client-s3": "^3.
|
|
86
|
-
"@aws-sdk/s3-request-presigner": "^3.
|
|
85
|
+
"@aws-sdk/client-s3": "^3.978.0",
|
|
86
|
+
"@aws-sdk/s3-request-presigner": "^3.978.0",
|
|
87
87
|
"@fastify/compress": "^8.0.1",
|
|
88
88
|
"@fastify/cookie": "^11.0.2",
|
|
89
89
|
"@fastify/helmet": "^13.0.1",
|
|
@@ -107,15 +107,15 @@
|
|
|
107
107
|
"@nestjs/schedule": "^6.1.0",
|
|
108
108
|
"@nestjs/swagger": "^11.2.3",
|
|
109
109
|
"@nestjs/websockets": "^11.1.10",
|
|
110
|
-
"@prisma/adapter-pg": "^7.
|
|
111
|
-
"@prisma/client": "7.
|
|
112
|
-
"@prisma/extension-accelerate": "^
|
|
110
|
+
"@prisma/adapter-pg": "^7.3.0",
|
|
111
|
+
"@prisma/client": "7.3.0",
|
|
112
|
+
"@prisma/extension-accelerate": "^3.0.1",
|
|
113
113
|
"@repo/constants": "workspace:*",
|
|
114
114
|
"@repo/contracts": "workspace:*",
|
|
115
115
|
"@repo/utils": "workspace:*",
|
|
116
116
|
"@repo/validators": "workspace:*",
|
|
117
|
-
"@ts-rest/core": "^3.
|
|
118
|
-
"@ts-rest/nest": "^3.
|
|
117
|
+
"@ts-rest/core": "^3.53.0-rc.1",
|
|
118
|
+
"@ts-rest/nest": "^3.53.0-rc.1",
|
|
119
119
|
"@volcengine/openapi": "^1.32.0",
|
|
120
120
|
"@volcengine/tos-sdk": "^2.7.6",
|
|
121
121
|
"@willsoto/nestjs-prometheus": "^6.0.2",
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
"axios": "^1.7.2",
|
|
127
127
|
"bcrypt": "^6.0.0",
|
|
128
128
|
"bull": "^4.16.5",
|
|
129
|
-
"bullmq": "^5.
|
|
129
|
+
"bullmq": "^5.67.2",
|
|
130
130
|
"class-transformer": "^0.5.1",
|
|
131
131
|
"class-validator": "^0.14.1",
|
|
132
132
|
"cls-hooked": "^4.2.2",
|
|
@@ -134,8 +134,8 @@
|
|
|
134
134
|
"dotenv-expand": "^12.0.3",
|
|
135
135
|
"fastify": "^5.2.0",
|
|
136
136
|
"fastify-sse-v2": "^4.2.1",
|
|
137
|
-
"google-auth-library": "^
|
|
138
|
-
"ioredis": "5.
|
|
137
|
+
"google-auth-library": "^10.5.0",
|
|
138
|
+
"ioredis": "5.9.2",
|
|
139
139
|
"js-yaml": "^4.1.0",
|
|
140
140
|
"lodash": "^4.17.21",
|
|
141
141
|
"moment-timezone": "^0.6.0",
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"nestjs-i18n": "^10.4.5",
|
|
148
148
|
"nodemailer": "^7.0.3",
|
|
149
149
|
"nodemailer-sendcloud-transport": "^0.0.2",
|
|
150
|
-
"openai": "^6.
|
|
150
|
+
"openai": "^6.17.0",
|
|
151
151
|
"passport": "^0.7.0",
|
|
152
152
|
"passport-google-oauth20": "^2.0.0",
|
|
153
153
|
"passport-jwt": "^4.0.1",
|
|
@@ -164,11 +164,11 @@
|
|
|
164
164
|
"socket.io": "^4.8.1",
|
|
165
165
|
"tencentcloud-sdk-nodejs-sms": "^4.0.859",
|
|
166
166
|
"uniqid": "^5.4.0",
|
|
167
|
-
"unleash-client": "^6.9.
|
|
167
|
+
"unleash-client": "^6.9.5",
|
|
168
168
|
"uuid": "^11.1.0",
|
|
169
169
|
"winston": "^3.13.0",
|
|
170
170
|
"winston-daily-rotate-file": "^5.0.0",
|
|
171
171
|
"ws": "^8.18.3",
|
|
172
|
-
"zod": "^3.
|
|
172
|
+
"zod": "^4.3.6"
|
|
173
173
|
}
|
|
174
174
|
}
|
|
@@ -32,7 +32,7 @@ import type { AppConfig, ZoneConfig } from '@/config/validation';
|
|
|
32
32
|
|
|
33
33
|
/** request middleware */
|
|
34
34
|
import RequestMiddleware from '@/common/middleware/request.middleware';
|
|
35
|
-
import { IpInfoServiceModule } from '@app/
|
|
35
|
+
import { IpInfoServiceModule } from '@app/services/ip-info';
|
|
36
36
|
import { ScheduleModule } from '@nestjs/schedule';
|
|
37
37
|
import { RedisModule } from '@app/redis';
|
|
38
38
|
import { CacheDecoratorModule } from '@/common/decorators/cache/cache.module';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
# API
|
|
2
|
-
NEXT_PUBLIC_API_BASE_URL=http://localhost:
|
|
1
|
+
# API 配置
|
|
2
|
+
NEXT_PUBLIC_API_BASE_URL=http://localhost:13100/api
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
NEXT_PUBLIC_BRAND_NAME='Pardx.ai'
|
|
5
|
+
NEXT_PUBLIC_BRAND_LOGO='/logo.svg'
|
|
6
|
+
NEXT_PUBLIC_BRAND_TITLE=PardxAI - Multi-Agent Content Creation & Knowledge Management Platform
|
|
7
|
+
NEXT_PUBLIC_BRAND_DESCRIPTION=PardxAI is an AI-powered multi-agent platform for content creation, knowledge management, and intelligent operations. Features include AI writing, evolutionary knowledge base, smart recommendations, AI recruitment agents, and meeting intelligence.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Component, type ReactNode, type ErrorInfo } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Error Boundary Props
|
|
7
|
+
*/
|
|
8
|
+
interface ErrorBoundaryProps {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
/** 自定义错误回退 UI */
|
|
11
|
+
fallback?: ReactNode;
|
|
12
|
+
/** 错误回调函数 */
|
|
13
|
+
onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
14
|
+
/** 是否显示重试按钮 */
|
|
15
|
+
showRetry?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Error Boundary State
|
|
20
|
+
*/
|
|
21
|
+
interface ErrorBoundaryState {
|
|
22
|
+
hasError: boolean;
|
|
23
|
+
error?: Error;
|
|
24
|
+
errorInfo?: ErrorInfo;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 默认错误回退 UI
|
|
29
|
+
*/
|
|
30
|
+
function DefaultErrorFallback({
|
|
31
|
+
error,
|
|
32
|
+
onRetry,
|
|
33
|
+
showRetry = true,
|
|
34
|
+
}: {
|
|
35
|
+
error?: Error;
|
|
36
|
+
onRetry?: () => void;
|
|
37
|
+
showRetry?: boolean;
|
|
38
|
+
}) {
|
|
39
|
+
return (
|
|
40
|
+
<div className="flex min-h-[200px] flex-col items-center justify-center p-8 text-center">
|
|
41
|
+
<div className="mb-4 text-6xl">😵</div>
|
|
42
|
+
<h2 className="mb-2 text-xl font-semibold text-gray-900 dark:text-gray-100">
|
|
43
|
+
出错了
|
|
44
|
+
</h2>
|
|
45
|
+
<p className="mb-4 text-gray-600 dark:text-gray-400">
|
|
46
|
+
{error?.message || '页面发生了意外错误'}
|
|
47
|
+
</p>
|
|
48
|
+
{showRetry && onRetry && (
|
|
49
|
+
<button
|
|
50
|
+
onClick={onRetry}
|
|
51
|
+
className="rounded-md bg-blue-600 px-4 py-2 text-white transition-colors hover:bg-blue-700"
|
|
52
|
+
>
|
|
53
|
+
重试
|
|
54
|
+
</button>
|
|
55
|
+
)}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* React Error Boundary 组件
|
|
62
|
+
*
|
|
63
|
+
* 用于捕获子组件树中的 JavaScript 错误,记录错误并显示回退 UI
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```tsx
|
|
67
|
+
* <ErrorBoundary fallback={<CustomError />}>
|
|
68
|
+
* <MyComponent />
|
|
69
|
+
* </ErrorBoundary>
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export class ErrorBoundary extends Component<
|
|
73
|
+
ErrorBoundaryProps,
|
|
74
|
+
ErrorBoundaryState
|
|
75
|
+
> {
|
|
76
|
+
constructor(props: ErrorBoundaryProps) {
|
|
77
|
+
super(props);
|
|
78
|
+
this.state = { hasError: false };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
|
82
|
+
return { hasError: true, error };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
|
86
|
+
// 记录错误信息
|
|
87
|
+
console.error('ErrorBoundary caught an error:', error, errorInfo);
|
|
88
|
+
|
|
89
|
+
// 更新状态以包含错误信息
|
|
90
|
+
this.setState({ errorInfo });
|
|
91
|
+
|
|
92
|
+
// 调用错误回调
|
|
93
|
+
this.props.onError?.(error, errorInfo);
|
|
94
|
+
|
|
95
|
+
// 在生产环境中,可以发送到错误追踪服务
|
|
96
|
+
if (process.env.NODE_ENV === 'production') {
|
|
97
|
+
// TODO: 发送到错误追踪服务 (如 Sentry)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
handleRetry = () => {
|
|
102
|
+
this.setState({ hasError: false, error: undefined, errorInfo: undefined });
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
render() {
|
|
106
|
+
if (this.state.hasError) {
|
|
107
|
+
// 如果提供了自定义 fallback,使用它
|
|
108
|
+
if (this.props.fallback) {
|
|
109
|
+
return this.props.fallback;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 否则使用默认错误 UI
|
|
113
|
+
return (
|
|
114
|
+
<DefaultErrorFallback
|
|
115
|
+
error={this.state.error}
|
|
116
|
+
onRetry={this.handleRetry}
|
|
117
|
+
showRetry={this.props.showRetry}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return this.props.children;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 页面级 Error Boundary
|
|
128
|
+
* 用于包裹整个页面,提供更友好的错误提示
|
|
129
|
+
*/
|
|
130
|
+
export function PageErrorBoundary({ children }: { children: ReactNode }) {
|
|
131
|
+
return (
|
|
132
|
+
<ErrorBoundary
|
|
133
|
+
showRetry
|
|
134
|
+
onError={(error, errorInfo) => {
|
|
135
|
+
// 页面级错误可以记录更多上下文
|
|
136
|
+
console.error('Page error:', {
|
|
137
|
+
error: error.message,
|
|
138
|
+
stack: error.stack,
|
|
139
|
+
componentStack: errorInfo.componentStack,
|
|
140
|
+
});
|
|
141
|
+
}}
|
|
142
|
+
>
|
|
143
|
+
{children}
|
|
144
|
+
</ErrorBoundary>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 组件级 Error Boundary
|
|
150
|
+
* 用于包裹单个组件,错误不会影响其他组件
|
|
151
|
+
*/
|
|
152
|
+
export function ComponentErrorBoundary({
|
|
153
|
+
children,
|
|
154
|
+
fallback,
|
|
155
|
+
}: {
|
|
156
|
+
children: ReactNode;
|
|
157
|
+
fallback?: ReactNode;
|
|
158
|
+
}) {
|
|
159
|
+
return (
|
|
160
|
+
<ErrorBoundary fallback={fallback} showRetry={false}>
|
|
161
|
+
{children}
|
|
162
|
+
</ErrorBoundary>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export default ErrorBoundary;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "new-york",
|
|
4
|
+
"rsc": true,
|
|
5
|
+
"tsx": true,
|
|
6
|
+
"tailwind": {
|
|
7
|
+
"config": "",
|
|
8
|
+
"css": "../../packages/ui/src/styles/globals.css",
|
|
9
|
+
"baseColor": "neutral",
|
|
10
|
+
"cssVariables": true
|
|
11
|
+
},
|
|
12
|
+
"iconLibrary": "lucide",
|
|
13
|
+
"aliases": {
|
|
14
|
+
"components": "@/components",
|
|
15
|
+
"hooks": "@/hooks",
|
|
16
|
+
"lib": "@/lib",
|
|
17
|
+
"utils": "@repo/ui/lib/utils",
|
|
18
|
+
"ui": "@repo/ui/components"
|
|
19
|
+
}
|
|
20
|
+
}
|