agentbrief 0.1.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.
Files changed (137) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +141 -0
  3. package/briefs/code-reviewer/brief.yaml +8 -0
  4. package/briefs/code-reviewer/knowledge/review-standards.md +32 -0
  5. package/briefs/code-reviewer/personality.md +19 -0
  6. package/briefs/code-reviewer/skills/architecture-review/SKILL.md +76 -0
  7. package/briefs/code-reviewer/skills/review-process/SKILL.md +41 -0
  8. package/briefs/code-reviewer/skills/verification/SKILL.md +47 -0
  9. package/briefs/data-analyst/brief.yaml +8 -0
  10. package/briefs/data-analyst/knowledge/metrics-reference.md +43 -0
  11. package/briefs/data-analyst/personality.md +23 -0
  12. package/briefs/data-analyst/skills/metrics-framework/SKILL.md +90 -0
  13. package/briefs/data-analyst/skills/sql-query-builder/SKILL.md +115 -0
  14. package/briefs/devops-sre/brief.yaml +12 -0
  15. package/briefs/devops-sre/knowledge/runbook.md +69 -0
  16. package/briefs/devops-sre/personality.md +18 -0
  17. package/briefs/devops-sre/skills/ci-cd-github-actions/SKILL.md +114 -0
  18. package/briefs/devops-sre/skills/monitoring-observability/SKILL.md +394 -0
  19. package/briefs/devops-sre/skills/systematic-debugging/SKILL.md +46 -0
  20. package/briefs/devops-sre/skills/verification/SKILL.md +47 -0
  21. package/briefs/frontend-design/brief.yaml +8 -0
  22. package/briefs/frontend-design/knowledge/design-principles.md +43 -0
  23. package/briefs/frontend-design/personality.md +19 -0
  24. package/briefs/frontend-design/skills/design-review-checklist/SKILL.md +151 -0
  25. package/briefs/frontend-design/skills/web-design-guidelines/SKILL.md +39 -0
  26. package/briefs/fullstack-dev/brief.yaml +9 -0
  27. package/briefs/fullstack-dev/personality.md +18 -0
  28. package/briefs/growth-engineer/brief.yaml +8 -0
  29. package/briefs/growth-engineer/knowledge/growth-framework.md +83 -0
  30. package/briefs/growth-engineer/personality.md +19 -0
  31. package/briefs/growth-engineer/skills/analytics-setup/SKILL.md +109 -0
  32. package/briefs/growth-engineer/skills/brainstorming/SKILL.md +55 -0
  33. package/briefs/growth-engineer/skills/content-strategy/SKILL.md +93 -0
  34. package/briefs/growth-engineer/skills/seo-audit/SKILL.md +412 -0
  35. package/briefs/growth-engineer/skills/seo-audit/evals/evals.json +136 -0
  36. package/briefs/growth-engineer/skills/seo-audit/references/ai-writing-detection.md +200 -0
  37. package/briefs/nextjs-fullstack/brief.yaml +12 -0
  38. package/briefs/nextjs-fullstack/knowledge/conventions.md +57 -0
  39. package/briefs/nextjs-fullstack/personality.md +19 -0
  40. package/briefs/nextjs-fullstack/skills/next-best-practices/SKILL.md +153 -0
  41. package/briefs/nextjs-fullstack/skills/next-best-practices/async-patterns.md +87 -0
  42. package/briefs/nextjs-fullstack/skills/next-best-practices/bundling.md +180 -0
  43. package/briefs/nextjs-fullstack/skills/next-best-practices/data-patterns.md +297 -0
  44. package/briefs/nextjs-fullstack/skills/next-best-practices/debug-tricks.md +105 -0
  45. package/briefs/nextjs-fullstack/skills/next-best-practices/directives.md +73 -0
  46. package/briefs/nextjs-fullstack/skills/next-best-practices/error-handling.md +227 -0
  47. package/briefs/nextjs-fullstack/skills/next-best-practices/file-conventions.md +140 -0
  48. package/briefs/nextjs-fullstack/skills/next-best-practices/font.md +245 -0
  49. package/briefs/nextjs-fullstack/skills/next-best-practices/functions.md +108 -0
  50. package/briefs/nextjs-fullstack/skills/next-best-practices/hydration-error.md +91 -0
  51. package/briefs/nextjs-fullstack/skills/next-best-practices/image.md +173 -0
  52. package/briefs/nextjs-fullstack/skills/next-best-practices/metadata.md +301 -0
  53. package/briefs/nextjs-fullstack/skills/next-best-practices/parallel-routes.md +287 -0
  54. package/briefs/nextjs-fullstack/skills/next-best-practices/route-handlers.md +146 -0
  55. package/briefs/nextjs-fullstack/skills/next-best-practices/rsc-boundaries.md +159 -0
  56. package/briefs/nextjs-fullstack/skills/next-best-practices/runtime-selection.md +39 -0
  57. package/briefs/nextjs-fullstack/skills/next-best-practices/scripts.md +141 -0
  58. package/briefs/nextjs-fullstack/skills/next-best-practices/self-hosting.md +371 -0
  59. package/briefs/nextjs-fullstack/skills/next-best-practices/suspense-boundaries.md +67 -0
  60. package/briefs/nextjs-fullstack/skills/tdd/SKILL.md +53 -0
  61. package/briefs/product-manager/brief.yaml +8 -0
  62. package/briefs/product-manager/knowledge/pm-toolkit.md +51 -0
  63. package/briefs/product-manager/personality.md +19 -0
  64. package/briefs/product-manager/skills/brainstorming/SKILL.md +55 -0
  65. package/briefs/product-manager/skills/specification/SKILL.md +76 -0
  66. package/briefs/qa-engineer/brief.yaml +11 -0
  67. package/briefs/qa-engineer/knowledge/testing-patterns.md +54 -0
  68. package/briefs/qa-engineer/personality.md +24 -0
  69. package/briefs/qa-engineer/skills/qa-test-and-fix/SKILL.md +101 -0
  70. package/briefs/qa-engineer/skills/regression-testing/SKILL.md +95 -0
  71. package/briefs/security-auditor/brief.yaml +12 -0
  72. package/briefs/security-auditor/knowledge/code-patterns.md +49 -0
  73. package/briefs/security-auditor/knowledge/owasp-cheatsheet.md +75 -0
  74. package/briefs/security-auditor/personality.md +23 -0
  75. package/briefs/security-auditor/skills/security-review/SKILL.md +29 -0
  76. package/briefs/security-auditor/skills/systematic-debugging/SKILL.md +46 -0
  77. package/briefs/security-auditor/skills/verification/SKILL.md +47 -0
  78. package/briefs/startup-builder/brief.yaml +8 -0
  79. package/briefs/startup-builder/knowledge/startup-phases.md +64 -0
  80. package/briefs/startup-builder/personality.md +18 -0
  81. package/briefs/startup-builder/skills/ceo-review/SKILL.md +95 -0
  82. package/briefs/startup-builder/skills/launch-strategy/SKILL.md +353 -0
  83. package/briefs/startup-builder/skills/launch-strategy/evals/evals.json +91 -0
  84. package/briefs/startup-builder/skills/tdd/SKILL.md +53 -0
  85. package/briefs/startup-builder/skills/verification/SKILL.md +47 -0
  86. package/briefs/startup-kit/brief.yaml +9 -0
  87. package/briefs/startup-kit/personality.md +18 -0
  88. package/briefs/tech-writer/brief.yaml +8 -0
  89. package/briefs/tech-writer/knowledge/style-guide.md +54 -0
  90. package/briefs/tech-writer/personality.md +19 -0
  91. package/briefs/tech-writer/skills/api-documentation/SKILL.md +390 -0
  92. package/briefs/tech-writer/skills/plan-and-execute/SKILL.md +54 -0
  93. package/briefs/tech-writer/skills/release-notes/SKILL.md +77 -0
  94. package/briefs/typescript-strict/brief.yaml +8 -0
  95. package/briefs/typescript-strict/knowledge/type-patterns.md +117 -0
  96. package/briefs/typescript-strict/personality.md +23 -0
  97. package/briefs/typescript-strict/skills/typescript-advanced-types/SKILL.md +717 -0
  98. package/dist/brief.d.ts +13 -0
  99. package/dist/brief.d.ts.map +1 -0
  100. package/dist/brief.js +90 -0
  101. package/dist/brief.js.map +1 -0
  102. package/dist/cli.d.ts +3 -0
  103. package/dist/cli.d.ts.map +1 -0
  104. package/dist/cli.js +180 -0
  105. package/dist/cli.js.map +1 -0
  106. package/dist/compiler.d.ts +25 -0
  107. package/dist/compiler.d.ts.map +1 -0
  108. package/dist/compiler.js +253 -0
  109. package/dist/compiler.js.map +1 -0
  110. package/dist/index.d.ts +54 -0
  111. package/dist/index.d.ts.map +1 -0
  112. package/dist/index.js +255 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/injector.d.ts +17 -0
  115. package/dist/injector.d.ts.map +1 -0
  116. package/dist/injector.js +76 -0
  117. package/dist/injector.js.map +1 -0
  118. package/dist/lock.d.ts +8 -0
  119. package/dist/lock.d.ts.map +1 -0
  120. package/dist/lock.js +50 -0
  121. package/dist/lock.js.map +1 -0
  122. package/dist/resolver.d.ts +24 -0
  123. package/dist/resolver.d.ts.map +1 -0
  124. package/dist/resolver.js +135 -0
  125. package/dist/resolver.js.map +1 -0
  126. package/dist/types.d.ts +61 -0
  127. package/dist/types.d.ts.map +1 -0
  128. package/dist/types.js +15 -0
  129. package/dist/types.js.map +1 -0
  130. package/package.json +64 -0
  131. package/registry.yaml +91 -0
  132. package/templates/default/brief.yaml +7 -0
  133. package/templates/default/knowledge/.gitkeep +0 -0
  134. package/templates/default/personality.md +12 -0
  135. package/templates/security/brief.yaml +6 -0
  136. package/templates/security/knowledge/.gitkeep +0 -0
  137. package/templates/security/personality.md +20 -0
@@ -0,0 +1,141 @@
1
+ # Scripts
2
+
3
+ Loading third-party scripts in Next.js.
4
+
5
+ ## Use next/script
6
+
7
+ Always use `next/script` instead of native `<script>` tags for better performance.
8
+
9
+ ```tsx
10
+ // Bad: Native script tag
11
+ <script src="https://example.com/script.js"></script>
12
+
13
+ // Good: Next.js Script component
14
+ import Script from 'next/script'
15
+
16
+ <Script src="https://example.com/script.js" />
17
+ ```
18
+
19
+ ## Inline Scripts Need ID
20
+
21
+ Inline scripts require an `id` attribute for Next.js to track them.
22
+
23
+ ```tsx
24
+ // Bad: Missing id
25
+ <Script dangerouslySetInnerHTML={{ __html: 'console.log("hi")' }} />
26
+
27
+ // Good: Has id
28
+ <Script id="my-script" dangerouslySetInnerHTML={{ __html: 'console.log("hi")' }} />
29
+
30
+ // Good: Inline with id
31
+ <Script id="show-banner">
32
+ {`document.getElementById('banner').classList.remove('hidden')`}
33
+ </Script>
34
+ ```
35
+
36
+ ## Don't Put Script in Head
37
+
38
+ `next/script` should not be placed inside `next/head`. It handles its own positioning.
39
+
40
+ ```tsx
41
+ // Bad: Script inside Head
42
+ import Head from 'next/head'
43
+ import Script from 'next/script'
44
+
45
+ <Head>
46
+ <Script src="/analytics.js" />
47
+ </Head>
48
+
49
+ // Good: Script outside Head
50
+ <Head>
51
+ <title>Page</title>
52
+ </Head>
53
+ <Script src="/analytics.js" />
54
+ ```
55
+
56
+ ## Loading Strategies
57
+
58
+ ```tsx
59
+ // afterInteractive (default) - Load after page is interactive
60
+ <Script src="/analytics.js" strategy="afterInteractive" />
61
+
62
+ // lazyOnload - Load during idle time
63
+ <Script src="/widget.js" strategy="lazyOnload" />
64
+
65
+ // beforeInteractive - Load before page is interactive (use sparingly)
66
+ // Only works in app/layout.tsx or pages/_document.js
67
+ <Script src="/critical.js" strategy="beforeInteractive" />
68
+
69
+ // worker - Load in web worker (experimental)
70
+ <Script src="/heavy.js" strategy="worker" />
71
+ ```
72
+
73
+ ## Google Analytics
74
+
75
+ Use `@next/third-parties` instead of inline GA scripts.
76
+
77
+ ```tsx
78
+ // Bad: Inline GA script
79
+ <Script src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX" />
80
+ <Script id="ga-init">
81
+ {`window.dataLayer = window.dataLayer || [];
82
+ function gtag(){dataLayer.push(arguments);}
83
+ gtag('js', new Date());
84
+ gtag('config', 'G-XXXXX');`}
85
+ </Script>
86
+
87
+ // Good: Next.js component
88
+ import { GoogleAnalytics } from '@next/third-parties/google'
89
+
90
+ export default function Layout({ children }) {
91
+ return (
92
+ <html>
93
+ <body>{children}</body>
94
+ <GoogleAnalytics gaId="G-XXXXX" />
95
+ </html>
96
+ )
97
+ }
98
+ ```
99
+
100
+ ## Google Tag Manager
101
+
102
+ ```tsx
103
+ import { GoogleTagManager } from '@next/third-parties/google'
104
+
105
+ export default function Layout({ children }) {
106
+ return (
107
+ <html>
108
+ <GoogleTagManager gtmId="GTM-XXXXX" />
109
+ <body>{children}</body>
110
+ </html>
111
+ )
112
+ }
113
+ ```
114
+
115
+ ## Other Third-Party Scripts
116
+
117
+ ```tsx
118
+ // YouTube embed
119
+ import { YouTubeEmbed } from '@next/third-parties/google'
120
+
121
+ <YouTubeEmbed videoid="dQw4w9WgXcQ" />
122
+
123
+ // Google Maps
124
+ import { GoogleMapsEmbed } from '@next/third-parties/google'
125
+
126
+ <GoogleMapsEmbed
127
+ apiKey="YOUR_API_KEY"
128
+ mode="place"
129
+ q="Brooklyn+Bridge,New+York,NY"
130
+ />
131
+ ```
132
+
133
+ ## Quick Reference
134
+
135
+ | Pattern | Issue | Fix |
136
+ |---------|-------|-----|
137
+ | `<script src="...">` | No optimization | Use `next/script` |
138
+ | `<Script>` without id | Can't track inline scripts | Add `id` attribute |
139
+ | `<Script>` inside `<Head>` | Wrong placement | Move outside Head |
140
+ | Inline GA/GTM scripts | No optimization | Use `@next/third-parties` |
141
+ | `strategy="beforeInteractive"` outside layout | Won't work | Only use in root layout |
@@ -0,0 +1,371 @@
1
+ # Self-Hosting Next.js
2
+
3
+ Deploy Next.js outside of Vercel with confidence.
4
+
5
+ ## Quick Start: Standalone Output
6
+
7
+ For Docker or any containerized deployment, use standalone output:
8
+
9
+ ```js
10
+ // next.config.js
11
+ module.exports = {
12
+ output: 'standalone',
13
+ };
14
+ ```
15
+
16
+ This creates a minimal `standalone` folder with only production dependencies:
17
+
18
+ ```
19
+ .next/
20
+ ├── standalone/
21
+ │ ├── server.js # Entry point
22
+ │ ├── node_modules/ # Only production deps
23
+ │ └── .next/ # Build output
24
+ └── static/ # Must be copied separately
25
+ ```
26
+
27
+ ## Docker Deployment
28
+
29
+ ### Dockerfile
30
+
31
+ ```dockerfile
32
+ FROM node:20-alpine AS base
33
+
34
+ # Install dependencies
35
+ FROM base AS deps
36
+ WORKDIR /app
37
+ COPY package.json package-lock.json* ./
38
+ RUN npm ci
39
+
40
+ # Build
41
+ FROM base AS builder
42
+ WORKDIR /app
43
+ COPY --from=deps /app/node_modules ./node_modules
44
+ COPY . .
45
+ RUN npm run build
46
+
47
+ # Production
48
+ FROM base AS runner
49
+ WORKDIR /app
50
+
51
+ ENV NODE_ENV=production
52
+
53
+ # Create non-root user
54
+ RUN addgroup --system --gid 1001 nodejs
55
+ RUN adduser --system --uid 1001 nextjs
56
+
57
+ # Copy standalone output
58
+ COPY --from=builder /app/.next/standalone ./
59
+ COPY --from=builder /app/.next/static ./.next/static
60
+ COPY --from=builder /app/public ./public
61
+
62
+ USER nextjs
63
+
64
+ EXPOSE 3000
65
+ ENV PORT=3000
66
+ ENV HOSTNAME="0.0.0.0"
67
+
68
+ CMD ["node", "server.js"]
69
+ ```
70
+
71
+ ### Docker Compose
72
+
73
+ ```yaml
74
+ version: '3.8'
75
+
76
+ services:
77
+ web:
78
+ build: .
79
+ ports:
80
+ - "3000:3000"
81
+ environment:
82
+ - NODE_ENV=production
83
+ restart: unless-stopped
84
+ healthcheck:
85
+ test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/api/health"]
86
+ interval: 30s
87
+ timeout: 10s
88
+ retries: 3
89
+ ```
90
+
91
+ ## PM2 Deployment
92
+
93
+ For traditional server deployments:
94
+
95
+ ```js
96
+ // ecosystem.config.js
97
+ module.exports = {
98
+ apps: [{
99
+ name: 'nextjs',
100
+ script: '.next/standalone/server.js',
101
+ instances: 'max',
102
+ exec_mode: 'cluster',
103
+ env: {
104
+ NODE_ENV: 'production',
105
+ PORT: 3000,
106
+ },
107
+ }],
108
+ };
109
+ ```
110
+
111
+ ```bash
112
+ npm run build
113
+ pm2 start ecosystem.config.js
114
+ ```
115
+
116
+ ## ISR and Cache Handlers
117
+
118
+ ### The Problem
119
+
120
+ ISR (Incremental Static Regeneration) uses filesystem caching by default. This **breaks with multiple instances**:
121
+
122
+ - Instance A regenerates page → saves to its local disk
123
+ - Instance B serves stale page → doesn't see Instance A's cache
124
+ - Load balancer sends users to random instances → inconsistent content
125
+
126
+ ### Solution: Custom Cache Handler
127
+
128
+ Next.js 14+ supports custom cache handlers for shared storage:
129
+
130
+ ```js
131
+ // next.config.js
132
+ module.exports = {
133
+ cacheHandler: require.resolve('./cache-handler.js'),
134
+ cacheMaxMemorySize: 0, // Disable in-memory cache
135
+ };
136
+ ```
137
+
138
+ #### Redis Cache Handler Example
139
+
140
+ ```js
141
+ // cache-handler.js
142
+ const Redis = require('ioredis');
143
+
144
+ const redis = new Redis(process.env.REDIS_URL);
145
+ const CACHE_PREFIX = 'nextjs:';
146
+
147
+ module.exports = class CacheHandler {
148
+ constructor(options) {
149
+ this.options = options;
150
+ }
151
+
152
+ async get(key) {
153
+ const data = await redis.get(CACHE_PREFIX + key);
154
+ if (!data) return null;
155
+
156
+ const parsed = JSON.parse(data);
157
+ return {
158
+ value: parsed.value,
159
+ lastModified: parsed.lastModified,
160
+ };
161
+ }
162
+
163
+ async set(key, data, ctx) {
164
+ const cacheData = {
165
+ value: data,
166
+ lastModified: Date.now(),
167
+ };
168
+
169
+ // Set TTL based on revalidate option
170
+ if (ctx?.revalidate) {
171
+ await redis.setex(
172
+ CACHE_PREFIX + key,
173
+ ctx.revalidate,
174
+ JSON.stringify(cacheData)
175
+ );
176
+ } else {
177
+ await redis.set(CACHE_PREFIX + key, JSON.stringify(cacheData));
178
+ }
179
+ }
180
+
181
+ async revalidateTag(tags) {
182
+ // Implement tag-based invalidation
183
+ // This requires tracking which keys have which tags
184
+ }
185
+ };
186
+ ```
187
+
188
+ #### S3 Cache Handler Example
189
+
190
+ ```js
191
+ // cache-handler.js
192
+ const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
193
+
194
+ const s3 = new S3Client({ region: process.env.AWS_REGION });
195
+ const BUCKET = process.env.CACHE_BUCKET;
196
+
197
+ module.exports = class CacheHandler {
198
+ async get(key) {
199
+ try {
200
+ const response = await s3.send(new GetObjectCommand({
201
+ Bucket: BUCKET,
202
+ Key: `cache/${key}`,
203
+ }));
204
+ const body = await response.Body.transformToString();
205
+ return JSON.parse(body);
206
+ } catch (err) {
207
+ if (err.name === 'NoSuchKey') return null;
208
+ throw err;
209
+ }
210
+ }
211
+
212
+ async set(key, data, ctx) {
213
+ await s3.send(new PutObjectCommand({
214
+ Bucket: BUCKET,
215
+ Key: `cache/${key}`,
216
+ Body: JSON.stringify({
217
+ value: data,
218
+ lastModified: Date.now(),
219
+ }),
220
+ ContentType: 'application/json',
221
+ }));
222
+ }
223
+ };
224
+ ```
225
+
226
+ ## What Works vs What Needs Setup
227
+
228
+ | Feature | Single Instance | Multi-Instance | Notes |
229
+ |---------|----------------|----------------|-------|
230
+ | SSR | Yes | Yes | No special setup |
231
+ | SSG | Yes | Yes | Built at deploy time |
232
+ | ISR | Yes | Needs cache handler | Filesystem cache breaks |
233
+ | Image Optimization | Yes | Yes | CPU-intensive, consider CDN |
234
+ | Middleware | Yes | Yes | Runs on Node.js |
235
+ | Edge Runtime | Limited | Limited | Some features Node-only |
236
+ | `revalidatePath/Tag` | Yes | Needs cache handler | Must share cache |
237
+ | `next/font` | Yes | Yes | Fonts bundled at build |
238
+ | Draft Mode | Yes | Yes | Cookie-based |
239
+
240
+ ## Image Optimization
241
+
242
+ Next.js Image Optimization works out of the box but is CPU-intensive.
243
+
244
+ ### Option 1: Built-in (Simple)
245
+
246
+ Works automatically, but consider:
247
+ - Set `deviceSizes` and `imageSizes` in config to limit variants
248
+ - Use `minimumCacheTTL` to reduce regeneration
249
+
250
+ ```js
251
+ // next.config.js
252
+ module.exports = {
253
+ images: {
254
+ minimumCacheTTL: 60 * 60 * 24, // 24 hours
255
+ deviceSizes: [640, 750, 1080, 1920], // Limit sizes
256
+ },
257
+ };
258
+ ```
259
+
260
+ ### Option 2: External Loader (Recommended for Scale)
261
+
262
+ Offload to Cloudinary, Imgix, or similar:
263
+
264
+ ```js
265
+ // next.config.js
266
+ module.exports = {
267
+ images: {
268
+ loader: 'custom',
269
+ loaderFile: './lib/image-loader.js',
270
+ },
271
+ };
272
+ ```
273
+
274
+ ```js
275
+ // lib/image-loader.js
276
+ export default function cloudinaryLoader({ src, width, quality }) {
277
+ const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`];
278
+ return `https://res.cloudinary.com/demo/image/upload/${params.join(',')}${src}`;
279
+ }
280
+ ```
281
+
282
+ ## Environment Variables
283
+
284
+ ### Build-time vs Runtime
285
+
286
+ ```js
287
+ // Available at build time only (baked into bundle)
288
+ NEXT_PUBLIC_API_URL=https://api.example.com
289
+
290
+ // Available at runtime (server-side only)
291
+ DATABASE_URL=postgresql://...
292
+ API_SECRET=...
293
+ ```
294
+
295
+ ### Runtime Configuration
296
+
297
+ For truly dynamic config, don't use `NEXT_PUBLIC_*`. Instead:
298
+
299
+ ```tsx
300
+ // app/api/config/route.ts
301
+ export async function GET() {
302
+ return Response.json({
303
+ apiUrl: process.env.API_URL,
304
+ features: process.env.FEATURES?.split(','),
305
+ });
306
+ }
307
+ ```
308
+
309
+ ## OpenNext: Serverless Without Vercel
310
+
311
+ [OpenNext](https://open-next.js.org/) adapts Next.js for AWS Lambda, Cloudflare Workers, etc.
312
+
313
+ ```bash
314
+ npx create-sst@latest
315
+ # or
316
+ npx @opennextjs/aws build
317
+ ```
318
+
319
+ Supports:
320
+ - AWS Lambda + CloudFront
321
+ - Cloudflare Workers
322
+ - Netlify Functions
323
+ - Deno Deploy
324
+
325
+ ## Health Check Endpoint
326
+
327
+ Always include a health check for load balancers:
328
+
329
+ ```tsx
330
+ // app/api/health/route.ts
331
+ export async function GET() {
332
+ try {
333
+ // Optional: check database connection
334
+ // await db.$queryRaw`SELECT 1`;
335
+
336
+ return Response.json({ status: 'healthy' }, { status: 200 });
337
+ } catch (error) {
338
+ return Response.json({ status: 'unhealthy' }, { status: 503 });
339
+ }
340
+ }
341
+ ```
342
+
343
+ ## Pre-Deployment Checklist
344
+
345
+ 1. **Build locally first**: `npm run build` - catch errors before deploy
346
+ 2. **Test standalone output**: `node .next/standalone/server.js`
347
+ 3. **Set `output: 'standalone'`** for Docker
348
+ 4. **Configure cache handler** for multi-instance ISR
349
+ 5. **Set `HOSTNAME="0.0.0.0"`** for containers
350
+ 6. **Copy `public/` and `.next/static/`** - not included in standalone
351
+ 7. **Add health check endpoint**
352
+ 8. **Test ISR revalidation** after deployment
353
+ 9. **Monitor memory usage** - Node.js defaults may need tuning
354
+
355
+ ## Testing Cache Handler
356
+
357
+ **Critical**: Test your cache handler on every Next.js upgrade:
358
+
359
+ ```bash
360
+ # Start multiple instances
361
+ PORT=3001 node .next/standalone/server.js &
362
+ PORT=3002 node .next/standalone/server.js &
363
+
364
+ # Trigger ISR revalidation
365
+ curl http://localhost:3001/api/revalidate?path=/posts
366
+
367
+ # Verify both instances see the update
368
+ curl http://localhost:3001/posts
369
+ curl http://localhost:3002/posts
370
+ # Should return identical content
371
+ ```
@@ -0,0 +1,67 @@
1
+ # Suspense Boundaries
2
+
3
+ Client hooks that cause CSR bailout without Suspense boundaries.
4
+
5
+ ## useSearchParams
6
+
7
+ Always requires Suspense boundary in static routes. Without it, the entire page becomes client-side rendered.
8
+
9
+ ```tsx
10
+ // Bad: Entire page becomes CSR
11
+ 'use client'
12
+
13
+ import { useSearchParams } from 'next/navigation'
14
+
15
+ export default function SearchBar() {
16
+ const searchParams = useSearchParams()
17
+ return <div>Query: {searchParams.get('q')}</div>
18
+ }
19
+ ```
20
+
21
+ ```tsx
22
+ // Good: Wrap in Suspense
23
+ import { Suspense } from 'react'
24
+ import SearchBar from './search-bar'
25
+
26
+ export default function Page() {
27
+ return (
28
+ <Suspense fallback={<div>Loading...</div>}>
29
+ <SearchBar />
30
+ </Suspense>
31
+ )
32
+ }
33
+ ```
34
+
35
+ ## usePathname
36
+
37
+ Requires Suspense boundary when route has dynamic parameters.
38
+
39
+ ```tsx
40
+ // In dynamic route [slug]
41
+ // Bad: No Suspense
42
+ 'use client'
43
+ import { usePathname } from 'next/navigation'
44
+
45
+ export function Breadcrumb() {
46
+ const pathname = usePathname()
47
+ return <nav>{pathname}</nav>
48
+ }
49
+ ```
50
+
51
+ ```tsx
52
+ // Good: Wrap in Suspense
53
+ <Suspense fallback={<BreadcrumbSkeleton />}>
54
+ <Breadcrumb />
55
+ </Suspense>
56
+ ```
57
+
58
+ If you use `generateStaticParams`, Suspense is optional.
59
+
60
+ ## Quick Reference
61
+
62
+ | Hook | Suspense Required |
63
+ |------|-------------------|
64
+ | `useSearchParams()` | Yes |
65
+ | `usePathname()` | Yes (dynamic routes) |
66
+ | `useParams()` | No |
67
+ | `useRouter()` | No |
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: tdd
3
+ description: Red-green-refactor cycle for test-driven development
4
+ ---
5
+
6
+ > Methodology from [obra/superpowers](https://github.com/obra/superpowers) (MIT)
7
+
8
+ # Test-Driven Development (TDD)
9
+
10
+ Iron law: **no production code without a preceding failing test.**
11
+
12
+ ## The RED-GREEN-REFACTOR Cycle
13
+
14
+ ### RED -- Write a Failing Test
15
+
16
+ 1. Identify the next smallest behavior to implement.
17
+ 2. Write a test that asserts that behavior.
18
+ 3. Run the test suite. Confirm the new test **fails** for the right reason.
19
+ 4. If it passes already, your test is not testing new behavior -- rewrite it.
20
+
21
+ ### GREEN -- Make It Pass
22
+
23
+ 1. Write the **minimum** production code to make the failing test pass.
24
+ 2. Do not add extra logic, handle future cases, or optimize.
25
+ 3. Run the test suite. All tests must be green.
26
+ 4. If other tests broke, fix them before moving on.
27
+
28
+ ### REFACTOR -- Clean Up
29
+
30
+ 1. Look at the code you just wrote. Remove duplication, improve naming, simplify.
31
+ 2. Run the test suite after every refactor step. Stay green.
32
+ 3. Do not add new behavior during refactor -- that requires a new RED step.
33
+
34
+ ## Practical Rules
35
+
36
+ - One assertion per test when possible. Focused tests give clearer failure messages.
37
+ - Name tests by behavior: `should reject expired tokens`, not `test_validate_3`.
38
+ - Keep the cycle short: aim for minutes per iteration, not hours.
39
+ - If you are stuck making a test pass, the step is too big. Write a simpler test first.
40
+ - Commit after each GREEN or REFACTOR step. Small commits are cheap insurance.
41
+
42
+ ## When to Apply TDD
43
+
44
+ - New features: always.
45
+ - Bug fixes: write a test that reproduces the bug first, then fix.
46
+ - Refactoring existing untested code: add characterization tests before changing anything.
47
+
48
+ ## Anti-patterns to Avoid
49
+
50
+ - Writing production code first and tests after (test-last is not TDD).
51
+ - Writing multiple tests before making any of them pass.
52
+ - Skipping the REFACTOR step -- tech debt accrues silently.
53
+ - Over-mocking: if your test has more mocks than assertions, rethink the design.
@@ -0,0 +1,8 @@
1
+ name: product-manager
2
+ version: "1.0.0"
3
+ description: "Product management specialist — PRDs, user stories, prioritization, roadmapping"
4
+ personality: personality.md
5
+ knowledge:
6
+ - knowledge/
7
+ skills:
8
+ - skills/
@@ -0,0 +1,51 @@
1
+ # Product Management Toolkit
2
+
3
+ ## Document Outputs
4
+
5
+ ### PRD (Product Requirements Document)
6
+ - Problem statement: what user pain are we solving? What is the evidence?
7
+ - User stories with acceptance criteria
8
+ - Success metrics: what metric moves if this works? How much? By when?
9
+ - Out of scope: what we are explicitly NOT building
10
+ - Risks: technical, business, and user adoption risks with mitigation plans
11
+
12
+ ### User Stories
13
+ - Format: "As a [user type], I want [goal] so that [benefit]"
14
+ - Each story has clear acceptance criteria
15
+ - Stories are small enough to complete in one sprint
16
+ - Include edge cases and error states in acceptance criteria
17
+
18
+ ### Technical Spec Requests
19
+ - Provide enough context for engineering to estimate and design
20
+ - Do not prescribe the solution -- describe the problem and constraints
21
+ - Include performance requirements, scale expectations, and integration points
22
+ - Reference existing system architecture where relevant
23
+
24
+ ### Prioritization (RICE Framework)
25
+ - **Reach**: How many users will this impact in a given time period?
26
+ - **Impact**: How much will it move the target metric? (3 = massive, 2 = high, 1 = medium, 0.5 = low, 0.25 = minimal)
27
+ - **Confidence**: How sure are we about reach and impact estimates? (100% = high, 80% = medium, 50% = low)
28
+ - **Effort**: How many person-weeks of work?
29
+ - **Score**: (Reach x Impact x Confidence) / Effort
30
+
31
+ ### Roadmap Items
32
+ - Theme -> Epic -> Story hierarchy with clear sequencing rationale
33
+ - Time horizons: Now (committed), Next (planned), Later (exploratory)
34
+ - Dependencies and blockers identified
35
+ - Flexibility increases with distance -- further out items are less defined
36
+
37
+ ## Decision Framework
38
+
39
+ 1. **Start with the problem** -- what user pain are we solving? What is the evidence?
40
+ 2. **Define success** -- what metric moves if this works? How much? By when?
41
+ 3. **Scope ruthlessly** -- what is the smallest thing we can ship to test the hypothesis?
42
+ 4. **Identify risks** -- technical, business, and user adoption risks. Mitigation plan for each.
43
+ 5. **Make trade-offs explicit** -- document what we are choosing NOT to do and why
44
+
45
+ ## Communication Guidelines
46
+
47
+ - Lead with the decision or recommendation, then supporting evidence
48
+ - Use structured formats: bullet points, tables, decision matrices
49
+ - Quantify impact wherever possible with specific numbers
50
+ - Tailor detail level to audience: executives get summary, engineers get specifics
51
+ - Status updates: what shipped, what we learned, what is next
@@ -0,0 +1,19 @@
1
+ ## Role
2
+
3
+ You are a product manager. You define what to build, why to build it, and how to validate that it works. You think in user problems, not features. You communicate in structured documents that align engineering, design, and business stakeholders.
4
+
5
+ ## Tone
6
+
7
+ - Lead with the conclusion, then the reasoning
8
+ - Use bullet points, not paragraphs
9
+ - Quantify whenever possible -- "reduces onboarding time from 5 min to 2 min" not "improves onboarding"
10
+ - Use visual aids (diagrams, wireframes, user flows) over text descriptions
11
+
12
+ ## Constraints
13
+
14
+ - Never propose a feature without articulating the user problem it solves
15
+ - Never skip success metrics -- every feature needs a measurable outcome
16
+ - Never write a PRD longer than 2 pages for an MVP feature
17
+ - Always include "out of scope" to prevent scope creep
18
+ - Always reference user research, data, or competitive analysis -- not just intuition
19
+ - Always define trade-offs explicitly -- document what you are choosing NOT to do and why