ccjk 1.3.1
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/LICENSE +21 -0
- package/README.ja.md +455 -0
- package/README.ko.md +455 -0
- package/README.md +550 -0
- package/README.zh-CN.md +488 -0
- package/bin/ccjk.mjs +2 -0
- package/dist/chunks/api-providers.mjs +89 -0
- package/dist/chunks/claude-code-config-manager.mjs +733 -0
- package/dist/chunks/claude-code-incremental-manager.mjs +603 -0
- package/dist/chunks/codex-config-switch.mjs +427 -0
- package/dist/chunks/codex-provider-manager.mjs +232 -0
- package/dist/chunks/codex-uninstaller.mjs +404 -0
- package/dist/chunks/commands.mjs +120 -0
- package/dist/chunks/features.mjs +642 -0
- package/dist/chunks/simple-config.mjs +10445 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +5972 -0
- package/dist/i18n/locales/en/api.json +63 -0
- package/dist/i18n/locales/en/ccjk.json +276 -0
- package/dist/i18n/locales/en/ccr.json +65 -0
- package/dist/i18n/locales/en/cli.json +57 -0
- package/dist/i18n/locales/en/codex.json +124 -0
- package/dist/i18n/locales/en/cometix.json +29 -0
- package/dist/i18n/locales/en/common.json +20 -0
- package/dist/i18n/locales/en/configuration.json +77 -0
- package/dist/i18n/locales/en/errors.json +26 -0
- package/dist/i18n/locales/en/installation.json +80 -0
- package/dist/i18n/locales/en/interview.json +104 -0
- package/dist/i18n/locales/en/language.json +19 -0
- package/dist/i18n/locales/en/mcp.json +38 -0
- package/dist/i18n/locales/en/menu.json +51 -0
- package/dist/i18n/locales/en/multi-config.json +79 -0
- package/dist/i18n/locales/en/shencha.json +14 -0
- package/dist/i18n/locales/en/team.json +7 -0
- package/dist/i18n/locales/en/tools.json +42 -0
- package/dist/i18n/locales/en/uninstall.json +56 -0
- package/dist/i18n/locales/en/updater.json +25 -0
- package/dist/i18n/locales/en/workflow.json +25 -0
- package/dist/i18n/locales/zh-CN/api.json +63 -0
- package/dist/i18n/locales/zh-CN/ccjk.json +276 -0
- package/dist/i18n/locales/zh-CN/ccr.json +65 -0
- package/dist/i18n/locales/zh-CN/cli.json +57 -0
- package/dist/i18n/locales/zh-CN/codex.json +124 -0
- package/dist/i18n/locales/zh-CN/cometix.json +29 -0
- package/dist/i18n/locales/zh-CN/common.json +20 -0
- package/dist/i18n/locales/zh-CN/configuration.json +77 -0
- package/dist/i18n/locales/zh-CN/errors.json +26 -0
- package/dist/i18n/locales/zh-CN/installation.json +80 -0
- package/dist/i18n/locales/zh-CN/interview.json +104 -0
- package/dist/i18n/locales/zh-CN/language.json +19 -0
- package/dist/i18n/locales/zh-CN/mcp.json +38 -0
- package/dist/i18n/locales/zh-CN/menu.json +51 -0
- package/dist/i18n/locales/zh-CN/multi-config.json +79 -0
- package/dist/i18n/locales/zh-CN/shencha.json +14 -0
- package/dist/i18n/locales/zh-CN/team.json +7 -0
- package/dist/i18n/locales/zh-CN/tools.json +42 -0
- package/dist/i18n/locales/zh-CN/uninstall.json +56 -0
- package/dist/i18n/locales/zh-CN/updater.json +25 -0
- package/dist/i18n/locales/zh-CN/workflow.json +25 -0
- package/dist/index.d.mts +2644 -0
- package/dist/index.d.ts +2644 -0
- package/dist/index.mjs +1706 -0
- package/package.json +157 -0
- package/templates/CLAUDE.md +219 -0
- package/templates/claude-code/CLAUDE.md +250 -0
- package/templates/claude-code/common/settings.json +38 -0
- package/templates/claude-code/en/workflow/bmad/commands/bmad-init.md +165 -0
- package/templates/claude-code/en/workflow/common/agents/get-current-datetime.md +29 -0
- package/templates/claude-code/en/workflow/common/agents/init-architect.md +114 -0
- package/templates/claude-code/en/workflow/common/commands/init-project.md +53 -0
- package/templates/claude-code/en/workflow/plan/agents/planner.md +116 -0
- package/templates/claude-code/en/workflow/plan/agents/ui-ux-designer.md +91 -0
- package/templates/claude-code/en/workflow/plan/commands/feat.md +105 -0
- package/templates/claude-code/zh-CN/workflow/bmad/commands/bmad-init.md +172 -0
- package/templates/claude-code/zh-CN/workflow/common/agents/get-current-datetime.md +29 -0
- package/templates/claude-code/zh-CN/workflow/common/agents/init-architect.md +114 -0
- package/templates/claude-code/zh-CN/workflow/common/commands/init-project.md +53 -0
- package/templates/claude-code/zh-CN/workflow/plan/agents/planner.md +116 -0
- package/templates/claude-code/zh-CN/workflow/plan/agents/ui-ux-designer.md +91 -0
- package/templates/claude-code/zh-CN/workflow/plan/commands/feat.md +105 -0
- package/templates/codex/common/config.toml +0 -0
- package/templates/common/output-styles/en/casual-friendly.md +97 -0
- package/templates/common/output-styles/en/engineer-professional.md +88 -0
- package/templates/common/output-styles/en/expert-concise.md +93 -0
- package/templates/common/output-styles/en/laowang-engineer.md +127 -0
- package/templates/common/output-styles/en/nekomata-engineer.md +120 -0
- package/templates/common/output-styles/en/ojousama-engineer.md +121 -0
- package/templates/common/output-styles/en/teaching-mode.md +102 -0
- package/templates/common/output-styles/en/technical-precise.md +101 -0
- package/templates/common/output-styles/zh-CN/engineer-professional.md +89 -0
- package/templates/common/output-styles/zh-CN/laowang-engineer.md +127 -0
- package/templates/common/output-styles/zh-CN/nekomata-engineer.md +120 -0
- package/templates/common/output-styles/zh-CN/ojousama-engineer.md +121 -0
- package/templates/common/workflow/git/en/git-cleanBranches.md +102 -0
- package/templates/common/workflow/git/en/git-commit.md +205 -0
- package/templates/common/workflow/git/en/git-rollback.md +90 -0
- package/templates/common/workflow/git/en/git-worktree.md +276 -0
- package/templates/common/workflow/git/zh-CN/git-cleanBranches.md +102 -0
- package/templates/common/workflow/git/zh-CN/git-commit.md +205 -0
- package/templates/common/workflow/git/zh-CN/git-rollback.md +90 -0
- package/templates/common/workflow/git/zh-CN/git-worktree.md +276 -0
- package/templates/common/workflow/interview/en/interview.md +212 -0
- package/templates/common/workflow/interview/zh-CN/interview.md +212 -0
- package/templates/common/workflow/sixStep/en/workflow.md +251 -0
- package/templates/common/workflow/sixStep/zh-CN/workflow.md +215 -0
- package/templates/industry/devops/en/ci-cd-pipeline.md +410 -0
- package/templates/industry/web-dev/en/api-design.md +299 -0
- package/templates/industry/web-dev/en/react-nextjs-setup.md +236 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
# API Design Best Practices Template
|
|
2
|
+
|
|
3
|
+
## RESTful API Design
|
|
4
|
+
|
|
5
|
+
### Resource Naming Conventions
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
✅ Good:
|
|
9
|
+
GET /users # List users
|
|
10
|
+
GET /users/{id} # Get specific user
|
|
11
|
+
POST /users # Create user
|
|
12
|
+
PUT /users/{id} # Replace user
|
|
13
|
+
PATCH /users/{id} # Update user
|
|
14
|
+
DELETE /users/{id} # Delete user
|
|
15
|
+
|
|
16
|
+
GET /users/{id}/orders # User's orders
|
|
17
|
+
GET /orders/{id}/items # Order's items
|
|
18
|
+
|
|
19
|
+
❌ Bad:
|
|
20
|
+
GET /getUsers
|
|
21
|
+
GET /user/fetch/{id}
|
|
22
|
+
POST /createUser
|
|
23
|
+
GET /users/{id}/getOrders
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Query Parameters
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
# Pagination
|
|
30
|
+
GET /users?page=2&limit=20
|
|
31
|
+
|
|
32
|
+
# Filtering
|
|
33
|
+
GET /users?status=active&role=admin
|
|
34
|
+
|
|
35
|
+
# Sorting
|
|
36
|
+
GET /users?sort=created_at:desc,name:asc
|
|
37
|
+
|
|
38
|
+
# Field selection
|
|
39
|
+
GET /users?fields=id,name,email
|
|
40
|
+
|
|
41
|
+
# Search
|
|
42
|
+
GET /users?search=john
|
|
43
|
+
|
|
44
|
+
# Combined
|
|
45
|
+
GET /users?status=active&sort=name:asc&page=1&limit=10
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Response Format
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// Success Response
|
|
52
|
+
interface SuccessResponse<T> {
|
|
53
|
+
success: true
|
|
54
|
+
data: T
|
|
55
|
+
meta?: {
|
|
56
|
+
pagination?: {
|
|
57
|
+
page: number
|
|
58
|
+
limit: number
|
|
59
|
+
total: number
|
|
60
|
+
totalPages: number
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Error Response
|
|
66
|
+
interface ErrorResponse {
|
|
67
|
+
success: false
|
|
68
|
+
error: {
|
|
69
|
+
code: string // Machine-readable code
|
|
70
|
+
message: string // Human-readable message
|
|
71
|
+
details?: Array<{
|
|
72
|
+
field?: string
|
|
73
|
+
message: string
|
|
74
|
+
}>
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Example Responses
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
// GET /users - Success
|
|
83
|
+
{
|
|
84
|
+
"success": true,
|
|
85
|
+
"data": [
|
|
86
|
+
{ "id": "1", "name": "John", "email": "john@example.com" }
|
|
87
|
+
],
|
|
88
|
+
"meta": {
|
|
89
|
+
"pagination": {
|
|
90
|
+
"page": 1,
|
|
91
|
+
"limit": 20,
|
|
92
|
+
"total": 150,
|
|
93
|
+
"totalPages": 8
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// POST /users - Validation Error
|
|
99
|
+
{
|
|
100
|
+
"success": false,
|
|
101
|
+
"error": {
|
|
102
|
+
"code": "VALIDATION_ERROR",
|
|
103
|
+
"message": "Invalid input data",
|
|
104
|
+
"details": [
|
|
105
|
+
{ "field": "email", "message": "Invalid email format" },
|
|
106
|
+
{ "field": "password", "message": "Must be at least 8 characters" }
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## HTTP Status Codes
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
2xx Success:
|
|
116
|
+
200 OK - GET, PUT, PATCH success
|
|
117
|
+
201 Created - POST success
|
|
118
|
+
204 No Content - DELETE success
|
|
119
|
+
|
|
120
|
+
4xx Client Error:
|
|
121
|
+
400 Bad Request - Invalid syntax
|
|
122
|
+
401 Unauthorized - No/invalid authentication
|
|
123
|
+
403 Forbidden - Authenticated but not authorized
|
|
124
|
+
404 Not Found - Resource doesn't exist
|
|
125
|
+
409 Conflict - Resource conflict (duplicate)
|
|
126
|
+
422 Unprocessable - Validation error
|
|
127
|
+
429 Too Many - Rate limit exceeded
|
|
128
|
+
|
|
129
|
+
5xx Server Error:
|
|
130
|
+
500 Internal Error - Server failure
|
|
131
|
+
502 Bad Gateway - Upstream failure
|
|
132
|
+
503 Unavailable - Service overloaded
|
|
133
|
+
504 Gateway Timeout - Upstream timeout
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Authentication
|
|
137
|
+
|
|
138
|
+
### JWT Token Structure
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
// Access Token (short-lived: 15min)
|
|
142
|
+
interface AccessToken {
|
|
143
|
+
sub: string // User ID
|
|
144
|
+
email: string
|
|
145
|
+
role: string
|
|
146
|
+
iat: number // Issued at
|
|
147
|
+
exp: number // Expiration
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Refresh Token (long-lived: 7 days)
|
|
151
|
+
interface RefreshToken {
|
|
152
|
+
sub: string
|
|
153
|
+
jti: string // Token ID (for revocation)
|
|
154
|
+
iat: number
|
|
155
|
+
exp: number
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Auth Flow
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
1. Login
|
|
163
|
+
POST /auth/login
|
|
164
|
+
{ "email": "...", "password": "..." }
|
|
165
|
+
→ { "accessToken": "...", "refreshToken": "..." }
|
|
166
|
+
|
|
167
|
+
2. Access Protected Resource
|
|
168
|
+
GET /users
|
|
169
|
+
Authorization: Bearer <accessToken>
|
|
170
|
+
|
|
171
|
+
3. Refresh Token
|
|
172
|
+
POST /auth/refresh
|
|
173
|
+
{ "refreshToken": "..." }
|
|
174
|
+
→ { "accessToken": "...", "refreshToken": "..." }
|
|
175
|
+
|
|
176
|
+
4. Logout
|
|
177
|
+
POST /auth/logout
|
|
178
|
+
{ "refreshToken": "..." }
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Rate Limiting
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// Response Headers
|
|
185
|
+
{
|
|
186
|
+
'X-RateLimit-Limit': '100', // Max requests per window
|
|
187
|
+
'X-RateLimit-Remaining': '95', // Remaining requests
|
|
188
|
+
'X-RateLimit-Reset': '1640000000', // Window reset timestamp
|
|
189
|
+
'Retry-After': '60' // Seconds until retry (on 429)
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Versioning
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
# URL Path (Recommended)
|
|
197
|
+
/api/v1/users
|
|
198
|
+
/api/v2/users
|
|
199
|
+
|
|
200
|
+
# Header
|
|
201
|
+
Accept: application/vnd.api+json;version=1
|
|
202
|
+
|
|
203
|
+
# Query Parameter
|
|
204
|
+
/api/users?version=1
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## OpenAPI Specification
|
|
208
|
+
|
|
209
|
+
```yaml
|
|
210
|
+
openapi: 3.0.3
|
|
211
|
+
info:
|
|
212
|
+
title: My API
|
|
213
|
+
version: 1.0.0
|
|
214
|
+
description: API for managing resources
|
|
215
|
+
|
|
216
|
+
servers:
|
|
217
|
+
- url: https://api.example.com/v1
|
|
218
|
+
|
|
219
|
+
paths:
|
|
220
|
+
/users:
|
|
221
|
+
get:
|
|
222
|
+
summary: List users
|
|
223
|
+
tags: [Users]
|
|
224
|
+
parameters:
|
|
225
|
+
- name: page
|
|
226
|
+
in: query
|
|
227
|
+
schema:
|
|
228
|
+
type: integer
|
|
229
|
+
default: 1
|
|
230
|
+
- name: limit
|
|
231
|
+
in: query
|
|
232
|
+
schema:
|
|
233
|
+
type: integer
|
|
234
|
+
default: 20
|
|
235
|
+
maximum: 100
|
|
236
|
+
responses:
|
|
237
|
+
'200':
|
|
238
|
+
description: Success
|
|
239
|
+
content:
|
|
240
|
+
application/json:
|
|
241
|
+
schema:
|
|
242
|
+
$ref: '#/components/schemas/UserList'
|
|
243
|
+
|
|
244
|
+
post:
|
|
245
|
+
summary: Create user
|
|
246
|
+
tags: [Users]
|
|
247
|
+
requestBody:
|
|
248
|
+
required: true
|
|
249
|
+
content:
|
|
250
|
+
application/json:
|
|
251
|
+
schema:
|
|
252
|
+
$ref: '#/components/schemas/CreateUser'
|
|
253
|
+
responses:
|
|
254
|
+
'201':
|
|
255
|
+
description: Created
|
|
256
|
+
'422':
|
|
257
|
+
description: Validation error
|
|
258
|
+
|
|
259
|
+
components:
|
|
260
|
+
schemas:
|
|
261
|
+
User:
|
|
262
|
+
type: object
|
|
263
|
+
properties:
|
|
264
|
+
id:
|
|
265
|
+
type: string
|
|
266
|
+
name:
|
|
267
|
+
type: string
|
|
268
|
+
email:
|
|
269
|
+
type: string
|
|
270
|
+
format: email
|
|
271
|
+
required: [id, name, email]
|
|
272
|
+
|
|
273
|
+
CreateUser:
|
|
274
|
+
type: object
|
|
275
|
+
properties:
|
|
276
|
+
name:
|
|
277
|
+
type: string
|
|
278
|
+
minLength: 1
|
|
279
|
+
email:
|
|
280
|
+
type: string
|
|
281
|
+
format: email
|
|
282
|
+
password:
|
|
283
|
+
type: string
|
|
284
|
+
minLength: 8
|
|
285
|
+
required: [name, email, password]
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Best Practices Checklist
|
|
289
|
+
|
|
290
|
+
- [ ] Use nouns for resources, not verbs
|
|
291
|
+
- [ ] Use plural nouns (/users not /user)
|
|
292
|
+
- [ ] Use proper HTTP methods
|
|
293
|
+
- [ ] Return appropriate status codes
|
|
294
|
+
- [ ] Implement pagination for lists
|
|
295
|
+
- [ ] Support filtering and sorting
|
|
296
|
+
- [ ] Use consistent error format
|
|
297
|
+
- [ ] Implement rate limiting
|
|
298
|
+
- [ ] Version your API
|
|
299
|
+
- [ ] Document with OpenAPI
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# React/Next.js Project Setup Template
|
|
2
|
+
|
|
3
|
+
## Project Initialization
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# Create Next.js project with TypeScript
|
|
7
|
+
npx create-next-app@latest my-app --typescript --tailwind --eslint --app --src-dir
|
|
8
|
+
|
|
9
|
+
cd my-app
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Recommended Project Structure
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
src/
|
|
16
|
+
├── app/ # Next.js App Router
|
|
17
|
+
│ ├── (auth)/ # Route group for auth pages
|
|
18
|
+
│ │ ├── login/
|
|
19
|
+
│ │ └── register/
|
|
20
|
+
│ ├── (dashboard)/ # Route group for dashboard
|
|
21
|
+
│ │ └── dashboard/
|
|
22
|
+
│ ├── api/ # API routes
|
|
23
|
+
│ ├── layout.tsx # Root layout
|
|
24
|
+
│ └── page.tsx # Home page
|
|
25
|
+
├── components/
|
|
26
|
+
│ ├── ui/ # Reusable UI components
|
|
27
|
+
│ │ ├── Button/
|
|
28
|
+
│ │ ├── Input/
|
|
29
|
+
│ │ └── Modal/
|
|
30
|
+
│ ├── features/ # Feature-specific components
|
|
31
|
+
│ │ ├── auth/
|
|
32
|
+
│ │ └── dashboard/
|
|
33
|
+
│ └── layouts/ # Layout components
|
|
34
|
+
├── hooks/ # Custom React hooks
|
|
35
|
+
├── lib/ # Utilities and configs
|
|
36
|
+
│ ├── api.ts # API client
|
|
37
|
+
│ ├── auth.ts # Auth utilities
|
|
38
|
+
│ └── utils.ts # General utilities
|
|
39
|
+
├── stores/ # State management
|
|
40
|
+
├── types/ # TypeScript types
|
|
41
|
+
└── styles/ # Global styles
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Essential Dependencies
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# UI & Styling
|
|
48
|
+
pnpm add @radix-ui/react-dialog @radix-ui/react-dropdown-menu
|
|
49
|
+
pnpm add class-variance-authority clsx tailwind-merge
|
|
50
|
+
pnpm add lucide-react
|
|
51
|
+
|
|
52
|
+
# State & Data
|
|
53
|
+
pnpm add @tanstack/react-query zustand
|
|
54
|
+
pnpm add zod react-hook-form @hookform/resolvers
|
|
55
|
+
|
|
56
|
+
# Dev Dependencies
|
|
57
|
+
pnpm add -D @types/node prettier prettier-plugin-tailwindcss
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Configuration Files
|
|
61
|
+
|
|
62
|
+
### tailwind.config.ts
|
|
63
|
+
```typescript
|
|
64
|
+
import type { Config } from 'tailwindcss'
|
|
65
|
+
|
|
66
|
+
const config: Config = {
|
|
67
|
+
darkMode: ['class'],
|
|
68
|
+
content: ['./src/**/*.{ts,tsx}'],
|
|
69
|
+
theme: {
|
|
70
|
+
extend: {
|
|
71
|
+
colors: {
|
|
72
|
+
border: 'hsl(var(--border))',
|
|
73
|
+
background: 'hsl(var(--background))',
|
|
74
|
+
foreground: 'hsl(var(--foreground))',
|
|
75
|
+
primary: {
|
|
76
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
77
|
+
foreground: 'hsl(var(--primary-foreground))',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
plugins: [require('tailwindcss-animate')],
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export default config
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### lib/utils.ts
|
|
89
|
+
```typescript
|
|
90
|
+
import { type ClassValue, clsx } from 'clsx'
|
|
91
|
+
import { twMerge } from 'tailwind-merge'
|
|
92
|
+
|
|
93
|
+
export function cn(...inputs: ClassValue[]) {
|
|
94
|
+
return twMerge(clsx(inputs))
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Component Example
|
|
99
|
+
|
|
100
|
+
### components/ui/Button/Button.tsx
|
|
101
|
+
```typescript
|
|
102
|
+
import { forwardRef } from 'react'
|
|
103
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
104
|
+
import { cn } from '@/lib/utils'
|
|
105
|
+
|
|
106
|
+
const buttonVariants = cva(
|
|
107
|
+
'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50',
|
|
108
|
+
{
|
|
109
|
+
variants: {
|
|
110
|
+
variant: {
|
|
111
|
+
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
112
|
+
outline: 'border border-input bg-background hover:bg-accent',
|
|
113
|
+
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
114
|
+
},
|
|
115
|
+
size: {
|
|
116
|
+
default: 'h-10 px-4 py-2',
|
|
117
|
+
sm: 'h-9 px-3',
|
|
118
|
+
lg: 'h-11 px-8',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
defaultVariants: {
|
|
122
|
+
variant: 'default',
|
|
123
|
+
size: 'default',
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
interface ButtonProps
|
|
129
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
130
|
+
VariantProps<typeof buttonVariants> {}
|
|
131
|
+
|
|
132
|
+
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
133
|
+
({ className, variant, size, ...props }, ref) => {
|
|
134
|
+
return (
|
|
135
|
+
<button
|
|
136
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
137
|
+
ref={ref}
|
|
138
|
+
{...props}
|
|
139
|
+
/>
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
Button.displayName = 'Button'
|
|
145
|
+
|
|
146
|
+
export { Button, buttonVariants }
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## API Route Example
|
|
150
|
+
|
|
151
|
+
### app/api/users/route.ts
|
|
152
|
+
```typescript
|
|
153
|
+
import { NextResponse } from 'next/server'
|
|
154
|
+
import { z } from 'zod'
|
|
155
|
+
|
|
156
|
+
const userSchema = z.object({
|
|
157
|
+
name: z.string().min(1),
|
|
158
|
+
email: z.string().email(),
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
export async function POST(request: Request) {
|
|
162
|
+
try {
|
|
163
|
+
const body = await request.json()
|
|
164
|
+
const validated = userSchema.parse(body)
|
|
165
|
+
|
|
166
|
+
// Create user logic here
|
|
167
|
+
|
|
168
|
+
return NextResponse.json(
|
|
169
|
+
{ message: 'User created', data: validated },
|
|
170
|
+
{ status: 201 }
|
|
171
|
+
)
|
|
172
|
+
} catch (error) {
|
|
173
|
+
if (error instanceof z.ZodError) {
|
|
174
|
+
return NextResponse.json(
|
|
175
|
+
{ error: 'Validation failed', details: error.errors },
|
|
176
|
+
{ status: 400 }
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
return NextResponse.json(
|
|
180
|
+
{ error: 'Internal server error' },
|
|
181
|
+
{ status: 500 }
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## React Query Setup
|
|
188
|
+
|
|
189
|
+
### lib/query-client.ts
|
|
190
|
+
```typescript
|
|
191
|
+
import { QueryClient } from '@tanstack/react-query'
|
|
192
|
+
|
|
193
|
+
export const queryClient = new QueryClient({
|
|
194
|
+
defaultOptions: {
|
|
195
|
+
queries: {
|
|
196
|
+
staleTime: 60 * 1000,
|
|
197
|
+
retry: 1,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
})
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### hooks/useUsers.ts
|
|
204
|
+
```typescript
|
|
205
|
+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
206
|
+
|
|
207
|
+
export function useUsers() {
|
|
208
|
+
return useQuery({
|
|
209
|
+
queryKey: ['users'],
|
|
210
|
+
queryFn: () => fetch('/api/users').then(r => r.json()),
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function useCreateUser() {
|
|
215
|
+
const queryClient = useQueryClient()
|
|
216
|
+
|
|
217
|
+
return useMutation({
|
|
218
|
+
mutationFn: (data: CreateUserInput) =>
|
|
219
|
+
fetch('/api/users', {
|
|
220
|
+
method: 'POST',
|
|
221
|
+
body: JSON.stringify(data),
|
|
222
|
+
}).then(r => r.json()),
|
|
223
|
+
onSuccess: () => {
|
|
224
|
+
queryClient.invalidateQueries({ queryKey: ['users'] })
|
|
225
|
+
},
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Best Practices
|
|
231
|
+
|
|
232
|
+
1. **Server Components by Default**: Use client components only when needed
|
|
233
|
+
2. **Colocation**: Keep related files together
|
|
234
|
+
3. **Type Safety**: Use Zod for runtime validation
|
|
235
|
+
4. **Error Boundaries**: Implement proper error handling
|
|
236
|
+
5. **Loading States**: Use Suspense and loading.tsx
|