@malamute/ai-rules 1.0.0 → 1.2.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 +270 -121
- package/bin/cli.js +5 -2
- package/configs/_shared/.claude/rules/conventions/documentation.md +324 -0
- package/configs/_shared/.claude/rules/conventions/git.md +265 -0
- package/configs/_shared/.claude/rules/{performance.md → conventions/performance.md} +1 -1
- package/configs/_shared/.claude/rules/conventions/principles.md +334 -0
- package/configs/_shared/.claude/rules/devops/ci-cd.md +262 -0
- package/configs/_shared/.claude/rules/devops/docker.md +275 -0
- package/configs/_shared/.claude/rules/devops/nx.md +194 -0
- package/configs/_shared/.claude/rules/domain/backend/api-design.md +203 -0
- package/configs/_shared/.claude/rules/lang/csharp/async.md +220 -0
- package/configs/_shared/.claude/rules/lang/csharp/csharp.md +314 -0
- package/configs/_shared/.claude/rules/lang/csharp/linq.md +210 -0
- package/configs/_shared/.claude/rules/lang/python/async.md +337 -0
- package/configs/_shared/.claude/rules/lang/python/celery.md +476 -0
- package/configs/_shared/.claude/rules/lang/python/config.md +339 -0
- package/configs/{python/.claude/rules → _shared/.claude/rules/lang/python}/database/sqlalchemy.md +6 -1
- package/configs/_shared/.claude/rules/lang/python/deployment.md +523 -0
- package/configs/_shared/.claude/rules/lang/python/error-handling.md +330 -0
- package/configs/_shared/.claude/rules/lang/python/migrations.md +421 -0
- package/configs/_shared/.claude/rules/lang/python/python.md +172 -0
- package/configs/_shared/.claude/rules/lang/python/repository.md +383 -0
- package/configs/{python/.claude/rules → _shared/.claude/rules/lang/python}/testing.md +2 -69
- package/configs/_shared/.claude/rules/lang/typescript/async.md +447 -0
- package/configs/_shared/.claude/rules/lang/typescript/generics.md +356 -0
- package/configs/_shared/.claude/rules/lang/typescript/typescript.md +212 -0
- package/configs/_shared/.claude/rules/quality/error-handling.md +48 -0
- package/configs/_shared/.claude/rules/quality/logging.md +45 -0
- package/configs/_shared/.claude/rules/quality/observability.md +240 -0
- package/configs/_shared/.claude/rules/quality/testing-patterns.md +65 -0
- package/configs/_shared/.claude/rules/security/secrets-management.md +222 -0
- package/configs/_shared/.claude/skills/analysis/explore/SKILL.md +257 -0
- package/configs/_shared/.claude/skills/analysis/security-audit/SKILL.md +184 -0
- package/configs/_shared/.claude/skills/dev/api-endpoint/SKILL.md +126 -0
- package/configs/_shared/.claude/{commands/generate-tests.md → skills/dev/generate-tests/SKILL.md} +6 -0
- package/configs/_shared/.claude/{commands/fix-issue.md → skills/git/fix-issue/SKILL.md} +6 -0
- package/configs/_shared/.claude/{commands/review-pr.md → skills/git/review-pr/SKILL.md} +6 -0
- package/configs/_shared/.claude/skills/infra/deploy/SKILL.md +139 -0
- package/configs/_shared/.claude/skills/infra/docker/SKILL.md +95 -0
- package/configs/_shared/.claude/skills/infra/migration/SKILL.md +158 -0
- package/configs/_shared/.claude/skills/nx/nx-affected/SKILL.md +72 -0
- package/configs/_shared/.claude/skills/nx/nx-lib/SKILL.md +375 -0
- package/configs/_shared/CLAUDE.md +52 -149
- package/configs/angular/.claude/rules/{components.md → core/components.md} +69 -15
- package/configs/angular/.claude/rules/core/resource.md +285 -0
- package/configs/angular/.claude/rules/core/signals.md +323 -0
- package/configs/angular/.claude/rules/http.md +338 -0
- package/configs/angular/.claude/rules/routing.md +291 -0
- package/configs/angular/.claude/rules/ssr.md +312 -0
- package/configs/angular/.claude/rules/state/signal-store.md +408 -0
- package/configs/angular/.claude/rules/{state.md → state/state.md} +2 -2
- package/configs/angular/.claude/rules/testing.md +7 -7
- package/configs/angular/.claude/rules/ui/aria.md +422 -0
- package/configs/angular/.claude/rules/ui/forms.md +424 -0
- package/configs/angular/.claude/rules/ui/pipes-directives.md +335 -0
- package/configs/angular/.claude/settings.json +1 -0
- package/configs/angular/.claude/skills/ngrx-slice/SKILL.md +362 -0
- package/configs/angular/.claude/skills/signal-store/SKILL.md +445 -0
- package/configs/angular/CLAUDE.md +24 -216
- package/configs/dotnet/.claude/rules/background-services.md +552 -0
- package/configs/dotnet/.claude/rules/configuration.md +426 -0
- package/configs/dotnet/.claude/rules/ddd.md +447 -0
- package/configs/dotnet/.claude/rules/dependency-injection.md +343 -0
- package/configs/dotnet/.claude/rules/mediatr.md +320 -0
- package/configs/dotnet/.claude/rules/middleware.md +489 -0
- package/configs/dotnet/.claude/rules/result-pattern.md +363 -0
- package/configs/dotnet/.claude/rules/validation.md +388 -0
- package/configs/dotnet/.claude/settings.json +21 -3
- package/configs/dotnet/CLAUDE.md +53 -286
- package/configs/fastapi/.claude/rules/background-tasks.md +254 -0
- package/configs/fastapi/.claude/rules/dependencies.md +170 -0
- package/configs/{python → fastapi}/.claude/rules/fastapi.md +61 -1
- package/configs/fastapi/.claude/rules/lifespan.md +274 -0
- package/configs/fastapi/.claude/rules/middleware.md +229 -0
- package/configs/fastapi/.claude/rules/pydantic.md +433 -0
- package/configs/fastapi/.claude/rules/responses.md +251 -0
- package/configs/fastapi/.claude/rules/routers.md +202 -0
- package/configs/fastapi/.claude/rules/security.md +222 -0
- package/configs/fastapi/.claude/rules/testing.md +251 -0
- package/configs/fastapi/.claude/rules/websockets.md +298 -0
- package/configs/fastapi/.claude/settings.json +33 -0
- package/configs/fastapi/CLAUDE.md +144 -0
- package/configs/flask/.claude/rules/blueprints.md +208 -0
- package/configs/flask/.claude/rules/cli.md +285 -0
- package/configs/flask/.claude/rules/configuration.md +281 -0
- package/configs/flask/.claude/rules/context.md +238 -0
- package/configs/flask/.claude/rules/error-handlers.md +278 -0
- package/configs/flask/.claude/rules/extensions.md +278 -0
- package/configs/flask/.claude/rules/flask.md +171 -0
- package/configs/flask/.claude/rules/marshmallow.md +206 -0
- package/configs/flask/.claude/rules/security.md +267 -0
- package/configs/flask/.claude/rules/testing.md +284 -0
- package/configs/flask/.claude/settings.json +33 -0
- package/configs/flask/CLAUDE.md +166 -0
- package/configs/nestjs/.claude/rules/common-patterns.md +300 -0
- package/configs/nestjs/.claude/rules/filters.md +376 -0
- package/configs/nestjs/.claude/rules/interceptors.md +317 -0
- package/configs/nestjs/.claude/rules/middleware.md +321 -0
- package/configs/nestjs/.claude/rules/modules.md +26 -0
- package/configs/nestjs/.claude/rules/pipes.md +351 -0
- package/configs/nestjs/.claude/rules/websockets.md +451 -0
- package/configs/nestjs/.claude/settings.json +16 -2
- package/configs/nestjs/CLAUDE.md +57 -215
- package/configs/nextjs/.claude/rules/api-routes.md +358 -0
- package/configs/nextjs/.claude/rules/authentication.md +355 -0
- package/configs/nextjs/.claude/rules/components.md +52 -0
- package/configs/nextjs/.claude/rules/data-fetching.md +249 -0
- package/configs/nextjs/.claude/rules/database.md +400 -0
- package/configs/nextjs/.claude/rules/middleware.md +303 -0
- package/configs/nextjs/.claude/rules/routing.md +324 -0
- package/configs/nextjs/.claude/rules/seo.md +350 -0
- package/configs/nextjs/.claude/rules/server-actions.md +353 -0
- package/configs/nextjs/.claude/rules/state/zustand.md +6 -6
- package/configs/nextjs/.claude/settings.json +5 -0
- package/configs/nextjs/CLAUDE.md +69 -331
- package/package.json +23 -9
- package/src/cli.js +220 -0
- package/src/config.js +29 -0
- package/src/index.js +13 -0
- package/src/installer.js +361 -0
- package/src/merge.js +116 -0
- package/src/tech-config.json +29 -0
- package/src/utils.js +96 -0
- package/configs/python/.claude/rules/flask.md +0 -332
- package/configs/python/.claude/settings.json +0 -18
- package/configs/python/CLAUDE.md +0 -273
- package/src/install.js +0 -315
- /package/configs/_shared/.claude/rules/{accessibility.md → domain/frontend/accessibility.md} +0 -0
- /package/configs/_shared/.claude/rules/{security.md → security/security.md} +0 -0
- /package/configs/_shared/.claude/skills/{debug → dev/debug}/SKILL.md +0 -0
- /package/configs/_shared/.claude/skills/{learning → dev/learning}/SKILL.md +0 -0
- /package/configs/_shared/.claude/skills/{spec → dev/spec}/SKILL.md +0 -0
- /package/configs/_shared/.claude/skills/{review → git/review}/SKILL.md +0 -0
package/configs/nextjs/CLAUDE.md
CHANGED
|
@@ -9,368 +9,106 @@
|
|
|
9
9
|
- TypeScript strict mode
|
|
10
10
|
- Nx monorepo
|
|
11
11
|
|
|
12
|
-
## Architecture - Nx
|
|
12
|
+
## Architecture - Nx
|
|
13
13
|
|
|
14
14
|
```
|
|
15
|
-
apps/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
products/
|
|
24
|
-
page.tsx
|
|
25
|
-
_components/
|
|
26
|
-
layout.tsx
|
|
27
|
-
error.tsx
|
|
28
|
-
loading.tsx
|
|
15
|
+
apps/[app-name]/app/ # App Router
|
|
16
|
+
(routes)/ # Route groups (not in URL)
|
|
17
|
+
users/
|
|
18
|
+
page.tsx # /users
|
|
19
|
+
_components/ # Private, co-located
|
|
20
|
+
layout.tsx
|
|
21
|
+
error.tsx
|
|
22
|
+
loading.tsx
|
|
29
23
|
|
|
30
|
-
libs/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
util/ # Helpers
|
|
36
|
-
|
|
37
|
-
shared/
|
|
38
|
-
ui/ # Design system components
|
|
39
|
-
util/ # Shared utilities
|
|
24
|
+
libs/[domain]/
|
|
25
|
+
feature/ # Feature logic
|
|
26
|
+
ui/ # Presentational components
|
|
27
|
+
data-access/ # API, server actions
|
|
28
|
+
util/ # Helpers
|
|
40
29
|
```
|
|
41
30
|
|
|
42
31
|
### Folder Conventions
|
|
43
32
|
|
|
44
33
|
| Pattern | Meaning |
|
|
45
|
-
|
|
46
|
-
| `_folder/` | Private - not a route
|
|
47
|
-
| `(folder)/` | Route group - organizational
|
|
34
|
+
|---------|--------- |
|
|
35
|
+
| `_folder/` | Private - co-located, not a route |
|
|
36
|
+
| `(folder)/` | Route group - organizational only |
|
|
48
37
|
| `[param]/` | Dynamic segment |
|
|
49
38
|
| `[...param]/` | Catch-all segment |
|
|
50
|
-
| `[[...param]]/` | Optional catch-all |
|
|
51
|
-
|
|
52
|
-
## React 19 / Next.js 15 - Core Principles
|
|
53
|
-
|
|
54
|
-
### Server Components by Default
|
|
55
|
-
|
|
56
|
-
Components are Server Components unless marked with `'use client'`.
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
// Server Component (default) - runs on server
|
|
60
|
-
// Can: fetch data, access DB, use secrets
|
|
61
|
-
// Cannot: use hooks, browser APIs, event handlers
|
|
62
|
-
export default async function UsersPage() {
|
|
63
|
-
const users = await fetchUsers();
|
|
64
|
-
return <UserList users={users} />;
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### Client Components
|
|
69
|
-
|
|
70
|
-
Add `'use client'` directive for interactivity:
|
|
71
|
-
|
|
72
|
-
```tsx
|
|
73
|
-
'use client';
|
|
74
|
-
|
|
75
|
-
// Client Component - runs in browser
|
|
76
|
-
// Can: use hooks, event handlers, browser APIs
|
|
77
|
-
// Cannot: directly access DB, use secrets
|
|
78
|
-
import { useState } from 'react';
|
|
79
|
-
|
|
80
|
-
export function SearchInput({ onSearch }: Props) {
|
|
81
|
-
const [query, setQuery] = useState('');
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<input
|
|
85
|
-
value={query}
|
|
86
|
-
onChange={(event) => setQuery(event.target.value)}
|
|
87
|
-
onKeyDown={(event) => event.key === 'Enter' && onSearch(query)}
|
|
88
|
-
/>
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### When to Use Client Components
|
|
94
|
-
|
|
95
|
-
| Use Client Component | Use Server Component |
|
|
96
|
-
|---------------------|---------------------|
|
|
97
|
-
| `useState`, `useEffect`, hooks | Data fetching |
|
|
98
|
-
| Event handlers (`onClick`, etc.) | Database access |
|
|
99
|
-
| Browser APIs | Sensitive operations |
|
|
100
|
-
| Interactive UI (forms, modals) | Static content |
|
|
101
|
-
|
|
102
|
-
## Data Fetching
|
|
103
|
-
|
|
104
|
-
### Server Components (Preferred)
|
|
105
|
-
|
|
106
|
-
```tsx
|
|
107
|
-
// app/users/page.tsx
|
|
108
|
-
async function getUsers(): Promise<User[]> {
|
|
109
|
-
const response = await fetch('https://api.example.com/users', {
|
|
110
|
-
cache: 'no-store', // Dynamic data
|
|
111
|
-
// cache: 'force-cache', // Static data (default)
|
|
112
|
-
// next: { revalidate: 60 }, // ISR - revalidate every 60s
|
|
113
|
-
});
|
|
114
|
-
return response.json();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export default async function UsersPage() {
|
|
118
|
-
const users = await getUsers();
|
|
119
|
-
|
|
120
|
-
return (
|
|
121
|
-
<ul>
|
|
122
|
-
{users.map((user) => (
|
|
123
|
-
<li key={user.id}>{user.name}</li>
|
|
124
|
-
))}
|
|
125
|
-
</ul>
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Server Actions (Mutations)
|
|
131
|
-
|
|
132
|
-
```tsx
|
|
133
|
-
// app/users/actions.ts
|
|
134
|
-
'use server';
|
|
135
|
-
|
|
136
|
-
import { revalidatePath } from 'next/cache';
|
|
137
|
-
|
|
138
|
-
export async function createUser(formData: FormData): Promise<void> {
|
|
139
|
-
const name = formData.get('name') as string;
|
|
140
|
-
|
|
141
|
-
await db.user.create({ data: { name } });
|
|
142
|
-
|
|
143
|
-
revalidatePath('/users');
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
```tsx
|
|
148
|
-
// app/users/_components/user-form.tsx
|
|
149
|
-
'use client';
|
|
150
|
-
|
|
151
|
-
import { createUser } from '../actions';
|
|
152
|
-
|
|
153
|
-
export function UserForm() {
|
|
154
|
-
return (
|
|
155
|
-
<form action={createUser}>
|
|
156
|
-
<input name="name" required />
|
|
157
|
-
<button type="submit">Create User</button>
|
|
158
|
-
</form>
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### React 19 Hooks for Data
|
|
164
|
-
|
|
165
|
-
```tsx
|
|
166
|
-
'use client';
|
|
167
|
-
|
|
168
|
-
import { useActionState, useOptimistic } from 'react';
|
|
169
39
|
|
|
170
|
-
|
|
171
|
-
const [state, formAction, isPending] = useActionState(createUser, initialState);
|
|
40
|
+
## Core Principles
|
|
172
41
|
|
|
173
|
-
|
|
174
|
-
const [optimisticItems, addOptimistic] = useOptimistic(
|
|
175
|
-
items,
|
|
176
|
-
(state, newItem) => [...state, newItem]
|
|
177
|
-
);
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## Component Patterns
|
|
181
|
-
|
|
182
|
-
### Page Components (Server)
|
|
183
|
-
|
|
184
|
-
```tsx
|
|
185
|
-
// app/users/page.tsx
|
|
186
|
-
import { UserList } from './_components/user-list';
|
|
187
|
-
import { getUsers } from '@/lib/api';
|
|
188
|
-
|
|
189
|
-
export default async function UsersPage() {
|
|
190
|
-
const users = await getUsers();
|
|
191
|
-
|
|
192
|
-
return (
|
|
193
|
-
<main>
|
|
194
|
-
<h1>Users</h1>
|
|
195
|
-
<UserList users={users} />
|
|
196
|
-
</main>
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### Interactive Components (Client)
|
|
202
|
-
|
|
203
|
-
```tsx
|
|
204
|
-
// app/users/_components/user-list.tsx
|
|
205
|
-
'use client';
|
|
42
|
+
### Server vs Client Components
|
|
206
43
|
|
|
207
|
-
|
|
208
|
-
|
|
44
|
+
| Server (default) | Client (`'use client'`) |
|
|
45
|
+
|------------------|-------------------------|
|
|
46
|
+
| Fetch data, access DB | useState, useEffect, hooks |
|
|
47
|
+
| Use secrets/env vars | Event handlers (onClick) |
|
|
48
|
+
| Static content | Browser APIs |
|
|
49
|
+
| No hooks/events | Interactive UI |
|
|
209
50
|
|
|
210
|
-
|
|
211
|
-
users: User[];
|
|
212
|
-
}
|
|
51
|
+
### Data Fetching
|
|
213
52
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return (
|
|
218
|
-
<ul>
|
|
219
|
-
{users.map((user) => (
|
|
220
|
-
<UserCard
|
|
221
|
-
key={user.id}
|
|
222
|
-
user={user}
|
|
223
|
-
isSelected={user.id === selectedId}
|
|
224
|
-
onSelect={() => setSelectedId(user.id)}
|
|
225
|
-
/>
|
|
226
|
-
))}
|
|
227
|
-
</ul>
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### Shared UI Components
|
|
233
|
-
|
|
234
|
-
```tsx
|
|
235
|
-
// libs/shared/ui/button.tsx
|
|
236
|
-
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
237
|
-
variant?: 'primary' | 'secondary';
|
|
238
|
-
isLoading?: boolean;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
export function Button({
|
|
242
|
-
variant = 'primary',
|
|
243
|
-
isLoading,
|
|
244
|
-
children,
|
|
245
|
-
disabled,
|
|
246
|
-
...props
|
|
247
|
-
}: ButtonProps) {
|
|
248
|
-
return (
|
|
249
|
-
<button
|
|
250
|
-
className={`btn btn-${variant}`}
|
|
251
|
-
disabled={disabled || isLoading}
|
|
252
|
-
{...props}
|
|
253
|
-
>
|
|
254
|
-
{isLoading ? 'Loading...' : children}
|
|
255
|
-
</button>
|
|
256
|
-
);
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
## Build & Commands
|
|
261
|
-
|
|
262
|
-
```bash
|
|
263
|
-
# Development
|
|
264
|
-
nx serve [app-name]
|
|
265
|
-
nx dev [app-name]
|
|
53
|
+
- **Read**: Server Components with `fetch()` or DB
|
|
54
|
+
- **Mutations**: Server Actions with `'use server'`
|
|
55
|
+
- **Revalidation**: `revalidatePath()` or `revalidateTag()`
|
|
266
56
|
|
|
267
|
-
|
|
268
|
-
nx build [app-name]
|
|
269
|
-
nx build [app-name] --configuration=production
|
|
57
|
+
### React 19 Hooks
|
|
270
58
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
nx affected -t test
|
|
275
|
-
|
|
276
|
-
# Lint
|
|
277
|
-
nx lint [project-name]
|
|
278
|
-
nx run-many -t lint
|
|
279
|
-
|
|
280
|
-
# Generate
|
|
281
|
-
nx g @nx/next:component [name] --project=[app]
|
|
282
|
-
nx g @nx/react:component [name] --project=[lib]
|
|
283
|
-
nx g @nx/next:page [name] --project=[app]
|
|
284
|
-
```
|
|
59
|
+
- `useActionState` - Form state + pending
|
|
60
|
+
- `useOptimistic` - Optimistic UI updates
|
|
61
|
+
- `use()` - Unwrap promises/context
|
|
285
62
|
|
|
286
63
|
## Code Style
|
|
287
64
|
|
|
288
|
-
### Component Files
|
|
289
|
-
|
|
290
65
|
- One component per file
|
|
291
|
-
- Named exports
|
|
292
|
-
- Default export only for
|
|
66
|
+
- Named exports for components
|
|
67
|
+
- Default export only for `page.tsx`, `layout.tsx`
|
|
68
|
+
- Files: `kebab-case.tsx`, Components: `PascalCase`
|
|
293
69
|
- Props interface above component
|
|
294
70
|
|
|
295
|
-
|
|
296
|
-
// Good
|
|
297
|
-
interface UserCardProps {
|
|
298
|
-
user: User;
|
|
299
|
-
onSelect: () => void;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
export function UserCard({ user, onSelect }: UserCardProps) {
|
|
303
|
-
return (/* ... */);
|
|
304
|
-
}
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
### Naming Conventions
|
|
308
|
-
|
|
309
|
-
| Element | Convention | Example |
|
|
310
|
-
|---------|------------|---------|
|
|
311
|
-
| Components | PascalCase | `UserCard` |
|
|
312
|
-
| Files | kebab-case | `user-card.tsx` |
|
|
313
|
-
| Hooks | camelCase with `use` | `useUserData` |
|
|
314
|
-
| Server Actions | camelCase | `createUser` |
|
|
315
|
-
| Route folders | kebab-case | `user-profile/` |
|
|
316
|
-
|
|
317
|
-
### Imports Order
|
|
71
|
+
### Naming
|
|
318
72
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
73
|
+
| Element | Convention |
|
|
74
|
+
|---------|------------|
|
|
75
|
+
| Components | `PascalCase` |
|
|
76
|
+
| Files | `kebab-case.tsx` |
|
|
77
|
+
| Hooks | `useCamelCase` |
|
|
78
|
+
| Server Actions | `camelCase` |
|
|
79
|
+
| Route folders | `kebab-case/` |
|
|
323
80
|
|
|
324
|
-
|
|
325
|
-
import { z } from 'zod';
|
|
81
|
+
### Error Handling
|
|
326
82
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
83
|
+
- `error.tsx` - Error boundary (must be client component)
|
|
84
|
+
- `loading.tsx` - Suspense loading state
|
|
85
|
+
- `not-found.tsx` - 404 page
|
|
330
86
|
|
|
331
|
-
|
|
332
|
-
import { UserCard } from './user-card';
|
|
87
|
+
## Commands
|
|
333
88
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
### Error Boundaries
|
|
341
|
-
|
|
342
|
-
```tsx
|
|
343
|
-
// app/users/error.tsx
|
|
344
|
-
'use client';
|
|
345
|
-
|
|
346
|
-
interface ErrorProps {
|
|
347
|
-
error: Error & { digest?: string };
|
|
348
|
-
reset: () => void;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
export default function Error({ error, reset }: ErrorProps) {
|
|
352
|
-
return (
|
|
353
|
-
<div>
|
|
354
|
-
<h2>Something went wrong!</h2>
|
|
355
|
-
<button onClick={reset}>Try again</button>
|
|
356
|
-
</div>
|
|
357
|
-
);
|
|
358
|
-
}
|
|
89
|
+
```bash
|
|
90
|
+
nx serve [app] # Dev server
|
|
91
|
+
nx build [app] --configuration=production
|
|
92
|
+
nx test [lib] # Unit tests
|
|
93
|
+
nx affected -t test # Test affected
|
|
94
|
+
nx e2e [app]-e2e # E2E tests
|
|
359
95
|
```
|
|
360
96
|
|
|
361
|
-
|
|
97
|
+
## Caching (Next.js 15)
|
|
362
98
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
99
|
+
- Default: `staleTime=0` - always fresh data on navigation
|
|
100
|
+
- Static routes cached, dynamic routes not cached
|
|
101
|
+
- Route segment config:
|
|
102
|
+
- `export const dynamic = 'force-dynamic'` - SSR
|
|
103
|
+
- `export const revalidate = 60` - ISR (seconds)
|
|
104
|
+
- `export const dynamic = 'force-static'` - SSG
|
|
105
|
+
- `"use cache"` directive for granular caching
|
|
106
|
+
- `fetch(url, { next: { revalidate: 60 } })` - per-request
|
|
369
107
|
|
|
370
108
|
## Performance
|
|
371
109
|
|
|
372
|
-
-
|
|
373
|
-
-
|
|
374
|
-
-
|
|
375
|
-
-
|
|
376
|
-
-
|
|
110
|
+
- Keep most UI as Server Components
|
|
111
|
+
- Add `'use client'` only for interactive "islands"
|
|
112
|
+
- `next/dynamic` for heavy client components
|
|
113
|
+
- Always use `next/image` and `next/link`
|
|
114
|
+
- Never `useEffect` for data fetching
|
package/package.json
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malamute/ai-rules",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Claude Code configuration boilerplates for Angular, Next.js, NestJS, .NET, Python and more",
|
|
5
|
-
"main": "src/
|
|
6
|
-
"bin":
|
|
7
|
-
"ai-rules": "./bin/cli.js"
|
|
8
|
-
},
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": "./bin/cli.js",
|
|
9
7
|
"scripts": {
|
|
10
|
-
"test": "
|
|
8
|
+
"test": "vitest run",
|
|
9
|
+
"test:watch": "vitest",
|
|
10
|
+
"test:coverage": "vitest run --coverage",
|
|
11
|
+
"lint": "eslint src bin",
|
|
12
|
+
"lint:rules": "node scripts/lint-rules.js",
|
|
13
|
+
"validate": "npm test && npm run lint:rules"
|
|
11
14
|
},
|
|
12
15
|
"keywords": [
|
|
13
16
|
"claude",
|
|
@@ -24,12 +27,16 @@
|
|
|
24
27
|
"python",
|
|
25
28
|
"fastapi"
|
|
26
29
|
],
|
|
27
|
-
"author": "",
|
|
30
|
+
"author": "Mehdi Chaabi",
|
|
28
31
|
"license": "MIT",
|
|
29
32
|
"repository": {
|
|
30
33
|
"type": "git",
|
|
31
|
-
"url": ""
|
|
34
|
+
"url": "git+https://github.com/SpaceMalamute/ai-rules.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/SpaceMalamute/ai-rules/issues"
|
|
32
38
|
},
|
|
39
|
+
"homepage": "https://github.com/SpaceMalamute/ai-rules#readme",
|
|
33
40
|
"files": [
|
|
34
41
|
"bin",
|
|
35
42
|
"src",
|
|
@@ -37,5 +44,12 @@
|
|
|
37
44
|
],
|
|
38
45
|
"engines": {
|
|
39
46
|
"node": ">=18.0.0"
|
|
40
|
-
}
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@eslint/js": "^9.39.2",
|
|
50
|
+
"eslint": "^9.39.2",
|
|
51
|
+
"husky": "^9.1.7",
|
|
52
|
+
"vitest": "^2.0.0"
|
|
53
|
+
},
|
|
54
|
+
"packageManager": "yarn@4.12.0"
|
|
41
55
|
}
|