@plazmodium/odin 0.3.3-beta → 0.3.5-beta

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.
Files changed (133) hide show
  1. package/README.md +25 -10
  2. package/builtin/ODIN.md +1067 -0
  3. package/builtin/agent-definitions/README.md +170 -0
  4. package/builtin/agent-definitions/_shared-context.md +377 -0
  5. package/builtin/agent-definitions/architect.md +627 -0
  6. package/builtin/agent-definitions/builder.md +713 -0
  7. package/builtin/agent-definitions/discovery.md +293 -0
  8. package/builtin/agent-definitions/documenter.md +238 -0
  9. package/builtin/agent-definitions/guardian.md +1049 -0
  10. package/builtin/agent-definitions/integrator.md +189 -0
  11. package/builtin/agent-definitions/planning.md +236 -0
  12. package/builtin/agent-definitions/product.md +405 -0
  13. package/builtin/agent-definitions/release.md +205 -0
  14. package/builtin/agent-definitions/reviewer.md +447 -0
  15. package/builtin/agent-definitions/watcher.md +402 -0
  16. package/builtin/skills/api/graphql/SKILL.md +548 -0
  17. package/builtin/skills/api/grpc/SKILL.md +554 -0
  18. package/builtin/skills/api/rest-api/SKILL.md +469 -0
  19. package/builtin/skills/api/trpc/SKILL.md +503 -0
  20. package/builtin/skills/architecture/clean-architecture/SKILL.md +141 -0
  21. package/builtin/skills/architecture/domain-driven-design/SKILL.md +129 -0
  22. package/builtin/skills/architecture/event-driven/SKILL.md +145 -0
  23. package/builtin/skills/architecture/microservices/SKILL.md +143 -0
  24. package/builtin/skills/architecture/tla-precheck/SKILL.md +171 -0
  25. package/builtin/skills/backend/golang-gin/SKILL.md +141 -0
  26. package/builtin/skills/backend/nodejs-express/SKILL.md +277 -0
  27. package/builtin/skills/backend/nodejs-fastify/SKILL.md +152 -0
  28. package/builtin/skills/backend/python-django/SKILL.md +128 -0
  29. package/builtin/skills/backend/python-fastapi/SKILL.md +140 -0
  30. package/builtin/skills/database/mongodb/SKILL.md +132 -0
  31. package/builtin/skills/database/postgresql/SKILL.md +120 -0
  32. package/builtin/skills/database/prisma-orm/SKILL.md +366 -0
  33. package/builtin/skills/database/redis/SKILL.md +140 -0
  34. package/builtin/skills/database/supabase/SKILL.md +416 -0
  35. package/builtin/skills/devops/aws/SKILL.md +382 -0
  36. package/builtin/skills/devops/docker/SKILL.md +359 -0
  37. package/builtin/skills/devops/github-actions/SKILL.md +435 -0
  38. package/builtin/skills/devops/kubernetes/SKILL.md +459 -0
  39. package/builtin/skills/devops/terraform/SKILL.md +453 -0
  40. package/builtin/skills/frontend/alpine-dev/SKILL.md +27 -0
  41. package/builtin/skills/frontend/angular-dev/SKILL.md +28 -0
  42. package/builtin/skills/frontend/astro-dev/SKILL.md +28 -0
  43. package/builtin/skills/frontend/htmx-dev/SKILL.md +28 -0
  44. package/builtin/skills/frontend/nextjs-dev/SKILL.md +470 -0
  45. package/builtin/skills/frontend/react-patterns/SKILL.md +166 -0
  46. package/builtin/skills/frontend/svelte-dev/SKILL.md +28 -0
  47. package/builtin/skills/frontend/tailwindcss/SKILL.md +131 -0
  48. package/builtin/skills/frontend/vuejs-dev/SKILL.md +28 -0
  49. package/builtin/skills/generic-dev/SKILL.md +307 -0
  50. package/builtin/skills/testing/cypress/SKILL.md +372 -0
  51. package/builtin/skills/testing/jest/SKILL.md +176 -0
  52. package/builtin/skills/testing/playwright/SKILL.md +341 -0
  53. package/builtin/skills/testing/unit-tests-eval-sdd/SKILL.md +73 -0
  54. package/builtin/skills/testing/unit-tests-sdd/SKILL.md +83 -0
  55. package/builtin/skills/testing/vitest/SKILL.md +249 -0
  56. package/dist/adapters/skills/filesystem.d.ts +1 -0
  57. package/dist/adapters/skills/filesystem.d.ts.map +1 -1
  58. package/dist/adapters/skills/filesystem.js +6 -18
  59. package/dist/adapters/skills/filesystem.js.map +1 -1
  60. package/dist/adapters/skills/types.d.ts +1 -0
  61. package/dist/adapters/skills/types.d.ts.map +1 -1
  62. package/dist/adapters/workflow-state/in-memory.d.ts +10 -2
  63. package/dist/adapters/workflow-state/in-memory.d.ts.map +1 -1
  64. package/dist/adapters/workflow-state/in-memory.js +98 -5
  65. package/dist/adapters/workflow-state/in-memory.js.map +1 -1
  66. package/dist/adapters/workflow-state/supabase.d.ts +8 -2
  67. package/dist/adapters/workflow-state/supabase.d.ts.map +1 -1
  68. package/dist/adapters/workflow-state/supabase.js +204 -0
  69. package/dist/adapters/workflow-state/supabase.js.map +1 -1
  70. package/dist/adapters/workflow-state/types.d.ts +15 -1
  71. package/dist/adapters/workflow-state/types.d.ts.map +1 -1
  72. package/dist/builtin-assets.d.ts +8 -0
  73. package/dist/builtin-assets.d.ts.map +1 -0
  74. package/dist/builtin-assets.js +90 -0
  75. package/dist/builtin-assets.js.map +1 -0
  76. package/dist/domain/skill-draft-validation.d.ts +18 -0
  77. package/dist/domain/skill-draft-validation.d.ts.map +1 -0
  78. package/dist/domain/skill-draft-validation.js +100 -0
  79. package/dist/domain/skill-draft-validation.js.map +1 -0
  80. package/dist/domain/skill-proposals.d.ts +11 -0
  81. package/dist/domain/skill-proposals.d.ts.map +1 -0
  82. package/dist/domain/skill-proposals.js +103 -0
  83. package/dist/domain/skill-proposals.js.map +1 -0
  84. package/dist/init.js +69 -11
  85. package/dist/init.js.map +1 -1
  86. package/dist/schemas.d.ts +39 -1
  87. package/dist/schemas.d.ts.map +1 -1
  88. package/dist/schemas.js +30 -1
  89. package/dist/schemas.js.map +1 -1
  90. package/dist/server.js +38 -2
  91. package/dist/server.js.map +1 -1
  92. package/dist/tools/apply-migrations.d.ts +10 -0
  93. package/dist/tools/apply-migrations.d.ts.map +1 -1
  94. package/dist/tools/apply-migrations.js +10 -26
  95. package/dist/tools/apply-migrations.js.map +1 -1
  96. package/dist/tools/capture-learning.d.ts.map +1 -1
  97. package/dist/tools/capture-learning.js +14 -1
  98. package/dist/tools/capture-learning.js.map +1 -1
  99. package/dist/tools/get-skill-proposal-queue.d.ts +5 -0
  100. package/dist/tools/get-skill-proposal-queue.d.ts.map +1 -0
  101. package/dist/tools/get-skill-proposal-queue.js +21 -0
  102. package/dist/tools/get-skill-proposal-queue.js.map +1 -0
  103. package/dist/tools/get-skill-proposals.d.ts +4 -0
  104. package/dist/tools/get-skill-proposals.d.ts.map +1 -0
  105. package/dist/tools/get-skill-proposals.js +11 -0
  106. package/dist/tools/get-skill-proposals.js.map +1 -0
  107. package/dist/tools/prepare-phase-context.d.ts.map +1 -1
  108. package/dist/tools/prepare-phase-context.js +5 -0
  109. package/dist/tools/prepare-phase-context.js.map +1 -1
  110. package/dist/tools/publish-skill-proposal.d.ts +5 -0
  111. package/dist/tools/publish-skill-proposal.d.ts.map +1 -0
  112. package/dist/tools/publish-skill-proposal.js +57 -0
  113. package/dist/tools/publish-skill-proposal.js.map +1 -0
  114. package/dist/tools/record-skill-proposal-decision.d.ts +4 -0
  115. package/dist/tools/record-skill-proposal-decision.d.ts.map +1 -0
  116. package/dist/tools/record-skill-proposal-decision.js +22 -0
  117. package/dist/tools/record-skill-proposal-decision.js.map +1 -0
  118. package/dist/tools/record-skill-proposal-draft.d.ts +5 -0
  119. package/dist/tools/record-skill-proposal-draft.d.ts.map +1 -0
  120. package/dist/tools/record-skill-proposal-draft.js +65 -0
  121. package/dist/tools/record-skill-proposal-draft.js.map +1 -0
  122. package/dist/tools/sync-skill-proposal-candidates.d.ts +5 -0
  123. package/dist/tools/sync-skill-proposal-candidates.d.ts.map +1 -0
  124. package/dist/tools/sync-skill-proposal-candidates.js +20 -0
  125. package/dist/tools/sync-skill-proposal-candidates.js.map +1 -0
  126. package/dist/types.d.ts +41 -0
  127. package/dist/types.d.ts.map +1 -1
  128. package/dist/types.js +2 -0
  129. package/dist/types.js.map +1 -1
  130. package/migrations/009_skill_proposal_candidates.sql +124 -0
  131. package/migrations/010_skill_proposals.sql +36 -0
  132. package/migrations/README.md +6 -0
  133. package/package.json +5 -3
@@ -0,0 +1,470 @@
1
+ ---
2
+ name: nextjs-dev
3
+ description: Next.js development — App Router, Server Components, Server Actions, caching, data fetching patterns, and deployment
4
+ category: frontend
5
+ version: "14.x - 16.x"
6
+ depends_on:
7
+ - react-patterns
8
+ compatible_with:
9
+ - tailwindcss
10
+ - supabase
11
+ - prisma-orm
12
+ - typescript
13
+ ---
14
+
15
+ # Next.js Development
16
+
17
+ ## Overview
18
+
19
+ Next.js 14+ with App Router provides Server Components by default, Server Actions for mutations, and streaming for progressive rendering. Next.js 16 introduces Cache Components (`use cache` directive) and makes request-bound APIs async. Prefer the App Router for all new projects.
20
+
21
+ ## Project Structure
22
+
23
+ ```text
24
+ app/
25
+ ├── layout.tsx # Root layout (wraps all pages)
26
+ ├── page.tsx # Home page (Server Component by default)
27
+ ├── error.tsx # Error boundary ('use client' required)
28
+ ├── not-found.tsx # 404 page
29
+ ├── loading.tsx # Loading skeleton (shown during streaming)
30
+ ├── globals.css # Global styles
31
+ ├── (admin)/ # Route group (no URL segment)
32
+ │ └── dashboard/
33
+ ├── _internal/ # Private folder (opted out of routing)
34
+ ├── features/
35
+ │ └── [id]/
36
+ │ └── page.tsx # Dynamic route
37
+ └── api/
38
+ └── route.ts # API route handler
39
+
40
+ components/
41
+ ├── ui/ # Primitives (button, card, etc.)
42
+ ├── layout/ # Sidebar, header, footer
43
+ └── shared/ # Reusable across pages
44
+
45
+ lib/
46
+ ├── data/ # Server-side data fetching functions
47
+ ├── actions/ # Server Actions ('use server')
48
+ ├── types/ # TypeScript interfaces
49
+ └── utils.ts # Formatting helpers
50
+ ```
51
+
52
+ **Route Groups**: Use parentheses (e.g., `(admin)`) to group routes without affecting the URL path.
53
+
54
+ **Private Folders**: Prefix with `_` (e.g., `_internal`) to opt out of routing and signal implementation details.
55
+
56
+ **Feature Folders**: For large apps, group by feature (e.g., `app/dashboard/`, `app/auth/`).
57
+
58
+ ## Core Patterns
59
+
60
+ ### Server Components (default)
61
+
62
+ ```typescript
63
+ // app/page.tsx — Server Component (no 'use client' directive)
64
+ export const dynamic = 'force-dynamic'; // Required when fetching from DB
65
+
66
+ import { getData } from '@/lib/data/my-data';
67
+
68
+ export default async function Page() {
69
+ const data = await getData(); // Runs on server only
70
+
71
+ return <div>{data.title}</div>;
72
+ }
73
+ ```
74
+
75
+ ### Client Components (opt-in)
76
+
77
+ ```typescript
78
+ // components/counter.tsx
79
+ 'use client'; // Required for interactivity, hooks, browser APIs
80
+
81
+ import { useState } from 'react';
82
+
83
+ export function Counter() {
84
+ const [count, setCount] = useState(0);
85
+ return <button onClick={() => setCount(count + 1)}>{count}</button>;
86
+ }
87
+ ```
88
+
89
+ ### Server Actions (mutations)
90
+
91
+ ```typescript
92
+ // lib/actions/my-actions.ts
93
+ 'use server';
94
+
95
+ import { revalidatePath } from 'next/cache';
96
+
97
+ export async function createItem(formData: FormData) {
98
+ const name = formData.get('name') as string;
99
+ // ... insert into DB
100
+ revalidatePath('/');
101
+ }
102
+ ```
103
+
104
+ ### Server-Only Data Fetching (Supabase pattern)
105
+
106
+ ```typescript
107
+ // lib/supabase.ts
108
+ import 'server-only'; // Prevents accidental client import
109
+
110
+ import { createClient } from '@supabase/supabase-js';
111
+
112
+ export function createServerClient() {
113
+ return createClient(
114
+ process.env.SUPABASE_URL!, // No NEXT_PUBLIC_ prefix
115
+ process.env.SUPABASE_SECRET_KEY!, // Secret key, server-only
116
+ {
117
+ auth: { autoRefreshToken: false, persistSession: false },
118
+ global: {
119
+ // CRITICAL: Bypass Next.js 14 fetch cache to prevent stale data.
120
+ // Without this, Supabase responses are cached by Next.js's Data Cache.
121
+ fetch: (input, init) =>
122
+ fetch(input, { ...init, cache: 'no-store' }),
123
+ },
124
+ }
125
+ );
126
+ }
127
+ ```
128
+
129
+ ## Server and Client Component Integration
130
+
131
+ **Never use `next/dynamic` with `{ ssr: false }` inside a Server Component.** This is not supported and will cause a build/runtime error.
132
+
133
+ **Correct Approach:**
134
+
135
+ 1. Move all client-only logic/UI into a dedicated Client Component (with `'use client'` at the top)
136
+ 2. Import and use that Client Component directly in the Server Component
137
+ 3. No need for `next/dynamic` — just import the Client Component normally
138
+
139
+ ```typescript
140
+ // Server Component
141
+ import DashboardNavbar from '@/components/DashboardNavbar';
142
+
143
+ export default async function DashboardPage() {
144
+ // ...server logic...
145
+ return (
146
+ <>
147
+ <DashboardNavbar /> {/* This is a Client Component */}
148
+ {/* ...rest of server-rendered page... */}
149
+ </>
150
+ );
151
+ }
152
+ ```
153
+
154
+ **Why**: Server Components cannot use client-only features or dynamic imports with SSR disabled. Client Components can be rendered inside Server Components, but not the other way around.
155
+
156
+ ## Next.js 16+ Async Request APIs
157
+
158
+ In Next.js 16, request-bound APIs are async in the App Router:
159
+
160
+ ```typescript
161
+ // Next.js 16+ — cookies, headers, draftMode are async
162
+ import { cookies, headers } from 'next/headers';
163
+
164
+ export default async function Page() {
165
+ const cookieStore = await cookies();
166
+ const headersList = await headers();
167
+ // ...
168
+ }
169
+ ```
170
+
171
+ **Route props may be Promises**: `params` and `searchParams` may be Promises in Server Components. Prefer awaiting them:
172
+
173
+ ```typescript
174
+ export default async function Page({
175
+ params,
176
+ }: {
177
+ params: Promise<{ id: string }>;
178
+ }) {
179
+ const { id } = await params;
180
+ // ...
181
+ }
182
+ ```
183
+
184
+ **Dynamic rendering**: Accessing request data (cookies/headers/searchParams) opts the route into dynamic behavior. Read them intentionally and isolate dynamic parts behind `Suspense` boundaries when appropriate.
185
+
186
+ ## API Routes (Route Handlers)
187
+
188
+ **Location**: Place API routes in `app/api/` (e.g., `app/api/users/route.ts`).
189
+
190
+ ```typescript
191
+ // app/api/users/route.ts
192
+ import { NextRequest, NextResponse } from 'next/server';
193
+
194
+ export async function GET(request: NextRequest) {
195
+ const { searchParams } = new URL(request.url);
196
+ const limit = searchParams.get('limit') ?? '10';
197
+
198
+ // ... fetch data
199
+ return NextResponse.json({ users: [] });
200
+ }
201
+
202
+ export async function POST(request: NextRequest) {
203
+ const body = await request.json();
204
+ // ... validate and create
205
+ return NextResponse.json({ id: 'new-id' }, { status: 201 });
206
+ }
207
+ ```
208
+
209
+ **Dynamic Segments**: Use `[param]` for dynamic routes (e.g., `app/api/users/[id]/route.ts`).
210
+
211
+ **Validation**: Always validate input with libraries like `zod`.
212
+
213
+ **Performance Note**: Do NOT call your own Route Handlers from Server Components (e.g., `fetch('/api/...')`). Extract shared logic into `lib/` modules and call directly to avoid extra server hops.
214
+
215
+ ## Auto-Refresh via Polling
216
+
217
+ When WebSocket-based realtime isn't available (e.g., Supabase Realtime requires paid onboarding), use polling with `router.refresh()` to re-fetch Server Component data without full page reload.
218
+
219
+ ### Architecture
220
+
221
+ ```text
222
+ RefreshProvider (layout.tsx) — React Context tracking polling state
223
+ └── PollingSubscription — Zero-UI Client Component, activates polling
224
+ └── usePollingRefresh — Hook: setInterval → router.refresh()
225
+ └── ConnectionStatus — Green dot "Auto-refresh" indicator
226
+ ```
227
+
228
+ ### Hook: usePollingRefresh
229
+
230
+ ```typescript
231
+ // lib/realtime/use-polling-refresh.ts
232
+ 'use client';
233
+
234
+ import { useEffect, useRef } from 'react';
235
+ import { useRouter } from 'next/navigation';
236
+
237
+ const DEFAULT_INTERVAL_MS = 5000;
238
+
239
+ export function usePollingRefresh(intervalMs = DEFAULT_INTERVAL_MS) {
240
+ const router = useRouter();
241
+ const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
242
+
243
+ useEffect(() => {
244
+ timerRef.current = setInterval(() => {
245
+ router.refresh(); // Re-fetches Server Component data
246
+ }, intervalMs);
247
+
248
+ return () => {
249
+ if (timerRef.current) clearInterval(timerRef.current);
250
+ };
251
+ }, [intervalMs, router]);
252
+ }
253
+ ```
254
+
255
+ ### Zero-UI Component (place as sibling in Server Component pages)
256
+
257
+ ```typescript
258
+ // components/polling-subscription.tsx
259
+ 'use client';
260
+
261
+ import { usePollingRefresh } from '@/lib/realtime/use-polling-refresh';
262
+
263
+ export function PollingSubscription({ intervalMs }: { intervalMs?: number }) {
264
+ usePollingRefresh(intervalMs);
265
+ return null; // Renders nothing — side effect only
266
+ }
267
+ ```
268
+
269
+ ### Usage in Server Component pages
270
+
271
+ ```typescript
272
+ // app/page.tsx
273
+ import { PollingSubscription } from '@/components/polling-subscription';
274
+ import { getData } from '@/lib/data/my-data';
275
+
276
+ export default async function Page() {
277
+ const data = await getData();
278
+
279
+ return (
280
+ <>
281
+ <PollingSubscription />
282
+ <div>{/* ...server-rendered content auto-refreshes every 5s... */}</div>
283
+ </>
284
+ );
285
+ }
286
+ ```
287
+
288
+ > **Why sibling, not wrapper?** Wrapping an `async` Server Component return with a `'use client'` component breaks Next.js module resolution for dynamic routes (`[id]`). Always place Client Components as siblings using `<> ... </>`.
289
+
290
+ ## Caching & Revalidation
291
+
292
+ ### Next.js 14.x (fetch cache)
293
+
294
+ Next.js 14 patches global `fetch` with `cache: 'force-cache'` by default. Override per-fetch or per-client to prevent stale data. See "Data Cache Gotcha" below.
295
+
296
+ ### Next.js 16.x (Cache Components)
297
+
298
+ Enable in `next.config.*`:
299
+
300
+ ```javascript
301
+ // next.config.mjs
302
+ export default {
303
+ cacheComponents: true,
304
+ };
305
+ ```
306
+
307
+ Use the `use cache` directive to opt a component/function into caching:
308
+
309
+ ```typescript
310
+ 'use cache';
311
+
312
+ export async function getCachedData() {
313
+ // This result will be cached
314
+ return await fetchExpensiveData();
315
+ }
316
+ ```
317
+
318
+ **Cache tagging and lifetimes**:
319
+
320
+ ```typescript
321
+ import { cacheTag, cacheLife } from 'next/cache';
322
+
323
+ export async function getProducts() {
324
+ 'use cache';
325
+ cacheTag('products'); // Associate with tag
326
+ cacheLife('hours'); // Set cache lifetime
327
+ return await fetchProducts();
328
+ }
329
+ ```
330
+
331
+ **Revalidation**:
332
+
333
+ ```typescript
334
+ import { revalidateTag } from 'next/cache';
335
+
336
+ // In a Server Action
337
+ export async function refreshProducts() {
338
+ 'use server';
339
+ revalidateTag('products', 'max'); // stale-while-revalidate
340
+ }
341
+ ```
342
+
343
+ Prefer `revalidateTag(tag, 'max')` for most cases. Use `updateTag(...)` inside Server Actions when you need immediate consistency.
344
+
345
+ ## Build Gotchas (Next.js 14+)
346
+
347
+ 1. **`next.config.ts` not supported** in Next.js 14.2 — use `.mjs` or `.js`
348
+
349
+ 2. **`@apply border-border` fails** unless shadcn/ui color tokens are defined in `tailwind.config.ts` (need `border: 'hsl(var(--border))'` etc.)
350
+
351
+ 3. **Static prerendering fails** when pages use `import 'server-only'` Supabase client — add `export const dynamic = 'force-dynamic'` to all data-fetching pages
352
+
353
+ 4. **Hydration mismatch** — `typeof window !== 'undefined'` evaluates differently server vs client. Defer browser checks to `useEffect`:
354
+
355
+ ```typescript
356
+ const [isClient, setIsClient] = useState(false);
357
+ useEffect(() => setIsClient(true), []);
358
+ ```
359
+
360
+ 5. **`next/dynamic` with `{ ssr: false }` in Server Components** — Not supported. Move client-only logic to a dedicated Client Component and import it directly.
361
+
362
+ ## Data Cache Gotcha: Stale Supabase Data (CRITICAL)
363
+
364
+ Next.js 14 patches the global `fetch` API to add `cache: 'force-cache'` by default. Libraries that use `fetch` internally (like `@supabase/supabase-js`) will have their responses cached by Next.js's **Data Cache**, even when pages have `export const dynamic = 'force-dynamic'`.
365
+
366
+ **Symptoms**: Pages show old data despite the database having correct values. `router.refresh()` and hard refresh don't help. Direct SQL queries return correct results.
367
+
368
+ **Why `force-dynamic` isn't enough**: `force-dynamic` opts out of the **Full Route Cache** (no static prerendering) but does NOT bypass the **Data Cache** for individual `fetch` calls. The Supabase client's internal fetch calls inherit the default `cache: 'force-cache'` behavior.
369
+
370
+ **Fix**: Override the Supabase client's `fetch` to pass `cache: 'no-store'`:
371
+
372
+ ```typescript
373
+ // lib/supabase.ts
374
+ client = createClient(url, key, {
375
+ auth: { autoRefreshToken: false, persistSession: false },
376
+ global: {
377
+ fetch: (input, init) =>
378
+ fetch(input, { ...init, cache: 'no-store' }),
379
+ },
380
+ });
381
+ ```
382
+
383
+ **Layouts are especially vulnerable**: `app/layout.tsx` doesn't support `export const dynamic`. Async Server Components in layouts (e.g., a command palette that fetches features) are always subject to fetch caching unless the client itself opts out.
384
+
385
+ **See also**: database/supabase (client setup with `cache: 'no-store'`)
386
+ **Confidence**: 1.00 | **Validated by**: integration-test | **Source**: DASH-003
387
+
388
+ ## Naming Conventions
389
+
390
+ ### Files and Folders
391
+
392
+ | Element | Convention | Example |
393
+ |---------|------------|---------|
394
+ | Folders | `kebab-case` | `user-profile/` |
395
+ | Component files | `PascalCase` | `UserCard.tsx` |
396
+ | Utility/hook files | `camelCase` | `useUser.ts` |
397
+ | Static assets | `kebab-case` or `snake_case` | `logo-dark.svg` |
398
+ | Context providers | `XyzProvider` | `ThemeProvider` |
399
+
400
+ ### Code
401
+
402
+ | Element | Convention | Example |
403
+ |---------|------------|---------|
404
+ | Variables/Functions | `camelCase` | `getUserData` |
405
+ | Types/Interfaces | `PascalCase` | `UserProfile` |
406
+ | Constants | `UPPER_SNAKE_CASE` | `MAX_RETRIES` |
407
+
408
+ ## Component Best Practices
409
+
410
+ **When to Create a Component:**
411
+ - If a UI pattern is reused more than once
412
+ - If a section of a page is complex or self-contained
413
+ - If it improves readability or testability
414
+
415
+ **Props:**
416
+ - Use TypeScript interfaces for props
417
+ - Prefer explicit prop types and default values
418
+
419
+ ```typescript
420
+ interface UserCardProps {
421
+ user: User;
422
+ showAvatar?: boolean;
423
+ }
424
+
425
+ export function UserCard({ user, showAvatar = true }: UserCardProps) {
426
+ // ...
427
+ }
428
+ ```
429
+
430
+ **Component Location:**
431
+ - Place shared components in `components/`
432
+ - Place route-specific components inside the relevant route folder
433
+
434
+ **Testing:**
435
+ - Co-locate tests with components (e.g., `UserCard.test.tsx`)
436
+
437
+ ## Tooling Updates (Next.js 16)
438
+
439
+ **Turbopack is the default dev bundler.** Configure via the top-level `turbopack` field in `next.config.*`:
440
+
441
+ ```javascript
442
+ // next.config.mjs
443
+ export default {
444
+ turbopack: {
445
+ // turbopack options
446
+ },
447
+ };
448
+ ```
449
+
450
+ **Typed routes are stable** via `typedRoutes: true` (TypeScript required).
451
+
452
+ **ESLint**: In Next.js 16, prefer running ESLint via the ESLint CLI (not `next lint`).
453
+
454
+ **Environment Variables**: `serverRuntimeConfig` / `publicRuntimeConfig` are removed. Use environment variables directly. Note that `NEXT_PUBLIC_` variables are inlined at build time.
455
+
456
+ ## Best Practices
457
+
458
+ 1. **Server Components by default** — only add `'use client'` when you need hooks, event handlers, or browser APIs
459
+ 2. **`import 'server-only'`** on any module that uses secrets — prevents accidental client bundling
460
+ 3. **No `NEXT_PUBLIC_` for secrets** — only use the prefix for values safe to expose in the browser
461
+ 4. **`force-dynamic` on DB pages** — prevents build-time prerendering that requires a live database
462
+ 5. **Server Actions for mutations** — use `'use server'` functions instead of API routes for form submissions
463
+ 6. **Parallel data fetching** — use `Promise.all()` in Server Components to fetch data concurrently
464
+ 7. **Loading skeletons** — add `loading.tsx` per route for instant navigation feedback
465
+ 8. **Error boundaries** — add `error.tsx` per route (must be `'use client'`)
466
+ 9. **Virtual DOM** — Do not manipulate the real DOM. Use `useState` for state changes.
467
+ 10. **TypeScript strict mode** — Enable `strict: true` in `tsconfig.json`
468
+ 11. **Validate all input** — Use libraries like `zod` for API routes and Server Actions
469
+ 12. **Use Suspense boundaries** — Isolate async data fetching for progressive loading
470
+ 13. **Avoid large client bundles** — Keep most logic in Server Components
@@ -0,0 +1,166 @@
1
+ ---
2
+ name: react-patterns
3
+ description: React component patterns, hooks, state management, and performance optimization
4
+ category: frontend
5
+ version: "18.x"
6
+ compatible_with:
7
+ - nextjs-dev
8
+ - tailwindcss
9
+ - jest
10
+ - vitest
11
+ - typescript
12
+ ---
13
+
14
+ # React Patterns
15
+
16
+ ## Overview
17
+
18
+ React is a declarative component library for building user interfaces. This skill covers idiomatic patterns for components, hooks, state management, and performance.
19
+
20
+ ## Project Structure
21
+
22
+ ```
23
+ src/
24
+ ├── components/
25
+ │ ├── ui/ # Generic UI primitives (Button, Input, Modal)
26
+ │ ├── features/ # Feature-specific components
27
+ │ └── layouts/ # Page layouts
28
+ ├── hooks/ # Custom hooks
29
+ ├── context/ # React context providers
30
+ ├── lib/ # Utility functions
31
+ ├── types/ # Shared TypeScript types
32
+ └── App.tsx
33
+ ```
34
+
35
+ ## Core Patterns
36
+
37
+ ### Component Composition
38
+
39
+ ```tsx
40
+ // Prefer composition over prop drilling
41
+ function Card({ children }: { children: React.ReactNode }) {
42
+ return <div className="rounded-lg border p-4">{children}</div>;
43
+ }
44
+
45
+ Card.Header = function CardHeader({ children }: { children: React.ReactNode }) {
46
+ return <div className="mb-2 font-bold">{children}</div>;
47
+ };
48
+
49
+ Card.Body = function CardBody({ children }: { children: React.ReactNode }) {
50
+ return <div>{children}</div>;
51
+ };
52
+
53
+ // Usage
54
+ <Card>
55
+ <Card.Header>Title</Card.Header>
56
+ <Card.Body>Content</Card.Body>
57
+ </Card>
58
+ ```
59
+
60
+ ### Custom Hooks
61
+
62
+ ```tsx
63
+ // Extract reusable logic into hooks
64
+ function useAsync<T>(asyncFn: () => Promise<T>, deps: unknown[] = []) {
65
+ const [state, setState] = useState<{
66
+ data: T | null;
67
+ error: Error | null;
68
+ loading: boolean;
69
+ }>({ data: null, error: null, loading: true });
70
+
71
+ useEffect(() => {
72
+ let cancelled = false;
73
+ setState(s => ({ ...s, loading: true }));
74
+
75
+ asyncFn()
76
+ .then(data => { if (!cancelled) setState({ data, error: null, loading: false }); })
77
+ .catch(error => { if (!cancelled) setState({ data: null, error, loading: false }); });
78
+
79
+ return () => { cancelled = true; };
80
+ }, deps); // eslint-disable-line react-hooks/exhaustive-deps
81
+
82
+ return state;
83
+ }
84
+ ```
85
+
86
+ ### State Management
87
+
88
+ ```tsx
89
+ // useReducer for complex state
90
+ type State = { items: Item[]; filter: string; sort: SortKey };
91
+ type Action =
92
+ | { type: 'ADD_ITEM'; payload: Item }
93
+ | { type: 'SET_FILTER'; payload: string }
94
+ | { type: 'SET_SORT'; payload: SortKey };
95
+
96
+ function reducer(state: State, action: Action): State {
97
+ switch (action.type) {
98
+ case 'ADD_ITEM':
99
+ return { ...state, items: [...state.items, action.payload] };
100
+ case 'SET_FILTER':
101
+ return { ...state, filter: action.payload };
102
+ case 'SET_SORT':
103
+ return { ...state, sort: action.payload };
104
+ }
105
+ }
106
+ ```
107
+
108
+ ### Error Boundaries
109
+
110
+ ```tsx
111
+ class ErrorBoundary extends React.Component<
112
+ { fallback: React.ReactNode; children: React.ReactNode },
113
+ { hasError: boolean }
114
+ > {
115
+ state = { hasError: false };
116
+
117
+ static getDerivedStateFromError() {
118
+ return { hasError: true };
119
+ }
120
+
121
+ componentDidCatch(error: Error, info: React.ErrorInfo) {
122
+ console.error('Error boundary caught:', error, info);
123
+ }
124
+
125
+ render() {
126
+ if (this.state.hasError) return this.props.fallback;
127
+ return this.props.children;
128
+ }
129
+ }
130
+ ```
131
+
132
+ ### Performance
133
+
134
+ ```tsx
135
+ // Memoize expensive components
136
+ const ExpensiveList = React.memo(function ExpensiveList({ items }: { items: Item[] }) {
137
+ return <ul>{items.map(item => <li key={item.id}>{item.name}</li>)}</ul>;
138
+ });
139
+
140
+ // Memoize expensive calculations
141
+ const sorted = useMemo(() => items.sort(compareFn), [items]);
142
+
143
+ // Stable callback references
144
+ const handleClick = useCallback((id: string) => {
145
+ setSelected(id);
146
+ }, []);
147
+ ```
148
+
149
+ ## Best Practices
150
+
151
+ 1. **Lift state up** only as far as needed — colocate state with the component that uses it
152
+ 2. **Derive state** from props/existing state instead of syncing with `useEffect`
153
+ 3. **Key lists properly** — use stable, unique IDs (not array indices)
154
+ 4. **Avoid premature memoization** — `memo`/`useMemo`/`useCallback` only when profiling shows need
155
+ 5. **Single responsibility** — one component = one concern
156
+ 6. **Type events explicitly** — `React.ChangeEvent<HTMLInputElement>` over `any`
157
+ 7. **Use fragments** — `<>...</>` to avoid unnecessary wrapper divs
158
+ 8. **Controlled forms** — manage form state in React, not the DOM
159
+
160
+ ## Gotchas
161
+
162
+ - **Stale closures** in `useEffect`/`useCallback` — check dependency arrays
163
+ - **Object/array identity** in deps — `useMemo` to stabilize reference equality
164
+ - **useEffect firing twice** in StrictMode (development) — not a bug, tests cleanup
165
+ - **setState is async** — use functional updates (`setCount(c => c + 1)`) when depending on previous state
166
+ - **Children re-rendering** — pass children as props/composition to avoid unnecessary rerenders
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: svelte-dev
3
+ description: Aids in Svelte development, including reactive declarations, stores, transitions, and component logic. Ideal for users building lightweight, compiler-optimized frontend apps without a virtual DOM.
4
+ category: frontend
5
+ compatible_with:
6
+ - tailwindcss
7
+ - vitest
8
+ - playwright
9
+ ---
10
+
11
+ # Svelte Development Assistance
12
+
13
+ ## Instructions
14
+ 1. **Evaluate the task**: Check for component building, state management, or animation needs.
15
+ 2. **Utilize Svelte's strengths**: Highlight compile-time optimizations and simple syntax.
16
+ 3. **Provide responses**:
17
+ - Code: Output .svelte files with reactive statements and bindings.
18
+ - Debugging: Explain common errors like undefined variables or store subscriptions.
19
+ - Advanced: Cover SvelteKit for routing and server-side features.
20
+ 4. **Leverage tools**: Use code_execution to run Svelte-compatible JS code.
21
+ 5. **Keep explanations simple**: Use everyday analogies and reference Svelte tutorials.
22
+
23
+ ## Best Practices
24
+ - Use writable stores for global state.
25
+ - Minimize external dependencies.
26
+ - Optimize with preload and lazy loading.
27
+
28
+ For detailed and up-to-date knowledge and examples on the latest Svelte, use Tessl.io respective tile in tessl/npm-svelte