@esreekarreddy/ai-prompts 1.0.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/LICENSE +21 -0
- package/README.md +361 -0
- package/chains/_index.md +33 -0
- package/chains/bug-fix.md +222 -0
- package/chains/new-feature.md +216 -0
- package/chains/production-launch.md +291 -0
- package/chains/refactor.md +210 -0
- package/chains/security-hardening.md +242 -0
- package/contexts/guides/api-design.md +229 -0
- package/contexts/guides/error-handling.md +219 -0
- package/contexts/patterns/agentic-coding.md +368 -0
- package/contexts/patterns/mcp-server-patterns.md +267 -0
- package/contexts/patterns/repository-pattern.md +163 -0
- package/contexts/patterns/service-layer.md +185 -0
- package/contexts/stacks/fastapi.md +187 -0
- package/contexts/stacks/nextjs-14.md +149 -0
- package/contexts/stacks/prisma.md +228 -0
- package/dist/index.d.ts +129 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +284 -0
- package/dist/index.js.map +1 -0
- package/examples/architecture-docs/sample-architecture.md +270 -0
- package/examples/code-reviews/sample-review.md +232 -0
- package/examples/prds/sample-prd.md +179 -0
- package/instructions/_index.md +57 -0
- package/instructions/personas/code-reviewer.md +83 -0
- package/instructions/personas/devops-engineer.md +90 -0
- package/instructions/personas/security-expert.md +69 -0
- package/instructions/personas/senior-engineer.md +243 -0
- package/instructions/personas/ux-engineer.md +88 -0
- package/instructions/standards/fastapi.md +241 -0
- package/instructions/standards/go.md +427 -0
- package/instructions/standards/nextjs.md +350 -0
- package/instructions/standards/nodejs.md +284 -0
- package/instructions/standards/python.md +245 -0
- package/instructions/standards/react.md +227 -0
- package/instructions/standards/rust.md +318 -0
- package/instructions/standards/typescript-react.md +822 -0
- package/instructions/standards/typescript.md +294 -0
- package/instructions/workflows/feature-development.md +222 -0
- package/instructions/workflows/incident-response.md +192 -0
- package/instructions/workflows/pr-review.md +149 -0
- package/instructions/workflows/tdd.md +160 -0
- package/package.json +84 -0
- package/prompts/_index.md +70 -0
- package/prompts/agentic/agentic-loop.md +83 -0
- package/prompts/agentic/context-manager.md +37 -0
- package/prompts/agentic/test-driven-fix.md +41 -0
- package/prompts/analysis/deep-debugger.md +488 -0
- package/prompts/design/design-system-extractor.md +147 -0
- package/prompts/development/code-cleaner.md +119 -0
- package/prompts/development/debugger.md +64 -0
- package/prompts/development/tech-debt-audit.md +88 -0
- package/prompts/planning/architecture-analyzer.md +72 -0
- package/prompts/planning/implementation-plan.md +98 -0
- package/prompts/planning/prd-generator.md +66 -0
- package/prompts/planning/scope-killer.md +74 -0
- package/prompts/quality/critical-path-tester.md +133 -0
- package/prompts/quality/pre-launch-checklist.md +137 -0
- package/prompts/quality/security-audit.md +115 -0
- package/prompts/quality/security-fixer.md +117 -0
- package/prompts/quality/security-hardening.md +157 -0
- package/prompts/system/master-system-prompt.md +252 -0
- package/skills/_index.md +60 -0
- package/skills/code-review-advanced.md +435 -0
- package/skills/code-review.md +86 -0
- package/skills/debugging.md +86 -0
- package/skills/documentation.md +97 -0
- package/skills/pr-description.md +116 -0
- package/skills/project-setup.md +123 -0
- package/skills/refactoring.md +93 -0
- package/skills/testing.md +134 -0
- package/snippets/_index.md +57 -0
- package/snippets/constraints/mvp-only.md +50 -0
- package/snippets/constraints/no-external-deps.md +45 -0
- package/snippets/constraints/read-only.md +45 -0
- package/snippets/constraints/security-first.md +50 -0
- package/snippets/modifiers/be-ruthless.md +52 -0
- package/snippets/modifiers/be-thorough.md +50 -0
- package/snippets/modifiers/effort-high.md +56 -0
- package/snippets/modifiers/explain-reasoning.md +50 -0
- package/snippets/modifiers/megathink.md +314 -0
- package/snippets/modifiers/meta-cot.md +101 -0
- package/snippets/modifiers/no-code-yet.md +55 -0
- package/snippets/modifiers/step-by-step.md +50 -0
- package/snippets/modifiers/ultrathink.md +359 -0
- package/snippets/output-formats/checklist.md +61 -0
- package/snippets/output-formats/json.md +53 -0
- package/snippets/output-formats/markdown-table.md +44 -0
- package/snippets/output-formats/numbered-list.md +44 -0
- package/templates/_index.md +101 -0
- package/templates/claude-md/auto-enhance.md +258 -0
- package/templates/claude-md/cli-tool.md +243 -0
- package/templates/claude-md/full.md +449 -0
- package/templates/claude-md/minimal.md +52 -0
- package/templates/claude-md/nextjs-app.md +207 -0
- package/templates/claude-md/nodejs-service.md +251 -0
- package/templates/claude-md/python-api.md +236 -0
- package/templates/copilot/instructions.md +33 -0
- package/templates/cursor-rules/fullstack.txt +98 -0
- package/templates/cursor-rules/minimal.txt +20 -0
- package/templates/cursor-rules/nextjs.txt +61 -0
- package/templates/cursor-rules/python.txt +79 -0
- package/templates/docs/adr-template.md +119 -0
- package/templates/docs/api-spec-template.md +277 -0
- package/templates/docs/prd-template.md +140 -0
- package/templates/docs/runbook-template.md +238 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Repository Pattern
|
|
2
|
+
|
|
3
|
+
> Abstracting data access from business logic
|
|
4
|
+
|
|
5
|
+
## Concept
|
|
6
|
+
|
|
7
|
+
The Repository Pattern separates the data access layer from business logic:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Business Logic → Repository Interface → Repository Implementation → Database
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Benefits
|
|
14
|
+
|
|
15
|
+
- **Testability**: Mock repositories in tests
|
|
16
|
+
- **Flexibility**: Switch databases without changing business logic
|
|
17
|
+
- **Single Responsibility**: Data access logic in one place
|
|
18
|
+
- **Abstraction**: Business logic doesn't know about SQL/ORM
|
|
19
|
+
|
|
20
|
+
## Implementation
|
|
21
|
+
|
|
22
|
+
### TypeScript Example
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// types/user.ts
|
|
26
|
+
interface User {
|
|
27
|
+
id: string;
|
|
28
|
+
email: string;
|
|
29
|
+
name: string;
|
|
30
|
+
createdAt: Date;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface CreateUserInput {
|
|
34
|
+
email: string;
|
|
35
|
+
name: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// repositories/user.repository.interface.ts
|
|
39
|
+
interface IUserRepository {
|
|
40
|
+
findById(id: string): Promise<User | null>;
|
|
41
|
+
findByEmail(email: string): Promise<User | null>;
|
|
42
|
+
findAll(): Promise<User[]>;
|
|
43
|
+
create(data: CreateUserInput): Promise<User>;
|
|
44
|
+
update(id: string, data: Partial<User>): Promise<User>;
|
|
45
|
+
delete(id: string): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// repositories/user.repository.ts
|
|
49
|
+
class PrismaUserRepository implements IUserRepository {
|
|
50
|
+
constructor(private prisma: PrismaClient) {}
|
|
51
|
+
|
|
52
|
+
async findById(id: string): Promise<User | null> {
|
|
53
|
+
return this.prisma.user.findUnique({ where: { id } });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async findByEmail(email: string): Promise<User | null> {
|
|
57
|
+
return this.prisma.user.findUnique({ where: { email } });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async findAll(): Promise<User[]> {
|
|
61
|
+
return this.prisma.user.findMany();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async create(data: CreateUserInput): Promise<User> {
|
|
65
|
+
return this.prisma.user.create({ data });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async update(id: string, data: Partial<User>): Promise<User> {
|
|
69
|
+
return this.prisma.user.update({ where: { id }, data });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async delete(id: string): Promise<void> {
|
|
73
|
+
await this.prisma.user.delete({ where: { id } });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Using in Service Layer
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
// services/user.service.ts
|
|
82
|
+
class UserService {
|
|
83
|
+
constructor(private userRepo: IUserRepository) {}
|
|
84
|
+
|
|
85
|
+
async registerUser(email: string, name: string): Promise<User> {
|
|
86
|
+
// Business logic here
|
|
87
|
+
const existing = await this.userRepo.findByEmail(email);
|
|
88
|
+
if (existing) {
|
|
89
|
+
throw new Error('Email already exists');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return this.userRepo.create({ email, name });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async getUserById(id: string): Promise<User> {
|
|
96
|
+
const user = await this.userRepo.findById(id);
|
|
97
|
+
if (!user) {
|
|
98
|
+
throw new NotFoundError('User');
|
|
99
|
+
}
|
|
100
|
+
return user;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Testing with Mock Repository
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// tests/user.service.test.ts
|
|
109
|
+
class MockUserRepository implements IUserRepository {
|
|
110
|
+
private users: User[] = [];
|
|
111
|
+
|
|
112
|
+
async findById(id: string) {
|
|
113
|
+
return this.users.find(u => u.id === id) || null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async findByEmail(email: string) {
|
|
117
|
+
return this.users.find(u => u.email === email) || null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async create(data: CreateUserInput) {
|
|
121
|
+
const user = { id: '1', ...data, createdAt: new Date() };
|
|
122
|
+
this.users.push(user);
|
|
123
|
+
return user;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ... other methods
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
describe('UserService', () => {
|
|
130
|
+
it('should register new user', async () => {
|
|
131
|
+
const repo = new MockUserRepository();
|
|
132
|
+
const service = new UserService(repo);
|
|
133
|
+
|
|
134
|
+
const user = await service.registerUser('test@example.com', 'Test');
|
|
135
|
+
|
|
136
|
+
expect(user.email).toBe('test@example.com');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should reject duplicate email', async () => {
|
|
140
|
+
const repo = new MockUserRepository();
|
|
141
|
+
const service = new UserService(repo);
|
|
142
|
+
|
|
143
|
+
await service.registerUser('test@example.com', 'Test');
|
|
144
|
+
|
|
145
|
+
await expect(
|
|
146
|
+
service.registerUser('test@example.com', 'Test2')
|
|
147
|
+
).rejects.toThrow('Email already exists');
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## When to Use
|
|
153
|
+
|
|
154
|
+
**Good for:**
|
|
155
|
+
- Large applications with complex data access
|
|
156
|
+
- When you might switch databases
|
|
157
|
+
- When extensive testing is needed
|
|
158
|
+
- Multi-database scenarios
|
|
159
|
+
|
|
160
|
+
**Overkill for:**
|
|
161
|
+
- Simple CRUD apps
|
|
162
|
+
- Prototypes
|
|
163
|
+
- Small projects with single database
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Service Layer Pattern
|
|
2
|
+
|
|
3
|
+
> Organizing business logic in a dedicated layer
|
|
4
|
+
|
|
5
|
+
## Concept
|
|
6
|
+
|
|
7
|
+
The Service Layer contains business logic, sitting between controllers/handlers and data access:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Controller → Service → Repository → Database
|
|
11
|
+
↑ ↓
|
|
12
|
+
└─── Response
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Benefits
|
|
16
|
+
|
|
17
|
+
- **Reusability**: Same logic used by API, CLI, jobs
|
|
18
|
+
- **Testability**: Test business logic without HTTP
|
|
19
|
+
- **Separation of Concerns**: Controllers handle HTTP, services handle logic
|
|
20
|
+
- **Transaction Management**: Coordinate multiple operations
|
|
21
|
+
|
|
22
|
+
## Implementation
|
|
23
|
+
|
|
24
|
+
### TypeScript Example
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// services/order.service.ts
|
|
28
|
+
import { OrderRepository } from '../repositories/order.repository';
|
|
29
|
+
import { ProductRepository } from '../repositories/product.repository';
|
|
30
|
+
import { PaymentService } from './payment.service';
|
|
31
|
+
import { EmailService } from './email.service';
|
|
32
|
+
|
|
33
|
+
interface CreateOrderInput {
|
|
34
|
+
userId: string;
|
|
35
|
+
items: Array<{ productId: string; quantity: number }>;
|
|
36
|
+
paymentMethodId: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class OrderService {
|
|
40
|
+
constructor(
|
|
41
|
+
private orderRepo: OrderRepository,
|
|
42
|
+
private productRepo: ProductRepository,
|
|
43
|
+
private paymentService: PaymentService,
|
|
44
|
+
private emailService: EmailService
|
|
45
|
+
) {}
|
|
46
|
+
|
|
47
|
+
async createOrder(input: CreateOrderInput): Promise<Order> {
|
|
48
|
+
// 1. Validate products exist and have stock
|
|
49
|
+
const products = await this.validateAndGetProducts(input.items);
|
|
50
|
+
|
|
51
|
+
// 2. Calculate total
|
|
52
|
+
const total = this.calculateTotal(products, input.items);
|
|
53
|
+
|
|
54
|
+
// 3. Process payment
|
|
55
|
+
const payment = await this.paymentService.charge({
|
|
56
|
+
amount: total,
|
|
57
|
+
methodId: input.paymentMethodId,
|
|
58
|
+
userId: input.userId,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!payment.success) {
|
|
62
|
+
throw new PaymentError(payment.error);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 4. Create order
|
|
66
|
+
const order = await this.orderRepo.create({
|
|
67
|
+
userId: input.userId,
|
|
68
|
+
items: input.items,
|
|
69
|
+
total,
|
|
70
|
+
paymentId: payment.id,
|
|
71
|
+
status: 'confirmed',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// 5. Update inventory
|
|
75
|
+
await this.productRepo.decrementStock(input.items);
|
|
76
|
+
|
|
77
|
+
// 6. Send confirmation (async, don't wait)
|
|
78
|
+
this.emailService.sendOrderConfirmation(order).catch(console.error);
|
|
79
|
+
|
|
80
|
+
return order;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private async validateAndGetProducts(items: OrderItem[]) {
|
|
84
|
+
const productIds = items.map(i => i.productId);
|
|
85
|
+
const products = await this.productRepo.findByIds(productIds);
|
|
86
|
+
|
|
87
|
+
// Check all products exist
|
|
88
|
+
if (products.length !== productIds.length) {
|
|
89
|
+
throw new ValidationError('Some products not found');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check stock
|
|
93
|
+
for (const item of items) {
|
|
94
|
+
const product = products.find(p => p.id === item.productId);
|
|
95
|
+
if (product.stock < item.quantity) {
|
|
96
|
+
throw new ValidationError(`Insufficient stock for ${product.name}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return products;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private calculateTotal(products: Product[], items: OrderItem[]): number {
|
|
104
|
+
return items.reduce((sum, item) => {
|
|
105
|
+
const product = products.find(p => p.id === item.productId);
|
|
106
|
+
return sum + (product.price * item.quantity);
|
|
107
|
+
}, 0);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Using in Controller
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// controllers/order.controller.ts
|
|
116
|
+
class OrderController {
|
|
117
|
+
constructor(private orderService: OrderService) {}
|
|
118
|
+
|
|
119
|
+
async create(req: Request, res: Response, next: NextFunction) {
|
|
120
|
+
try {
|
|
121
|
+
const order = await this.orderService.createOrder({
|
|
122
|
+
userId: req.user.id,
|
|
123
|
+
items: req.body.items,
|
|
124
|
+
paymentMethodId: req.body.paymentMethodId,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
res.status(201).json(order);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
if (error instanceof ValidationError) {
|
|
130
|
+
return res.status(400).json({ error: error.message });
|
|
131
|
+
}
|
|
132
|
+
if (error instanceof PaymentError) {
|
|
133
|
+
return res.status(402).json({ error: error.message });
|
|
134
|
+
}
|
|
135
|
+
next(error);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Service Guidelines
|
|
142
|
+
|
|
143
|
+
### Do
|
|
144
|
+
- Contain all business logic
|
|
145
|
+
- Coordinate between repositories
|
|
146
|
+
- Handle transactions
|
|
147
|
+
- Throw domain-specific errors
|
|
148
|
+
|
|
149
|
+
### Don't
|
|
150
|
+
- Handle HTTP request/response
|
|
151
|
+
- Access request objects directly
|
|
152
|
+
- Know about view layer
|
|
153
|
+
- Contain data access logic
|
|
154
|
+
|
|
155
|
+
## Service Method Patterns
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// Query methods - return data or null
|
|
159
|
+
async getUser(id: string): Promise<User | null> {
|
|
160
|
+
return this.userRepo.findById(id);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Command methods - throw on failure
|
|
164
|
+
async createUser(data: CreateUserInput): Promise<User> {
|
|
165
|
+
// Validation
|
|
166
|
+
if (await this.userRepo.findByEmail(data.email)) {
|
|
167
|
+
throw new DuplicateError('Email already exists');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Business logic
|
|
171
|
+
const hashedPassword = await this.hashPassword(data.password);
|
|
172
|
+
|
|
173
|
+
// Persistence
|
|
174
|
+
return this.userRepo.create({
|
|
175
|
+
...data,
|
|
176
|
+
password: hashedPassword,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Boolean checks
|
|
181
|
+
async canUserAccess(userId: string, resourceId: string): Promise<boolean> {
|
|
182
|
+
const resource = await this.resourceRepo.findById(resourceId);
|
|
183
|
+
return resource?.ownerId === userId;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# FastAPI Context
|
|
2
|
+
|
|
3
|
+
> Reference for FastAPI Python web framework
|
|
4
|
+
|
|
5
|
+
## Key Features
|
|
6
|
+
|
|
7
|
+
- Fast (async support, Starlette + Pydantic)
|
|
8
|
+
- Automatic OpenAPI/Swagger docs
|
|
9
|
+
- Type hints for validation
|
|
10
|
+
- Dependency injection system
|
|
11
|
+
|
|
12
|
+
## Basic Structure
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
from fastapi import FastAPI, HTTPException, Depends
|
|
16
|
+
from pydantic import BaseModel
|
|
17
|
+
|
|
18
|
+
app = FastAPI()
|
|
19
|
+
|
|
20
|
+
class Item(BaseModel):
|
|
21
|
+
name: str
|
|
22
|
+
price: float
|
|
23
|
+
|
|
24
|
+
@app.get("/")
|
|
25
|
+
async def root():
|
|
26
|
+
return {"message": "Hello World"}
|
|
27
|
+
|
|
28
|
+
@app.get("/items/{item_id}")
|
|
29
|
+
async def get_item(item_id: int):
|
|
30
|
+
return {"item_id": item_id}
|
|
31
|
+
|
|
32
|
+
@app.post("/items/")
|
|
33
|
+
async def create_item(item: Item):
|
|
34
|
+
return item
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Request Handling
|
|
38
|
+
|
|
39
|
+
### Path Parameters
|
|
40
|
+
```python
|
|
41
|
+
@app.get("/users/{user_id}")
|
|
42
|
+
async def get_user(user_id: int): # Validated as int
|
|
43
|
+
return {"user_id": user_id}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Query Parameters
|
|
47
|
+
```python
|
|
48
|
+
@app.get("/items/")
|
|
49
|
+
async def list_items(
|
|
50
|
+
skip: int = 0,
|
|
51
|
+
limit: int = 10,
|
|
52
|
+
search: str | None = None
|
|
53
|
+
):
|
|
54
|
+
return {"skip": skip, "limit": limit, "search": search}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Request Body
|
|
58
|
+
```python
|
|
59
|
+
class CreateUser(BaseModel):
|
|
60
|
+
email: str
|
|
61
|
+
name: str
|
|
62
|
+
password: str
|
|
63
|
+
|
|
64
|
+
@app.post("/users/")
|
|
65
|
+
async def create_user(user: CreateUser):
|
|
66
|
+
return {"email": user.email}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Pydantic Models
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from pydantic import BaseModel, EmailStr, Field
|
|
73
|
+
from datetime import datetime
|
|
74
|
+
|
|
75
|
+
class UserBase(BaseModel):
|
|
76
|
+
email: EmailStr
|
|
77
|
+
name: str = Field(..., min_length=2, max_length=100)
|
|
78
|
+
|
|
79
|
+
class UserCreate(UserBase):
|
|
80
|
+
password: str = Field(..., min_length=8)
|
|
81
|
+
|
|
82
|
+
class UserResponse(UserBase):
|
|
83
|
+
id: int
|
|
84
|
+
created_at: datetime
|
|
85
|
+
|
|
86
|
+
model_config = {"from_attributes": True}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Dependencies
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from fastapi import Depends
|
|
93
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
94
|
+
|
|
95
|
+
async def get_db():
|
|
96
|
+
async with async_session() as session:
|
|
97
|
+
yield session
|
|
98
|
+
|
|
99
|
+
async def get_current_user(
|
|
100
|
+
token: str = Depends(oauth2_scheme),
|
|
101
|
+
db: AsyncSession = Depends(get_db)
|
|
102
|
+
):
|
|
103
|
+
user = await verify_token(db, token)
|
|
104
|
+
if not user:
|
|
105
|
+
raise HTTPException(status_code=401)
|
|
106
|
+
return user
|
|
107
|
+
|
|
108
|
+
@app.get("/me")
|
|
109
|
+
async def get_me(user: User = Depends(get_current_user)):
|
|
110
|
+
return user
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Error Handling
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from fastapi import HTTPException, status
|
|
117
|
+
|
|
118
|
+
@app.get("/items/{item_id}")
|
|
119
|
+
async def get_item(item_id: int):
|
|
120
|
+
item = await get_item_by_id(item_id)
|
|
121
|
+
if not item:
|
|
122
|
+
raise HTTPException(
|
|
123
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
124
|
+
detail="Item not found"
|
|
125
|
+
)
|
|
126
|
+
return item
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Background Tasks
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from fastapi import BackgroundTasks
|
|
133
|
+
|
|
134
|
+
async def send_email(email: str, message: str):
|
|
135
|
+
# Send email
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
@app.post("/notify/")
|
|
139
|
+
async def notify(
|
|
140
|
+
email: str,
|
|
141
|
+
background_tasks: BackgroundTasks
|
|
142
|
+
):
|
|
143
|
+
background_tasks.add_task(send_email, email, "Hello")
|
|
144
|
+
return {"message": "Notification scheduled"}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Middleware
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
151
|
+
|
|
152
|
+
app.add_middleware(
|
|
153
|
+
CORSMiddleware,
|
|
154
|
+
allow_origins=["*"],
|
|
155
|
+
allow_methods=["*"],
|
|
156
|
+
allow_headers=["*"],
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
@app.middleware("http")
|
|
160
|
+
async def log_requests(request, call_next):
|
|
161
|
+
print(f"{request.method} {request.url}")
|
|
162
|
+
response = await call_next(request)
|
|
163
|
+
return response
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Routers
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
# routers/users.py
|
|
170
|
+
from fastapi import APIRouter
|
|
171
|
+
|
|
172
|
+
router = APIRouter(prefix="/users", tags=["users"])
|
|
173
|
+
|
|
174
|
+
@router.get("/")
|
|
175
|
+
async def list_users():
|
|
176
|
+
return []
|
|
177
|
+
|
|
178
|
+
# main.py
|
|
179
|
+
from routers import users
|
|
180
|
+
app.include_router(users.router)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## OpenAPI Docs
|
|
184
|
+
|
|
185
|
+
- Swagger UI: `http://localhost:8000/docs`
|
|
186
|
+
- ReDoc: `http://localhost:8000/redoc`
|
|
187
|
+
- OpenAPI JSON: `http://localhost:8000/openapi.json`
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Next.js 14 Context
|
|
2
|
+
|
|
3
|
+
> Reference for Next.js 14 with App Router
|
|
4
|
+
|
|
5
|
+
## Key Concepts
|
|
6
|
+
|
|
7
|
+
### App Router vs Pages Router
|
|
8
|
+
Next.js 14 uses the **App Router** by default:
|
|
9
|
+
- Files in `app/` directory
|
|
10
|
+
- React Server Components by default
|
|
11
|
+
- New data fetching patterns
|
|
12
|
+
- Layouts and loading states built-in
|
|
13
|
+
|
|
14
|
+
### Server Components (Default)
|
|
15
|
+
```tsx
|
|
16
|
+
// This is a Server Component (no directive needed)
|
|
17
|
+
async function Page() {
|
|
18
|
+
const data = await db.query(...); // Direct database access
|
|
19
|
+
return <Component data={data} />;
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Client Components (Opt-in)
|
|
24
|
+
```tsx
|
|
25
|
+
'use client';
|
|
26
|
+
|
|
27
|
+
import { useState } from 'react';
|
|
28
|
+
|
|
29
|
+
export function Counter() {
|
|
30
|
+
const [count, setCount] = useState(0);
|
|
31
|
+
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## File Conventions
|
|
36
|
+
|
|
37
|
+
| File | Purpose |
|
|
38
|
+
|------|---------|
|
|
39
|
+
| `page.tsx` | Route UI |
|
|
40
|
+
| `layout.tsx` | Shared layout |
|
|
41
|
+
| `loading.tsx` | Loading UI |
|
|
42
|
+
| `error.tsx` | Error boundary |
|
|
43
|
+
| `not-found.tsx` | 404 page |
|
|
44
|
+
| `route.ts` | API route |
|
|
45
|
+
|
|
46
|
+
## Data Fetching
|
|
47
|
+
|
|
48
|
+
### In Server Components
|
|
49
|
+
```tsx
|
|
50
|
+
// Fetch directly - no useEffect needed
|
|
51
|
+
async function Page() {
|
|
52
|
+
const res = await fetch('https://api.example.com/data', {
|
|
53
|
+
cache: 'force-cache', // Default: cache
|
|
54
|
+
// cache: 'no-store', // No cache
|
|
55
|
+
// next: { revalidate: 60 } // Revalidate every 60s
|
|
56
|
+
});
|
|
57
|
+
const data = await res.json();
|
|
58
|
+
return <Display data={data} />;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Server Actions
|
|
63
|
+
```tsx
|
|
64
|
+
// app/actions.ts
|
|
65
|
+
'use server';
|
|
66
|
+
|
|
67
|
+
export async function createItem(formData: FormData) {
|
|
68
|
+
const name = formData.get('name');
|
|
69
|
+
await db.items.create({ data: { name } });
|
|
70
|
+
revalidatePath('/items');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// In component
|
|
74
|
+
<form action={createItem}>
|
|
75
|
+
<input name="name" />
|
|
76
|
+
<button type="submit">Create</button>
|
|
77
|
+
</form>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Route Handlers (API)
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// app/api/users/route.ts
|
|
84
|
+
import { NextResponse } from 'next/server';
|
|
85
|
+
|
|
86
|
+
export async function GET() {
|
|
87
|
+
const users = await db.users.findMany();
|
|
88
|
+
return NextResponse.json(users);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function POST(request: Request) {
|
|
92
|
+
const body = await request.json();
|
|
93
|
+
const user = await db.users.create({ data: body });
|
|
94
|
+
return NextResponse.json(user, { status: 201 });
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Common Patterns
|
|
99
|
+
|
|
100
|
+
### Dynamic Routes
|
|
101
|
+
```
|
|
102
|
+
app/
|
|
103
|
+
├── users/
|
|
104
|
+
│ └── [id]/
|
|
105
|
+
│ └── page.tsx → /users/123
|
|
106
|
+
├── blog/
|
|
107
|
+
│ └── [...slug]/
|
|
108
|
+
│ └── page.tsx → /blog/a/b/c
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Route Groups
|
|
112
|
+
```
|
|
113
|
+
app/
|
|
114
|
+
├── (marketing)/
|
|
115
|
+
│ ├── about/page.tsx → /about
|
|
116
|
+
│ └── layout.tsx → Marketing layout
|
|
117
|
+
├── (dashboard)/
|
|
118
|
+
│ ├── dashboard/page.tsx → /dashboard
|
|
119
|
+
│ └── layout.tsx → Dashboard layout
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Parallel Routes
|
|
123
|
+
```
|
|
124
|
+
app/
|
|
125
|
+
├── @modal/
|
|
126
|
+
│ └── login/page.tsx
|
|
127
|
+
├── @sidebar/
|
|
128
|
+
│ └── default.tsx
|
|
129
|
+
└── layout.tsx → Renders both in parallel
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Caching
|
|
133
|
+
|
|
134
|
+
| Type | Default | Control |
|
|
135
|
+
|------|---------|---------|
|
|
136
|
+
| fetch() | Cached | `cache: 'no-store'` |
|
|
137
|
+
| Route Handlers | Not cached | `export const dynamic = 'force-static'` |
|
|
138
|
+
| Server Actions | Not cached | Use `revalidatePath()` |
|
|
139
|
+
|
|
140
|
+
## When to Use What
|
|
141
|
+
|
|
142
|
+
| Need | Use |
|
|
143
|
+
|------|-----|
|
|
144
|
+
| Database queries | Server Component |
|
|
145
|
+
| User interaction | Client Component |
|
|
146
|
+
| Form submission | Server Action |
|
|
147
|
+
| External API (frontend) | Client + SWR/React Query |
|
|
148
|
+
| External API (backend) | Route Handler |
|
|
149
|
+
| Mutations | Server Action |
|