thrivekit 2.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/.claude/commands/explain.md +114 -0
- package/.claude/commands/idea.md +370 -0
- package/.claude/commands/my-dna.md +122 -0
- package/.claude/commands/prd.md +286 -0
- package/.claude/commands/review.md +167 -0
- package/.claude/commands/sign.md +32 -0
- package/.claude/commands/styleguide.md +450 -0
- package/.claude/commands/tour.md +301 -0
- package/.claude/commands/vibe-check.md +116 -0
- package/.claude/commands/vibe-help.md +47 -0
- package/.claude/commands/vibe-list.md +203 -0
- package/.claude/settings.json +75 -0
- package/.claude/settings.local.json +12 -0
- package/.pre-commit-hooks.yaml +102 -0
- package/LICENSE +21 -0
- package/README.md +214 -0
- package/bin/postinstall.sh +29 -0
- package/bin/ralph.sh +171 -0
- package/bin/thrivekit.sh +24 -0
- package/bin/vibe-check.js +19 -0
- package/dist/checks/check-any-types.d.ts +6 -0
- package/dist/checks/check-any-types.d.ts.map +1 -0
- package/dist/checks/check-any-types.js +73 -0
- package/dist/checks/check-any-types.js.map +1 -0
- package/dist/checks/check-commented-code.d.ts +6 -0
- package/dist/checks/check-commented-code.d.ts.map +1 -0
- package/dist/checks/check-commented-code.js +81 -0
- package/dist/checks/check-commented-code.js.map +1 -0
- package/dist/checks/check-console-error.d.ts +6 -0
- package/dist/checks/check-console-error.d.ts.map +1 -0
- package/dist/checks/check-console-error.js +41 -0
- package/dist/checks/check-console-error.js.map +1 -0
- package/dist/checks/check-debug-statements.d.ts +6 -0
- package/dist/checks/check-debug-statements.d.ts.map +1 -0
- package/dist/checks/check-debug-statements.js +120 -0
- package/dist/checks/check-debug-statements.js.map +1 -0
- package/dist/checks/check-deep-nesting.d.ts +6 -0
- package/dist/checks/check-deep-nesting.d.ts.map +1 -0
- package/dist/checks/check-deep-nesting.js +116 -0
- package/dist/checks/check-deep-nesting.js.map +1 -0
- package/dist/checks/check-docker-platform.d.ts +6 -0
- package/dist/checks/check-docker-platform.d.ts.map +1 -0
- package/dist/checks/check-docker-platform.js +42 -0
- package/dist/checks/check-docker-platform.js.map +1 -0
- package/dist/checks/check-dry-violations.d.ts +6 -0
- package/dist/checks/check-dry-violations.d.ts.map +1 -0
- package/dist/checks/check-dry-violations.js +124 -0
- package/dist/checks/check-dry-violations.js.map +1 -0
- package/dist/checks/check-empty-catch.d.ts +6 -0
- package/dist/checks/check-empty-catch.d.ts.map +1 -0
- package/dist/checks/check-empty-catch.js +111 -0
- package/dist/checks/check-empty-catch.js.map +1 -0
- package/dist/checks/check-function-length.d.ts +6 -0
- package/dist/checks/check-function-length.d.ts.map +1 -0
- package/dist/checks/check-function-length.js +152 -0
- package/dist/checks/check-function-length.js.map +1 -0
- package/dist/checks/check-hardcoded-ai-models.d.ts +10 -0
- package/dist/checks/check-hardcoded-ai-models.d.ts.map +1 -0
- package/dist/checks/check-hardcoded-ai-models.js +102 -0
- package/dist/checks/check-hardcoded-ai-models.js.map +1 -0
- package/dist/checks/check-hardcoded-urls.d.ts +6 -0
- package/dist/checks/check-hardcoded-urls.d.ts.map +1 -0
- package/dist/checks/check-hardcoded-urls.js +124 -0
- package/dist/checks/check-hardcoded-urls.js.map +1 -0
- package/dist/checks/check-magic-numbers.d.ts +6 -0
- package/dist/checks/check-magic-numbers.d.ts.map +1 -0
- package/dist/checks/check-magic-numbers.js +116 -0
- package/dist/checks/check-magic-numbers.js.map +1 -0
- package/dist/checks/check-secrets.d.ts +6 -0
- package/dist/checks/check-secrets.d.ts.map +1 -0
- package/dist/checks/check-secrets.js +138 -0
- package/dist/checks/check-secrets.js.map +1 -0
- package/dist/checks/check-snake-case-ts.d.ts +6 -0
- package/dist/checks/check-snake-case-ts.d.ts.map +1 -0
- package/dist/checks/check-snake-case-ts.js +78 -0
- package/dist/checks/check-snake-case-ts.js.map +1 -0
- package/dist/checks/check-todo-fixme.d.ts +6 -0
- package/dist/checks/check-todo-fixme.d.ts.map +1 -0
- package/dist/checks/check-todo-fixme.js +41 -0
- package/dist/checks/check-todo-fixme.js.map +1 -0
- package/dist/checks/check-unsafe-html.d.ts +6 -0
- package/dist/checks/check-unsafe-html.d.ts.map +1 -0
- package/dist/checks/check-unsafe-html.js +101 -0
- package/dist/checks/check-unsafe-html.js.map +1 -0
- package/dist/checks/index.d.ts +30 -0
- package/dist/checks/index.d.ts.map +1 -0
- package/dist/checks/index.js +57 -0
- package/dist/checks/index.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +206 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/file-reader.d.ts +24 -0
- package/dist/utils/file-reader.d.ts.map +1 -0
- package/dist/utils/file-reader.js +140 -0
- package/dist/utils/file-reader.js.map +1 -0
- package/dist/utils/patterns.d.ts +27 -0
- package/dist/utils/patterns.d.ts.map +1 -0
- package/dist/utils/patterns.js +84 -0
- package/dist/utils/patterns.js.map +1 -0
- package/dist/utils/reporters.d.ts +21 -0
- package/dist/utils/reporters.d.ts.map +1 -0
- package/dist/utils/reporters.js +115 -0
- package/dist/utils/reporters.js.map +1 -0
- package/dist/utils/types.d.ts +71 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/utils/types.js +5 -0
- package/dist/utils/types.js.map +1 -0
- package/package.json +82 -0
- package/ralph/api.sh +210 -0
- package/ralph/backup.sh +838 -0
- package/ralph/browser-verify/README.md +135 -0
- package/ralph/browser-verify/verify.ts +450 -0
- package/ralph/checks/check-fastapi-responses.py +155 -0
- package/ralph/hooks/hooks-config.json +72 -0
- package/ralph/hooks/inject-context.sh +44 -0
- package/ralph/hooks/install.sh +207 -0
- package/ralph/hooks/log-tools.sh +45 -0
- package/ralph/hooks/protect-prd.sh +27 -0
- package/ralph/hooks/save-learnings.sh +36 -0
- package/ralph/hooks/warn-debug.sh +54 -0
- package/ralph/hooks/warn-empty-catch.sh +63 -0
- package/ralph/hooks/warn-secrets.sh +89 -0
- package/ralph/hooks/warn-urls.sh +77 -0
- package/ralph/init.sh +388 -0
- package/ralph/loop.sh +570 -0
- package/ralph/playwright.sh +238 -0
- package/ralph/prd.sh +295 -0
- package/ralph/setup/feature-tour.sh +155 -0
- package/ralph/setup/quick-setup.sh +239 -0
- package/ralph/setup/tutorial.sh +159 -0
- package/ralph/setup/ui.sh +136 -0
- package/ralph/setup.sh +353 -0
- package/ralph/signs.sh +150 -0
- package/ralph/utils.sh +682 -0
- package/ralph/verify/browser.sh +324 -0
- package/ralph/verify/lint.sh +363 -0
- package/ralph/verify/review.sh +164 -0
- package/ralph/verify/tests.sh +81 -0
- package/ralph/verify.sh +224 -0
- package/templates/PROMPT.md +235 -0
- package/templates/config/fullstack.json +86 -0
- package/templates/config/go.json +81 -0
- package/templates/config/minimal.json +76 -0
- package/templates/config/node.json +81 -0
- package/templates/config/python.json +81 -0
- package/templates/config/rust.json +81 -0
- package/templates/examples/CLAUDE-django.md +174 -0
- package/templates/examples/CLAUDE-fastapi.md +270 -0
- package/templates/examples/CLAUDE-fastmcp.md +352 -0
- package/templates/examples/CLAUDE-fullstack.md +256 -0
- package/templates/examples/CLAUDE-node.md +246 -0
- package/templates/examples/CLAUDE-react.md +138 -0
- package/templates/optional/cursorrules.template +147 -0
- package/templates/optional/eslint.config.js +34 -0
- package/templates/optional/lint-staged.config.js +34 -0
- package/templates/optional/ruff.toml +125 -0
- package/templates/optional/vibe-check.yml +116 -0
- package/templates/optional/vscode-settings.json +127 -0
- package/templates/signs.json +46 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# Project Instructions for AI Coding Agents
|
|
2
|
+
|
|
3
|
+
## Naming Conventions
|
|
4
|
+
|
|
5
|
+
### Frontend (React/TypeScript)
|
|
6
|
+
- **Files**: `PascalCase.tsx` for components, `camelCase.ts` for utilities
|
|
7
|
+
- **Components**: `PascalCase` — e.g., `UserProfile`, `AuthProvider`
|
|
8
|
+
- **Hooks**: `useCamelCase` — e.g., `useAuth`, `useUserData`
|
|
9
|
+
- **Functions/Variables**: `camelCase` — e.g., `handleSubmit`, `isLoading`
|
|
10
|
+
|
|
11
|
+
### Backend (Django/Python)
|
|
12
|
+
- **Files**: `snake_case.py` — e.g., `user_views.py`
|
|
13
|
+
- **Functions/Variables**: `snake_case` — e.g., `get_user_by_id`
|
|
14
|
+
- **Classes**: `PascalCase` — e.g., `UserViewSet`, `UserSerializer`
|
|
15
|
+
|
|
16
|
+
### Shared
|
|
17
|
+
- **API endpoints**: `kebab-case` — e.g., `/api/user-profile/`
|
|
18
|
+
- **Database tables**: `snake_case` — e.g., `user_sessions`
|
|
19
|
+
- **Constants**: `SCREAMING_SNAKE` — e.g., `MAX_RETRIES`
|
|
20
|
+
|
|
21
|
+
## Tech Stack
|
|
22
|
+
- **Frontend**: React 18, TypeScript, Vite, TailwindCSS
|
|
23
|
+
- **Backend**: Django 5, Django REST Framework
|
|
24
|
+
- **Database**: PostgreSQL
|
|
25
|
+
- **Cache/Queue**: Redis, Celery
|
|
26
|
+
- **Testing**: pytest (backend), Vitest (frontend), Playwright (E2E)
|
|
27
|
+
|
|
28
|
+
## Architecture Overview
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
32
|
+
│ React │────▶│ Django │────▶│ PostgreSQL │
|
|
33
|
+
│ Frontend │ │ REST API │ │ Database │
|
|
34
|
+
└─────────────┘ └─────────────┘ └─────────────┘
|
|
35
|
+
│
|
|
36
|
+
▼
|
|
37
|
+
┌─────────────┐
|
|
38
|
+
│ Redis │
|
|
39
|
+
│ + Celery │
|
|
40
|
+
└─────────────┘
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Code Quality Standards
|
|
44
|
+
|
|
45
|
+
### API Contract
|
|
46
|
+
- Frontend and backend share type definitions
|
|
47
|
+
- Use consistent naming (camelCase in TS, snake_case in Python)
|
|
48
|
+
- API transforms snake_case responses to camelCase
|
|
49
|
+
- Document API changes before implementing
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// Frontend: types/api.ts
|
|
53
|
+
interface User {
|
|
54
|
+
id: number;
|
|
55
|
+
email: string;
|
|
56
|
+
firstName: string; // Transformed from first_name
|
|
57
|
+
lastName: string;
|
|
58
|
+
createdAt: string;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# Backend: serializers.py
|
|
64
|
+
class UserSerializer(serializers.ModelSerializer):
|
|
65
|
+
class Meta:
|
|
66
|
+
model = User
|
|
67
|
+
fields = ['id', 'email', 'first_name', 'last_name', 'created_at']
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Frontend Standards
|
|
71
|
+
|
|
72
|
+
**Components**
|
|
73
|
+
- Use functional components with TypeScript
|
|
74
|
+
- Keep components under 100 lines
|
|
75
|
+
- Extract logic to custom hooks
|
|
76
|
+
- Handle loading/error/empty states
|
|
77
|
+
|
|
78
|
+
**State Management**
|
|
79
|
+
- React Query for server state
|
|
80
|
+
- Zustand for UI state only
|
|
81
|
+
- Don't duplicate server state
|
|
82
|
+
|
|
83
|
+
**API Calls**
|
|
84
|
+
```typescript
|
|
85
|
+
// services/api.ts
|
|
86
|
+
const api = {
|
|
87
|
+
users: {
|
|
88
|
+
getAll: () => fetch<User[]>('/api/users/'),
|
|
89
|
+
getById: (id: number) => fetch<User>(`/api/users/${id}/`),
|
|
90
|
+
create: (data: CreateUserInput) => post<User>('/api/users/', data),
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Backend Standards
|
|
96
|
+
|
|
97
|
+
**Views**
|
|
98
|
+
- Use DRF ViewSets for CRUD
|
|
99
|
+
- Apply proper permissions
|
|
100
|
+
- Return appropriate status codes
|
|
101
|
+
- Filter querysets by user ownership
|
|
102
|
+
|
|
103
|
+
**Models**
|
|
104
|
+
- Add explicit `related_name`
|
|
105
|
+
- Include `__str__` method
|
|
106
|
+
- Index frequently queried fields
|
|
107
|
+
- Use model managers for complex queries
|
|
108
|
+
|
|
109
|
+
**Queries**
|
|
110
|
+
- Avoid N+1 with select_related/prefetch_related
|
|
111
|
+
- Use pagination for list endpoints
|
|
112
|
+
- Add database indexes
|
|
113
|
+
|
|
114
|
+
### Shared Patterns
|
|
115
|
+
|
|
116
|
+
**Authentication**
|
|
117
|
+
- JWT tokens in httpOnly cookies
|
|
118
|
+
- CSRF protection for state-changing requests
|
|
119
|
+
- Refresh tokens for long sessions
|
|
120
|
+
|
|
121
|
+
**Error Handling**
|
|
122
|
+
```typescript
|
|
123
|
+
// Frontend
|
|
124
|
+
try {
|
|
125
|
+
await api.users.create(data);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
if (error instanceof ApiError) {
|
|
128
|
+
showToast(error.message);
|
|
129
|
+
} else {
|
|
130
|
+
showToast('Something went wrong');
|
|
131
|
+
logger.error(error);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
# Backend
|
|
138
|
+
try:
|
|
139
|
+
user = create_user(data)
|
|
140
|
+
except ValidationError as e:
|
|
141
|
+
raise DRFValidationError(e.messages)
|
|
142
|
+
except IntegrityError:
|
|
143
|
+
raise DRFValidationError({'email': 'Email already exists'})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Testing Strategy
|
|
147
|
+
|
|
148
|
+
**Unit Tests**
|
|
149
|
+
- Frontend: Test hooks, utilities, complex components
|
|
150
|
+
- Backend: Test services, serializers, model methods
|
|
151
|
+
|
|
152
|
+
**Integration Tests**
|
|
153
|
+
- Backend: Test API endpoints with pytest
|
|
154
|
+
- Frontend: Test API integration with MSW
|
|
155
|
+
|
|
156
|
+
**E2E Tests (Playwright)**
|
|
157
|
+
- Test critical user flows
|
|
158
|
+
- Use TDD workflow (test first, then implement)
|
|
159
|
+
- Include SCENARIO/EXPECTED/FAILURE documentation
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
test('user can complete checkout', async ({ page }) => {
|
|
163
|
+
/**
|
|
164
|
+
* SCENARIO: Logged-in user adds item and completes checkout
|
|
165
|
+
* EXPECTED: Order confirmation shown, order in database
|
|
166
|
+
* FAILURE: Stuck at any step, error shown
|
|
167
|
+
*/
|
|
168
|
+
await loginAsTestUser(page);
|
|
169
|
+
await page.goto('/products/1');
|
|
170
|
+
await page.click('[data-testid="add-to-cart"]');
|
|
171
|
+
await page.click('[data-testid="checkout"]');
|
|
172
|
+
await page.fill('[name="address"]', '123 Main St');
|
|
173
|
+
await page.click('[data-testid="place-order"]');
|
|
174
|
+
|
|
175
|
+
await expect(page.getByText('Order Confirmed')).toBeVisible();
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## File Structure
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
project/
|
|
183
|
+
├── frontend/
|
|
184
|
+
│ ├── src/
|
|
185
|
+
│ │ ├── components/
|
|
186
|
+
│ │ ├── hooks/
|
|
187
|
+
│ │ ├── pages/
|
|
188
|
+
│ │ ├── services/
|
|
189
|
+
│ │ ├── stores/
|
|
190
|
+
│ │ └── types/
|
|
191
|
+
│ └── e2e/ # Playwright tests
|
|
192
|
+
├── backend/
|
|
193
|
+
│ ├── config/ # Django settings
|
|
194
|
+
│ ├── apps/
|
|
195
|
+
│ │ ├── users/
|
|
196
|
+
│ │ └── orders/
|
|
197
|
+
│ └── tests/
|
|
198
|
+
├── docker-compose.yml
|
|
199
|
+
└── Makefile
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Environment Variables
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# .env.example
|
|
206
|
+
|
|
207
|
+
# Database
|
|
208
|
+
DATABASE_URL=postgresql://user:pass@localhost:5432/dbname
|
|
209
|
+
|
|
210
|
+
# Django
|
|
211
|
+
SECRET_KEY=your-secret-key
|
|
212
|
+
DEBUG=True
|
|
213
|
+
ALLOWED_HOSTS=localhost,127.0.0.1
|
|
214
|
+
|
|
215
|
+
# Frontend
|
|
216
|
+
VITE_API_URL=http://localhost:8000/api
|
|
217
|
+
|
|
218
|
+
# Redis
|
|
219
|
+
REDIS_URL=redis://localhost:6379
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Pre-commit Hooks
|
|
223
|
+
This project uses thrivekit hooks. Run `/vibe-check` before committing.
|
|
224
|
+
|
|
225
|
+
## Common Commands
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# Development
|
|
229
|
+
make up # Start all services (Docker)
|
|
230
|
+
make frontend # Run frontend dev server
|
|
231
|
+
make logs # View backend logs
|
|
232
|
+
|
|
233
|
+
# Database
|
|
234
|
+
make migrate # Run migrations
|
|
235
|
+
make makemigrations # Create migrations
|
|
236
|
+
|
|
237
|
+
# Testing
|
|
238
|
+
make test # Run all tests
|
|
239
|
+
make test-backend # Run backend tests
|
|
240
|
+
make test-frontend # Run frontend tests
|
|
241
|
+
make test-e2e # Run Playwright E2E tests
|
|
242
|
+
|
|
243
|
+
# Code Quality
|
|
244
|
+
make lint # Run all linters
|
|
245
|
+
make format # Format all code
|
|
246
|
+
make typecheck # Check TypeScript types
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Workflow
|
|
250
|
+
|
|
251
|
+
1. **Idea** - Run `/idea "feature description"` to brainstorm
|
|
252
|
+
2. **Approve** - Review the idea file, then approve
|
|
253
|
+
3. **PRD** - Review generated stories in `.ralph/prd.json`
|
|
254
|
+
4. **Run** - Execute `ralph run` for autonomous coding
|
|
255
|
+
5. **Audit** - Run `/vibe-check` before shipping
|
|
256
|
+
6. **Commit** - Pre-commit hooks catch remaining issues
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# Project Instructions for AI Coding Agents
|
|
2
|
+
|
|
3
|
+
## Naming Conventions
|
|
4
|
+
- **Files**: `kebab-case.ts` — e.g., `user-service.ts`, `auth-middleware.ts`
|
|
5
|
+
- **Functions/Variables**: `camelCase` — e.g., `getUserById`, `isValid`
|
|
6
|
+
- **Classes/Interfaces/Types**: `PascalCase` — e.g., `UserService`, `CreateUserInput`
|
|
7
|
+
- **Constants**: `SCREAMING_SNAKE` — e.g., `MAX_RETRIES`, `DEFAULT_PORT`
|
|
8
|
+
- **Database tables**: `snake_case` — e.g., `user_sessions` (Prisma converts to camelCase)
|
|
9
|
+
- **API endpoints**: `kebab-case` — e.g., `/api/user-profile`, `/api/auth/sign-in`
|
|
10
|
+
|
|
11
|
+
## Tech Stack
|
|
12
|
+
- **Runtime**: Node.js 20+
|
|
13
|
+
- **Framework**: Express.js / Fastify
|
|
14
|
+
- **Language**: TypeScript
|
|
15
|
+
- **Database**: PostgreSQL with Prisma
|
|
16
|
+
- **Testing**: Jest, Supertest
|
|
17
|
+
|
|
18
|
+
## Code Quality Standards
|
|
19
|
+
|
|
20
|
+
### TypeScript
|
|
21
|
+
- Enable strict mode in tsconfig
|
|
22
|
+
- Never use `any` - define proper types
|
|
23
|
+
- Use `unknown` for truly dynamic data
|
|
24
|
+
- Export types from dedicated files
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// types/user.ts
|
|
28
|
+
export interface User {
|
|
29
|
+
id: string;
|
|
30
|
+
email: string;
|
|
31
|
+
name: string;
|
|
32
|
+
createdAt: Date;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface CreateUserInput {
|
|
36
|
+
email: string;
|
|
37
|
+
name: string;
|
|
38
|
+
password: string;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### API Endpoints
|
|
43
|
+
- Use consistent response format
|
|
44
|
+
- Return appropriate HTTP status codes
|
|
45
|
+
- Validate all input with Zod or Joi
|
|
46
|
+
- Handle errors with middleware
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// Consistent response format
|
|
50
|
+
interface ApiResponse<T> {
|
|
51
|
+
success: boolean;
|
|
52
|
+
data?: T;
|
|
53
|
+
error?: {
|
|
54
|
+
code: string;
|
|
55
|
+
message: string;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Controller
|
|
60
|
+
export async function createUser(req: Request, res: Response) {
|
|
61
|
+
const input = createUserSchema.parse(req.body);
|
|
62
|
+
|
|
63
|
+
const user = await userService.create(input);
|
|
64
|
+
|
|
65
|
+
res.status(201).json({
|
|
66
|
+
success: true,
|
|
67
|
+
data: user,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Error Handling
|
|
73
|
+
- Use custom error classes
|
|
74
|
+
- Centralize error handling in middleware
|
|
75
|
+
- Log errors with context
|
|
76
|
+
- Never expose stack traces to clients
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// errors.ts
|
|
80
|
+
export class AppError extends Error {
|
|
81
|
+
constructor(
|
|
82
|
+
public statusCode: number,
|
|
83
|
+
public code: string,
|
|
84
|
+
message: string
|
|
85
|
+
) {
|
|
86
|
+
super(message);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export class NotFoundError extends AppError {
|
|
91
|
+
constructor(resource: string) {
|
|
92
|
+
super(404, 'NOT_FOUND', `${resource} not found`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// middleware/errorHandler.ts
|
|
97
|
+
export function errorHandler(
|
|
98
|
+
err: Error,
|
|
99
|
+
req: Request,
|
|
100
|
+
res: Response,
|
|
101
|
+
next: NextFunction
|
|
102
|
+
) {
|
|
103
|
+
logger.error('Request error', { error: err, path: req.path });
|
|
104
|
+
|
|
105
|
+
if (err instanceof AppError) {
|
|
106
|
+
return res.status(err.statusCode).json({
|
|
107
|
+
success: false,
|
|
108
|
+
error: { code: err.code, message: err.message },
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Don't expose internal errors
|
|
113
|
+
res.status(500).json({
|
|
114
|
+
success: false,
|
|
115
|
+
error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' },
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Database (Prisma)
|
|
121
|
+
- Use transactions for multi-step operations
|
|
122
|
+
- Select only needed fields
|
|
123
|
+
- Use pagination for list endpoints
|
|
124
|
+
- Add indexes in schema
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Good - select only needed fields
|
|
128
|
+
const users = await prisma.user.findMany({
|
|
129
|
+
select: {
|
|
130
|
+
id: true,
|
|
131
|
+
email: true,
|
|
132
|
+
name: true,
|
|
133
|
+
},
|
|
134
|
+
take: 20,
|
|
135
|
+
skip: page * 20,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Transaction
|
|
139
|
+
await prisma.$transaction(async (tx) => {
|
|
140
|
+
const order = await tx.order.create({ data: orderData });
|
|
141
|
+
await tx.inventory.decrement({ where: { productId }, data: { quantity } });
|
|
142
|
+
return order;
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Async/Await
|
|
147
|
+
- Always use try/catch or error middleware
|
|
148
|
+
- Use Promise.all for parallel operations
|
|
149
|
+
- Handle promise rejections
|
|
150
|
+
- Avoid callback-style code
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// Parallel operations
|
|
154
|
+
const [user, orders, notifications] = await Promise.all([
|
|
155
|
+
userService.getById(userId),
|
|
156
|
+
orderService.getByUser(userId),
|
|
157
|
+
notificationService.getUnread(userId),
|
|
158
|
+
]);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Security
|
|
162
|
+
- Validate all input
|
|
163
|
+
- Use parameterized queries (Prisma does this)
|
|
164
|
+
- Set security headers (helmet)
|
|
165
|
+
- Rate limit sensitive endpoints
|
|
166
|
+
- Never log sensitive data
|
|
167
|
+
|
|
168
|
+
### Logging
|
|
169
|
+
- Use structured logging (pino, winston)
|
|
170
|
+
- Include request ID for tracing
|
|
171
|
+
- Log appropriate levels
|
|
172
|
+
- Never log passwords or tokens
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
logger.info('User created', {
|
|
176
|
+
userId: user.id,
|
|
177
|
+
email: user.email,
|
|
178
|
+
// Never log: password, token, etc.
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Testing
|
|
183
|
+
- Unit test business logic
|
|
184
|
+
- Integration test API endpoints
|
|
185
|
+
- Mock external services
|
|
186
|
+
- Use test database
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
describe('POST /api/users', () => {
|
|
190
|
+
it('creates a user with valid input', async () => {
|
|
191
|
+
const response = await request(app)
|
|
192
|
+
.post('/api/users')
|
|
193
|
+
.send({ email: 'test@example.com', name: 'Test', password: 'secure123' });
|
|
194
|
+
|
|
195
|
+
expect(response.status).toBe(201);
|
|
196
|
+
expect(response.body.success).toBe(true);
|
|
197
|
+
expect(response.body.data.email).toBe('test@example.com');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('returns 400 for invalid email', async () => {
|
|
201
|
+
const response = await request(app)
|
|
202
|
+
.post('/api/users')
|
|
203
|
+
.send({ email: 'invalid', name: 'Test', password: 'secure123' });
|
|
204
|
+
|
|
205
|
+
expect(response.status).toBe(400);
|
|
206
|
+
expect(response.body.error.code).toBe('VALIDATION_ERROR');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## File Structure
|
|
212
|
+
```
|
|
213
|
+
src/
|
|
214
|
+
├── controllers/ # Route handlers
|
|
215
|
+
├── services/ # Business logic
|
|
216
|
+
├── repositories/ # Database access
|
|
217
|
+
├── middleware/ # Express middleware
|
|
218
|
+
├── types/ # TypeScript types
|
|
219
|
+
├── utils/ # Helper functions
|
|
220
|
+
├── routes/ # Route definitions
|
|
221
|
+
└── index.ts # App entry point
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Environment Variables
|
|
225
|
+
```typescript
|
|
226
|
+
// config.ts
|
|
227
|
+
export const config = {
|
|
228
|
+
port: process.env.PORT || 3000,
|
|
229
|
+
databaseUrl: process.env.DATABASE_URL!,
|
|
230
|
+
jwtSecret: process.env.JWT_SECRET!,
|
|
231
|
+
nodeEnv: process.env.NODE_ENV || 'development',
|
|
232
|
+
};
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Pre-commit Hooks
|
|
236
|
+
This project uses thrivekit hooks. Run `/vibe-check` before committing.
|
|
237
|
+
|
|
238
|
+
## Common Commands
|
|
239
|
+
```bash
|
|
240
|
+
npm run dev # Start dev server with hot reload
|
|
241
|
+
npm run build # Build TypeScript
|
|
242
|
+
npm start # Start production server
|
|
243
|
+
npm test # Run tests
|
|
244
|
+
npm run lint # Run linter
|
|
245
|
+
npm run db:migrate # Run Prisma migrations
|
|
246
|
+
```
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Project Instructions for AI Coding Agents
|
|
2
|
+
|
|
3
|
+
## Naming Conventions
|
|
4
|
+
- **Files**: `PascalCase.tsx` for components, `camelCase.ts` for utilities — e.g., `UserProfile.tsx`, `useAuth.ts`
|
|
5
|
+
- **Components**: `PascalCase` — e.g., `UserProfile`, `AuthProvider`
|
|
6
|
+
- **Hooks**: `useCamelCase` — e.g., `useAuth`, `useUserData`
|
|
7
|
+
- **Functions/Variables**: `camelCase` — e.g., `handleSubmit`, `isLoading`
|
|
8
|
+
- **Types/Interfaces**: `PascalCase` — e.g., `UserProps`, `AuthState`
|
|
9
|
+
- **Constants**: `SCREAMING_SNAKE` — e.g., `API_BASE_URL`, `MAX_RETRIES`
|
|
10
|
+
- **CSS classes**: `kebab-case` (TailwindCSS utility classes are standard)
|
|
11
|
+
|
|
12
|
+
## Tech Stack
|
|
13
|
+
- **Frontend**: React 18, TypeScript, Vite
|
|
14
|
+
- **Styling**: TailwindCSS
|
|
15
|
+
- **State**: React Query for server state, Zustand for client state
|
|
16
|
+
- **Testing**: Vitest, React Testing Library, Playwright
|
|
17
|
+
|
|
18
|
+
## Code Quality Standards
|
|
19
|
+
|
|
20
|
+
### TypeScript
|
|
21
|
+
- **Never use `any`** - Create proper interfaces for all data
|
|
22
|
+
- Use strict mode (`"strict": true` in tsconfig)
|
|
23
|
+
- Prefer `interface` for object shapes, `type` for unions/intersections
|
|
24
|
+
- Use `unknown` instead of `any` when type is truly unknown
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// Bad
|
|
28
|
+
const data: any = await fetchUser();
|
|
29
|
+
|
|
30
|
+
// Good
|
|
31
|
+
interface User {
|
|
32
|
+
id: string;
|
|
33
|
+
email: string;
|
|
34
|
+
name: string;
|
|
35
|
+
}
|
|
36
|
+
const data: User = await fetchUser();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### React Components
|
|
40
|
+
- Use functional components with hooks
|
|
41
|
+
- Keep components small and focused (< 100 lines)
|
|
42
|
+
- Extract logic into custom hooks
|
|
43
|
+
- Use proper TypeScript types for props
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Good component structure
|
|
47
|
+
interface UserCardProps {
|
|
48
|
+
user: User;
|
|
49
|
+
onEdit: (user: User) => void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function UserCard({ user, onEdit }: UserCardProps) {
|
|
53
|
+
return (/* ... */);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### State Management
|
|
58
|
+
- Use React Query for server state (caching, refetching)
|
|
59
|
+
- Use Zustand for UI state only
|
|
60
|
+
- Keep state as close to usage as possible
|
|
61
|
+
- Don't duplicate server state in client state
|
|
62
|
+
|
|
63
|
+
### Error Handling
|
|
64
|
+
- Always handle loading, error, and empty states
|
|
65
|
+
- Use Error Boundaries for unexpected errors
|
|
66
|
+
- Show user-friendly error messages
|
|
67
|
+
- Log errors with context for debugging
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// Always handle all states
|
|
71
|
+
const { data, isLoading, error } = useQuery(['user'], fetchUser);
|
|
72
|
+
|
|
73
|
+
if (isLoading) return <Skeleton />;
|
|
74
|
+
if (error) return <ErrorMessage error={error} />;
|
|
75
|
+
if (!data) return <EmptyState />;
|
|
76
|
+
|
|
77
|
+
return <UserProfile user={data} />;
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Styling with TailwindCSS
|
|
81
|
+
- Use Tailwind utility classes
|
|
82
|
+
- Extract repeated patterns to components, not @apply
|
|
83
|
+
- Use design system tokens (colors, spacing)
|
|
84
|
+
- Keep className strings readable
|
|
85
|
+
|
|
86
|
+
### Testing
|
|
87
|
+
- Write tests for business logic and user interactions
|
|
88
|
+
- Use React Testing Library (test behavior, not implementation)
|
|
89
|
+
- Mock external dependencies
|
|
90
|
+
- Use Playwright for critical user flows
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// Test user behavior, not implementation
|
|
94
|
+
test('user can submit form', async () => {
|
|
95
|
+
render(<ContactForm />);
|
|
96
|
+
|
|
97
|
+
await userEvent.type(screen.getByLabelText(/email/i), 'test@example.com');
|
|
98
|
+
await userEvent.click(screen.getByRole('button', { name: /submit/i }));
|
|
99
|
+
|
|
100
|
+
expect(screen.getByText(/thanks/i)).toBeInTheDocument();
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## File Structure
|
|
105
|
+
```
|
|
106
|
+
src/
|
|
107
|
+
├── components/ # Reusable UI components
|
|
108
|
+
│ ├── ui/ # Design system primitives
|
|
109
|
+
│ └── features/ # Feature-specific components
|
|
110
|
+
├── hooks/ # Custom React hooks
|
|
111
|
+
├── pages/ # Page components (routes)
|
|
112
|
+
├── services/ # API calls and external services
|
|
113
|
+
├── stores/ # Zustand stores
|
|
114
|
+
├── types/ # TypeScript types/interfaces
|
|
115
|
+
└── utils/ # Helper functions
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Environment Variables
|
|
119
|
+
- Use `import.meta.env.VITE_*` for client-side env vars
|
|
120
|
+
- Never commit real secrets
|
|
121
|
+
- Provide defaults for local development
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000/api';
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Pre-commit Hooks
|
|
128
|
+
This project uses thrivekit hooks. Run `/vibe-check` before committing.
|
|
129
|
+
|
|
130
|
+
## Common Commands
|
|
131
|
+
```bash
|
|
132
|
+
npm run dev # Start dev server
|
|
133
|
+
npm run build # Build for production
|
|
134
|
+
npm test # Run unit tests
|
|
135
|
+
npm run test:e2e # Run E2E tests
|
|
136
|
+
npm run lint # Run linter
|
|
137
|
+
npm run typecheck # Check types
|
|
138
|
+
```
|