agentic-team-templates 0.3.0
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/README.md +280 -0
- package/bin/cli.js +5 -0
- package/package.json +47 -0
- package/src/index.js +521 -0
- package/templates/_shared/code-quality.md +162 -0
- package/templates/_shared/communication.md +114 -0
- package/templates/_shared/core-principles.md +62 -0
- package/templates/_shared/git-workflow.md +165 -0
- package/templates/_shared/security-fundamentals.md +173 -0
- package/templates/blockchain/.cursorrules/defi-patterns.md +520 -0
- package/templates/blockchain/.cursorrules/gas-optimization.md +339 -0
- package/templates/blockchain/.cursorrules/overview.md +130 -0
- package/templates/blockchain/.cursorrules/security.md +318 -0
- package/templates/blockchain/.cursorrules/smart-contracts.md +364 -0
- package/templates/blockchain/.cursorrules/testing.md +415 -0
- package/templates/blockchain/.cursorrules/web3-integration.md +538 -0
- package/templates/blockchain/CLAUDE.md +389 -0
- package/templates/cli-tools/.cursorrules/architecture.md +412 -0
- package/templates/cli-tools/.cursorrules/arguments.md +406 -0
- package/templates/cli-tools/.cursorrules/distribution.md +546 -0
- package/templates/cli-tools/.cursorrules/error-handling.md +455 -0
- package/templates/cli-tools/.cursorrules/overview.md +136 -0
- package/templates/cli-tools/.cursorrules/testing.md +537 -0
- package/templates/cli-tools/.cursorrules/user-experience.md +545 -0
- package/templates/cli-tools/CLAUDE.md +356 -0
- package/templates/data-engineering/.cursorrules/data-modeling.md +367 -0
- package/templates/data-engineering/.cursorrules/data-quality.md +455 -0
- package/templates/data-engineering/.cursorrules/overview.md +85 -0
- package/templates/data-engineering/.cursorrules/performance.md +339 -0
- package/templates/data-engineering/.cursorrules/pipeline-design.md +280 -0
- package/templates/data-engineering/.cursorrules/security.md +460 -0
- package/templates/data-engineering/.cursorrules/testing.md +452 -0
- package/templates/data-engineering/CLAUDE.md +974 -0
- package/templates/devops-sre/.cursorrules/capacity-planning.md +653 -0
- package/templates/devops-sre/.cursorrules/change-management.md +584 -0
- package/templates/devops-sre/.cursorrules/chaos-engineering.md +651 -0
- package/templates/devops-sre/.cursorrules/disaster-recovery.md +641 -0
- package/templates/devops-sre/.cursorrules/incident-management.md +565 -0
- package/templates/devops-sre/.cursorrules/observability.md +714 -0
- package/templates/devops-sre/.cursorrules/overview.md +230 -0
- package/templates/devops-sre/.cursorrules/postmortems.md +588 -0
- package/templates/devops-sre/.cursorrules/runbooks.md +760 -0
- package/templates/devops-sre/.cursorrules/slo-sli.md +617 -0
- package/templates/devops-sre/.cursorrules/toil-reduction.md +567 -0
- package/templates/devops-sre/CLAUDE.md +1007 -0
- package/templates/documentation/.cursorrules/adr.md +277 -0
- package/templates/documentation/.cursorrules/api-documentation.md +411 -0
- package/templates/documentation/.cursorrules/code-comments.md +253 -0
- package/templates/documentation/.cursorrules/maintenance.md +260 -0
- package/templates/documentation/.cursorrules/overview.md +82 -0
- package/templates/documentation/.cursorrules/readme-standards.md +306 -0
- package/templates/documentation/CLAUDE.md +120 -0
- package/templates/fullstack/.cursorrules/api-contracts.md +331 -0
- package/templates/fullstack/.cursorrules/architecture.md +298 -0
- package/templates/fullstack/.cursorrules/overview.md +109 -0
- package/templates/fullstack/.cursorrules/shared-types.md +348 -0
- package/templates/fullstack/.cursorrules/testing.md +386 -0
- package/templates/fullstack/CLAUDE.md +349 -0
- package/templates/ml-ai/.cursorrules/data-engineering.md +483 -0
- package/templates/ml-ai/.cursorrules/deployment.md +601 -0
- package/templates/ml-ai/.cursorrules/model-development.md +538 -0
- package/templates/ml-ai/.cursorrules/monitoring.md +658 -0
- package/templates/ml-ai/.cursorrules/overview.md +131 -0
- package/templates/ml-ai/.cursorrules/security.md +637 -0
- package/templates/ml-ai/.cursorrules/testing.md +678 -0
- package/templates/ml-ai/CLAUDE.md +1136 -0
- package/templates/mobile/.cursorrules/navigation.md +246 -0
- package/templates/mobile/.cursorrules/offline-first.md +302 -0
- package/templates/mobile/.cursorrules/overview.md +71 -0
- package/templates/mobile/.cursorrules/performance.md +345 -0
- package/templates/mobile/.cursorrules/testing.md +339 -0
- package/templates/mobile/CLAUDE.md +233 -0
- package/templates/platform-engineering/.cursorrules/ci-cd.md +778 -0
- package/templates/platform-engineering/.cursorrules/developer-experience.md +632 -0
- package/templates/platform-engineering/.cursorrules/infrastructure-as-code.md +600 -0
- package/templates/platform-engineering/.cursorrules/kubernetes.md +710 -0
- package/templates/platform-engineering/.cursorrules/observability.md +747 -0
- package/templates/platform-engineering/.cursorrules/overview.md +215 -0
- package/templates/platform-engineering/.cursorrules/security.md +855 -0
- package/templates/platform-engineering/.cursorrules/testing.md +878 -0
- package/templates/platform-engineering/CLAUDE.md +850 -0
- package/templates/utility-agent/.cursorrules/action-control.md +284 -0
- package/templates/utility-agent/.cursorrules/context-management.md +186 -0
- package/templates/utility-agent/.cursorrules/hallucination-prevention.md +253 -0
- package/templates/utility-agent/.cursorrules/overview.md +78 -0
- package/templates/utility-agent/.cursorrules/token-optimization.md +369 -0
- package/templates/utility-agent/CLAUDE.md +513 -0
- package/templates/web-backend/.cursorrules/api-design.md +255 -0
- package/templates/web-backend/.cursorrules/authentication.md +309 -0
- package/templates/web-backend/.cursorrules/database-patterns.md +298 -0
- package/templates/web-backend/.cursorrules/error-handling.md +366 -0
- package/templates/web-backend/.cursorrules/overview.md +69 -0
- package/templates/web-backend/.cursorrules/security.md +358 -0
- package/templates/web-backend/.cursorrules/testing.md +395 -0
- package/templates/web-backend/CLAUDE.md +366 -0
- package/templates/web-frontend/.cursorrules/accessibility.md +296 -0
- package/templates/web-frontend/.cursorrules/component-patterns.md +204 -0
- package/templates/web-frontend/.cursorrules/overview.md +72 -0
- package/templates/web-frontend/.cursorrules/performance.md +325 -0
- package/templates/web-frontend/.cursorrules/state-management.md +227 -0
- package/templates/web-frontend/.cursorrules/styling.md +271 -0
- package/templates/web-frontend/.cursorrules/testing.md +311 -0
- package/templates/web-frontend/CLAUDE.md +399 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Fullstack Development
|
|
2
|
+
|
|
3
|
+
Guidelines for building cohesive full-stack web applications.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
This ruleset applies to:
|
|
8
|
+
- Monolithic full-stack applications
|
|
9
|
+
- Full-stack frameworks (Next.js, Nuxt, SvelteKit, Remix, etc.)
|
|
10
|
+
- Separate frontend/backend codebases sharing types
|
|
11
|
+
- JAMstack applications with serverless backends
|
|
12
|
+
|
|
13
|
+
## Key Principles
|
|
14
|
+
|
|
15
|
+
### 1. Unified Type System
|
|
16
|
+
Share types between frontend and backend to catch errors at compile time.
|
|
17
|
+
|
|
18
|
+
### 2. Clear Boundaries
|
|
19
|
+
Maintain separation between client and server concerns, even in unified frameworks.
|
|
20
|
+
|
|
21
|
+
### 3. API-First Thinking
|
|
22
|
+
Design the API contract first, then implement both sides.
|
|
23
|
+
|
|
24
|
+
### 4. End-to-End Testing
|
|
25
|
+
Test the full user journey, not just isolated components.
|
|
26
|
+
|
|
27
|
+
## Project Structures
|
|
28
|
+
|
|
29
|
+
### Monorepo Structure
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
packages/
|
|
33
|
+
├── shared/ # Shared types, validation, utilities
|
|
34
|
+
│ ├── types/
|
|
35
|
+
│ ├── validation/
|
|
36
|
+
│ └── utils/
|
|
37
|
+
├── web/ # Frontend application
|
|
38
|
+
│ ├── components/
|
|
39
|
+
│ ├── pages/
|
|
40
|
+
│ └── hooks/
|
|
41
|
+
├── api/ # Backend API
|
|
42
|
+
│ ├── routes/
|
|
43
|
+
│ ├── services/
|
|
44
|
+
│ └── repositories/
|
|
45
|
+
└── e2e/ # End-to-end tests
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Full-Stack Framework Structure
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
src/
|
|
52
|
+
├── app/ # Pages and routing
|
|
53
|
+
│ ├── (public)/ # Public routes
|
|
54
|
+
│ ├── (auth)/ # Authenticated routes
|
|
55
|
+
│ └── api/ # API routes
|
|
56
|
+
├── components/ # React components
|
|
57
|
+
├── lib/ # Shared logic
|
|
58
|
+
│ ├── client/ # Client-only code
|
|
59
|
+
│ ├── server/ # Server-only code
|
|
60
|
+
│ └── shared/ # Isomorphic code
|
|
61
|
+
├── types/ # TypeScript definitions
|
|
62
|
+
└── validation/ # Shared validation schemas
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Core Concepts
|
|
66
|
+
|
|
67
|
+
### Server vs Client Boundaries
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// Server-only code (never sent to client)
|
|
71
|
+
// lib/server/db.ts
|
|
72
|
+
import { PrismaClient } from '@prisma/client';
|
|
73
|
+
export const db = new PrismaClient();
|
|
74
|
+
|
|
75
|
+
// Client-only code
|
|
76
|
+
// lib/client/analytics.ts
|
|
77
|
+
export const trackEvent = (event: string) => {
|
|
78
|
+
window.analytics?.track(event);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Shared code (works both sides)
|
|
82
|
+
// lib/shared/validation.ts
|
|
83
|
+
export const UserSchema = z.object({
|
|
84
|
+
email: z.string().email(),
|
|
85
|
+
name: z.string().min(1),
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Data Flow
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
User Action → Frontend Component → API Request → Server Handler
|
|
93
|
+
↓ ↓
|
|
94
|
+
UI Update ← Frontend State ← API Response ← Database Query
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Definition of Done
|
|
98
|
+
|
|
99
|
+
A fullstack feature is complete when:
|
|
100
|
+
|
|
101
|
+
- [ ] Types shared between frontend and backend
|
|
102
|
+
- [ ] API contract documented
|
|
103
|
+
- [ ] Frontend renders correctly
|
|
104
|
+
- [ ] Backend handles all edge cases
|
|
105
|
+
- [ ] Validation consistent on both sides
|
|
106
|
+
- [ ] Loading and error states handled
|
|
107
|
+
- [ ] E2E tests cover critical paths
|
|
108
|
+
- [ ] No TypeScript errors
|
|
109
|
+
- [ ] Performance acceptable
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# Shared Types
|
|
2
|
+
|
|
3
|
+
Strategies for sharing types between frontend and backend.
|
|
4
|
+
|
|
5
|
+
## Why Share Types?
|
|
6
|
+
|
|
7
|
+
- **Single Source of Truth**: Define once, use everywhere
|
|
8
|
+
- **Compile-Time Safety**: Catch mismatches before runtime
|
|
9
|
+
- **Refactoring Confidence**: Changes propagate automatically
|
|
10
|
+
- **Documentation**: Types serve as documentation
|
|
11
|
+
|
|
12
|
+
## Monorepo Setup
|
|
13
|
+
|
|
14
|
+
### Package Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
packages/
|
|
18
|
+
├── shared/ # Shared types and utilities
|
|
19
|
+
│ ├── package.json
|
|
20
|
+
│ ├── src/
|
|
21
|
+
│ │ ├── types/
|
|
22
|
+
│ │ │ ├── user.ts
|
|
23
|
+
│ │ │ ├── post.ts
|
|
24
|
+
│ │ │ └── index.ts
|
|
25
|
+
│ │ ├── validation/
|
|
26
|
+
│ │ │ ├── user.ts
|
|
27
|
+
│ │ │ └── index.ts
|
|
28
|
+
│ │ └── index.ts
|
|
29
|
+
│ └── tsconfig.json
|
|
30
|
+
├── web/
|
|
31
|
+
│ └── package.json # depends on @myapp/shared
|
|
32
|
+
└── api/
|
|
33
|
+
└── package.json # depends on @myapp/shared
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Shared Package
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
// packages/shared/package.json
|
|
40
|
+
{
|
|
41
|
+
"name": "@myapp/shared",
|
|
42
|
+
"main": "dist/index.js",
|
|
43
|
+
"types": "dist/index.d.ts",
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"dev": "tsc --watch"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// packages/shared/src/types/user.ts
|
|
53
|
+
export interface User {
|
|
54
|
+
id: string;
|
|
55
|
+
email: string;
|
|
56
|
+
name: string;
|
|
57
|
+
role: 'user' | 'admin';
|
|
58
|
+
createdAt: Date;
|
|
59
|
+
updatedAt: Date;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface CreateUserInput {
|
|
63
|
+
email: string;
|
|
64
|
+
name: string;
|
|
65
|
+
role?: 'user' | 'admin';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface UpdateUserInput {
|
|
69
|
+
name?: string;
|
|
70
|
+
role?: 'user' | 'admin';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// packages/shared/src/index.ts
|
|
74
|
+
export * from './types/user';
|
|
75
|
+
export * from './validation/user';
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Using Shared Types
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
// In API (packages/api/src/services/userService.ts)
|
|
82
|
+
import { User, CreateUserInput } from '@myapp/shared';
|
|
83
|
+
|
|
84
|
+
export const createUser = async (input: CreateUserInput): Promise<User> => {
|
|
85
|
+
// Implementation
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// In Web (packages/web/src/components/UserForm.tsx)
|
|
89
|
+
import { CreateUserInput } from '@myapp/shared';
|
|
90
|
+
|
|
91
|
+
interface UserFormProps {
|
|
92
|
+
onSubmit: (data: CreateUserInput) => void;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Shared Validation
|
|
97
|
+
|
|
98
|
+
### Zod Schemas
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// packages/shared/src/validation/user.ts
|
|
102
|
+
import { z } from 'zod';
|
|
103
|
+
|
|
104
|
+
export const CreateUserSchema = z.object({
|
|
105
|
+
email: z.string().email('Invalid email format'),
|
|
106
|
+
name: z.string().min(1, 'Name is required').max(100),
|
|
107
|
+
role: z.enum(['user', 'admin']).default('user'),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export const UpdateUserSchema = CreateUserSchema.partial().omit({ email: true });
|
|
111
|
+
|
|
112
|
+
// Infer types from schemas
|
|
113
|
+
export type CreateUserInput = z.infer<typeof CreateUserSchema>;
|
|
114
|
+
export type UpdateUserInput = z.infer<typeof UpdateUserSchema>;
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Usage on Backend
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
// packages/api/src/routes/users.ts
|
|
121
|
+
import { CreateUserSchema } from '@myapp/shared';
|
|
122
|
+
|
|
123
|
+
app.post('/users', async (req, res) => {
|
|
124
|
+
const result = CreateUserSchema.safeParse(req.body);
|
|
125
|
+
|
|
126
|
+
if (!result.success) {
|
|
127
|
+
return res.status(422).json({
|
|
128
|
+
error: {
|
|
129
|
+
code: 'VALIDATION_ERROR',
|
|
130
|
+
details: result.error.errors,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const user = await createUser(result.data);
|
|
136
|
+
res.status(201).json({ data: user });
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Usage on Frontend
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
// packages/web/src/components/UserForm.tsx
|
|
144
|
+
import { CreateUserSchema, CreateUserInput } from '@myapp/shared';
|
|
145
|
+
import { useForm } from 'react-hook-form';
|
|
146
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
147
|
+
|
|
148
|
+
export function UserForm({ onSubmit }: { onSubmit: (data: CreateUserInput) => void }) {
|
|
149
|
+
const form = useForm<CreateUserInput>({
|
|
150
|
+
resolver: zodResolver(CreateUserSchema),
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
155
|
+
<input {...form.register('email')} />
|
|
156
|
+
{form.formState.errors.email && (
|
|
157
|
+
<span>{form.formState.errors.email.message}</span>
|
|
158
|
+
)}
|
|
159
|
+
{/* ... */}
|
|
160
|
+
</form>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Type Transformations
|
|
166
|
+
|
|
167
|
+
### API Response Types
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
// packages/shared/src/types/api.ts
|
|
171
|
+
|
|
172
|
+
// Generic API response wrapper
|
|
173
|
+
export interface ApiResponse<T> {
|
|
174
|
+
data: T;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface ApiError {
|
|
178
|
+
error: {
|
|
179
|
+
code: string;
|
|
180
|
+
message: string;
|
|
181
|
+
details?: unknown;
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface PaginatedResponse<T> {
|
|
186
|
+
data: T[];
|
|
187
|
+
pagination: {
|
|
188
|
+
page: number;
|
|
189
|
+
limit: number;
|
|
190
|
+
total: number;
|
|
191
|
+
totalPages: number;
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Specific response types
|
|
196
|
+
export type UserResponse = ApiResponse<User>;
|
|
197
|
+
export type UsersResponse = PaginatedResponse<User>;
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Date Handling
|
|
201
|
+
|
|
202
|
+
Dates serialize to strings in JSON. Handle the transformation:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
// packages/shared/src/types/user.ts
|
|
206
|
+
|
|
207
|
+
// Internal type (used in backend with Date objects)
|
|
208
|
+
export interface User {
|
|
209
|
+
id: string;
|
|
210
|
+
name: string;
|
|
211
|
+
createdAt: Date;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// API type (serialized dates)
|
|
215
|
+
export interface UserDTO {
|
|
216
|
+
id: string;
|
|
217
|
+
name: string;
|
|
218
|
+
createdAt: string; // ISO 8601 string
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Transformer
|
|
222
|
+
export const toUserDTO = (user: User): UserDTO => ({
|
|
223
|
+
...user,
|
|
224
|
+
createdAt: user.createdAt.toISOString(),
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
export const fromUserDTO = (dto: UserDTO): User => ({
|
|
228
|
+
...dto,
|
|
229
|
+
createdAt: new Date(dto.createdAt),
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Enums and Constants
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
// packages/shared/src/constants/user.ts
|
|
237
|
+
|
|
238
|
+
export const UserRole = {
|
|
239
|
+
USER: 'user',
|
|
240
|
+
ADMIN: 'admin',
|
|
241
|
+
} as const;
|
|
242
|
+
|
|
243
|
+
export type UserRole = typeof UserRole[keyof typeof UserRole];
|
|
244
|
+
|
|
245
|
+
export const UserStatus = {
|
|
246
|
+
ACTIVE: 'active',
|
|
247
|
+
PENDING: 'pending',
|
|
248
|
+
SUSPENDED: 'suspended',
|
|
249
|
+
} as const;
|
|
250
|
+
|
|
251
|
+
export type UserStatus = typeof UserStatus[keyof typeof UserStatus];
|
|
252
|
+
|
|
253
|
+
// Usage
|
|
254
|
+
import { UserRole, UserStatus } from '@myapp/shared';
|
|
255
|
+
|
|
256
|
+
if (user.role === UserRole.ADMIN) {
|
|
257
|
+
// ...
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Error Types
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
// packages/shared/src/types/errors.ts
|
|
265
|
+
|
|
266
|
+
export const ErrorCode = {
|
|
267
|
+
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
268
|
+
NOT_FOUND: 'NOT_FOUND',
|
|
269
|
+
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
270
|
+
FORBIDDEN: 'FORBIDDEN',
|
|
271
|
+
CONFLICT: 'CONFLICT',
|
|
272
|
+
INTERNAL_ERROR: 'INTERNAL_ERROR',
|
|
273
|
+
} as const;
|
|
274
|
+
|
|
275
|
+
export type ErrorCode = typeof ErrorCode[keyof typeof ErrorCode];
|
|
276
|
+
|
|
277
|
+
export interface AppError {
|
|
278
|
+
code: ErrorCode;
|
|
279
|
+
message: string;
|
|
280
|
+
details?: unknown;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Usage in frontend for type-safe error handling
|
|
284
|
+
const handleError = (error: AppError) => {
|
|
285
|
+
switch (error.code) {
|
|
286
|
+
case ErrorCode.VALIDATION_ERROR:
|
|
287
|
+
showValidationErrors(error.details);
|
|
288
|
+
break;
|
|
289
|
+
case ErrorCode.UNAUTHORIZED:
|
|
290
|
+
redirectToLogin();
|
|
291
|
+
break;
|
|
292
|
+
default:
|
|
293
|
+
showGenericError(error.message);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Utility Types
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
// packages/shared/src/types/utils.ts
|
|
302
|
+
|
|
303
|
+
// Make specific fields optional
|
|
304
|
+
export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
305
|
+
|
|
306
|
+
// Make specific fields required
|
|
307
|
+
export type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
308
|
+
|
|
309
|
+
// Omit common auto-generated fields
|
|
310
|
+
export type CreateInput<T> = Omit<T, 'id' | 'createdAt' | 'updatedAt'>;
|
|
311
|
+
|
|
312
|
+
// Usage
|
|
313
|
+
type CreateUserInput = CreateInput<User>;
|
|
314
|
+
// { email: string; name: string; role: 'user' | 'admin' }
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Best Practices
|
|
318
|
+
|
|
319
|
+
### 1. Keep Shared Package Minimal
|
|
320
|
+
|
|
321
|
+
Only share what's truly shared. Don't pull in frontend or backend dependencies.
|
|
322
|
+
|
|
323
|
+
### 2. Version Carefully
|
|
324
|
+
|
|
325
|
+
Changes to shared types affect both frontend and backend. Make changes carefully.
|
|
326
|
+
|
|
327
|
+
### 3. Use Strict Mode
|
|
328
|
+
|
|
329
|
+
```json
|
|
330
|
+
// packages/shared/tsconfig.json
|
|
331
|
+
{
|
|
332
|
+
"compilerOptions": {
|
|
333
|
+
"strict": true,
|
|
334
|
+
"noUncheckedIndexedAccess": true,
|
|
335
|
+
"noImplicitReturns": true
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### 4. Export Explicitly
|
|
341
|
+
|
|
342
|
+
```ts
|
|
343
|
+
// packages/shared/src/index.ts
|
|
344
|
+
// Explicitly export what should be public
|
|
345
|
+
export { User, CreateUserInput, UpdateUserInput } from './types/user';
|
|
346
|
+
export { CreateUserSchema, UpdateUserSchema } from './validation/user';
|
|
347
|
+
// Don't export internal helpers
|
|
348
|
+
```
|