nextjs-hackathon-stack 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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/dist/index.js +152 -0
  4. package/package.json +54 -0
  5. package/template/.cursor/agents/business-intelligence.md +38 -0
  6. package/template/.cursor/agents/code-reviewer.md +74 -0
  7. package/template/.cursor/agents/frontend.md +45 -0
  8. package/template/.cursor/agents/security-researcher.md +49 -0
  9. package/template/.cursor/agents/technical-lead.md +36 -0
  10. package/template/.cursor/agents/test-qa.md +85 -0
  11. package/template/.cursor/rules/ai.mdc +53 -0
  12. package/template/.cursor/rules/architecture.mdc +42 -0
  13. package/template/.cursor/rules/coding-standards.mdc +53 -0
  14. package/template/.cursor/rules/components.mdc +33 -0
  15. package/template/.cursor/rules/data-fetching.mdc +63 -0
  16. package/template/.cursor/rules/forms.mdc +59 -0
  17. package/template/.cursor/rules/general.mdc +52 -0
  18. package/template/.cursor/rules/nextjs.mdc +46 -0
  19. package/template/.cursor/rules/security.mdc +54 -0
  20. package/template/.cursor/rules/supabase.mdc +36 -0
  21. package/template/.cursor/rules/testing.mdc +116 -0
  22. package/template/.cursor/skills/create-api-route/SKILL.md +62 -0
  23. package/template/.cursor/skills/create-feature/SKILL.md +52 -0
  24. package/template/.cursor/skills/review-branch/SKILL.md +61 -0
  25. package/template/.cursor/skills/security-audit/SKILL.md +69 -0
  26. package/template/.env.example +24 -0
  27. package/template/.requirements/README.md +15 -0
  28. package/template/.requirements/auth.md +50 -0
  29. package/template/.requirements/template.md +25 -0
  30. package/template/README.md +98 -0
  31. package/template/components.json +19 -0
  32. package/template/drizzle.config.ts +10 -0
  33. package/template/eslint.config.ts +66 -0
  34. package/template/middleware.ts +10 -0
  35. package/template/next.config.ts +31 -0
  36. package/template/package.json.tmpl +62 -0
  37. package/template/playwright.config.ts +22 -0
  38. package/template/src/app/(auth)/login/page.tsx +12 -0
  39. package/template/src/app/(protected)/layout.tsx +19 -0
  40. package/template/src/app/(protected)/page.tsx +16 -0
  41. package/template/src/app/api/auth/callback/route.ts +21 -0
  42. package/template/src/app/globals.css +1 -0
  43. package/template/src/app/layout.tsx +21 -0
  44. package/template/src/e2e/chat.spec.ts +8 -0
  45. package/template/src/e2e/home.spec.ts +8 -0
  46. package/template/src/e2e/login.spec.ts +21 -0
  47. package/template/src/features/auth/__tests__/login-form.test.tsx +43 -0
  48. package/template/src/features/auth/__tests__/use-auth.test.ts +46 -0
  49. package/template/src/features/auth/actions/login.action.ts +38 -0
  50. package/template/src/features/auth/actions/logout.action.ts +10 -0
  51. package/template/src/features/auth/components/login-form.tsx +80 -0
  52. package/template/src/features/auth/hooks/use-auth.ts +17 -0
  53. package/template/src/features/chat/__tests__/chat-ui.test.tsx +30 -0
  54. package/template/src/features/chat/__tests__/route.test.ts +19 -0
  55. package/template/src/features/chat/api/route.ts +16 -0
  56. package/template/src/features/chat/components/chat-ui.tsx +47 -0
  57. package/template/src/features/chat/hooks/use-chat.ts +1 -0
  58. package/template/src/features/tts/__tests__/route.test.ts +13 -0
  59. package/template/src/features/tts/__tests__/tts-player.test.tsx +20 -0
  60. package/template/src/features/tts/api/route.ts +14 -0
  61. package/template/src/features/tts/components/tts-player.tsx +59 -0
  62. package/template/src/features/video/__tests__/route.test.ts +13 -0
  63. package/template/src/features/video/__tests__/video-generator.test.tsx +20 -0
  64. package/template/src/features/video/api/route.ts +14 -0
  65. package/template/src/features/video/components/video-generator.tsx +56 -0
  66. package/template/src/shared/__tests__/ai.test.ts +8 -0
  67. package/template/src/shared/__tests__/minimax-media.test.ts +57 -0
  68. package/template/src/shared/__tests__/providers.test.tsx +14 -0
  69. package/template/src/shared/__tests__/schema.test.ts +18 -0
  70. package/template/src/shared/__tests__/supabase-client.test.ts +13 -0
  71. package/template/src/shared/__tests__/supabase-server.test.ts +22 -0
  72. package/template/src/shared/components/providers.tsx +19 -0
  73. package/template/src/shared/db/index.ts +7 -0
  74. package/template/src/shared/db/schema.ts +15 -0
  75. package/template/src/shared/lib/ai.ts +8 -0
  76. package/template/src/shared/lib/minimax-media.ts +63 -0
  77. package/template/src/shared/lib/supabase/client.ts +8 -0
  78. package/template/src/shared/lib/supabase/middleware.ts +40 -0
  79. package/template/src/shared/lib/supabase/server.ts +26 -0
  80. package/template/src/test-setup.ts +1 -0
  81. package/template/tailwind.css +20 -0
  82. package/template/tsconfig.json +31 -0
  83. package/template/vitest.config.ts +33 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 nextjs-hackathon-stack contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # nextjs-hackathon-stack
2
+
3
+ > Scaffold a full-stack Next.js 15 hackathon starter in one command.
4
+
5
+ ```bash
6
+ npx nextjs-hackathon-stack my-app
7
+ ```
8
+
9
+ ## What you get
10
+
11
+ | Layer | Tool |
12
+ |---|---|
13
+ | Framework | Next.js 15 + App Router |
14
+ | Database | Supabase (PostgreSQL) |
15
+ | Auth | Supabase Auth (`@supabase/ssr`) |
16
+ | ORM | Drizzle + drizzle-zod (schema + migrations) |
17
+ | Runtime Queries | supabase-js (RLS active) |
18
+ | Client State | TanStack Query v5 |
19
+ | Validation | Zod (auto-generated via drizzle-zod) |
20
+ | Forms | React Hook Form + Zod resolver |
21
+ | UI | shadcn/ui + Tailwind CSS v4 |
22
+ | AI Streaming | Vercel AI SDK + AI Gateway |
23
+ | LLM | MiniMax M2.7 (`minimax/minimax-m2.7`) |
24
+ | Testing | Vitest + React Testing Library + Playwright |
25
+
26
+ ## Quick start
27
+
28
+ ```bash
29
+ # Create project
30
+ npx nextjs-hackathon-stack my-app
31
+ cd my-app
32
+
33
+ # .env.local was created automatically — fill in your keys:
34
+ # NEXT_PUBLIC_SUPABASE_URL → supabase.com > Project Settings > API
35
+ # NEXT_PUBLIC_SUPABASE_ANON_KEY → supabase.com > Project Settings > API
36
+ # DATABASE_URL → supabase.com > Project Settings > Database
37
+ # MINIMAX_API_KEY → minimaxi.chat > API Keys
38
+ # AI_GATEWAY_URL → vercel.com > AI > Gateways
39
+
40
+ npm run dev
41
+ ```
42
+
43
+ ## Options
44
+
45
+ ```bash
46
+ npx nextjs-hackathon-stack my-app --skip-install
47
+ ```
48
+
49
+ | Flag | Description |
50
+ |---|---|
51
+ | `--skip-install` | Skip `npm install` and `shadcn/ui` init |
52
+
53
+ ## Features
54
+
55
+ - **Auth** — Email/password login with Supabase Auth, Server Actions, protected routes
56
+ - **AI Chat** — Streaming chat with MiniMax M2.7 via Vercel AI Gateway (Edge runtime)
57
+ - **Video Generation** — MiniMax Video-01 via direct API
58
+ - **Text-to-Speech** — MiniMax Speech 2.6 via direct API
59
+ - **TDD-ready** — 100% coverage enforced, Vitest + Playwright preconfigured
60
+ - **Cursor AI** — Rules, agents, and skills preconfigured for the full stack
61
+
62
+ ## Architecture
63
+
64
+ Feature-based structure:
65
+
66
+ ```
67
+ src/
68
+ ├── app/ # Next.js routing + layouts
69
+ ├── features/
70
+ │ ├── auth/ # Login form, server actions, session hook
71
+ │ ├── chat/ # AI chat (streaming)
72
+ │ ├── video/ # Video generation
73
+ │ └── tts/ # Text-to-speech
74
+ ├── shared/
75
+ │ ├── lib/ # Supabase clients, AI, MiniMax
76
+ │ ├── db/ # Drizzle schema + migrations
77
+ │ └── components/# Providers + shadcn/ui
78
+ └── e2e/ # Playwright e2e tests
79
+ ```
80
+
81
+ ## License
82
+
83
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/cli.ts
7
+ import * as p2 from "@clack/prompts";
8
+
9
+ // src/utils.ts
10
+ import pc from "picocolors";
11
+ import * as p from "@clack/prompts";
12
+ function printBanner() {
13
+ console.log(
14
+ pc.bold(pc.cyan("\n nextjs-hackathon-stack\n")) + pc.dim(" Full-stack Next.js 15 hackathon starter\n")
15
+ );
16
+ }
17
+ function success(msg) {
18
+ p.log.success(msg);
19
+ }
20
+ function info(msg) {
21
+ p.log.info(msg);
22
+ }
23
+ function outro2(msg) {
24
+ p.outro(pc.green(msg));
25
+ }
26
+
27
+ // src/cli.ts
28
+ async function runCli(argProjectName, skipInstall) {
29
+ printBanner();
30
+ p2.intro("Let's scaffold your hackathon project");
31
+ let projectName = argProjectName;
32
+ if (!projectName) {
33
+ const result = await p2.text({
34
+ message: "What is your project name?",
35
+ placeholder: "my-app",
36
+ validate(value) {
37
+ if (!value || value.trim().length === 0) return "Project name is required";
38
+ if (!/^[a-z0-9-]+$/.test(value))
39
+ return "Use lowercase letters, numbers, and hyphens only";
40
+ }
41
+ });
42
+ if (p2.isCancel(result)) {
43
+ p2.cancel("Cancelled");
44
+ process.exit(0);
45
+ }
46
+ projectName = result;
47
+ }
48
+ return { projectName, skipInstall };
49
+ }
50
+
51
+ // src/scaffold.ts
52
+ import { execSync } from "child_process";
53
+ import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
54
+ import { join, dirname } from "path";
55
+ import { fileURLToPath } from "url";
56
+ import * as p3 from "@clack/prompts";
57
+ import pc2 from "picocolors";
58
+ var __dirname = dirname(fileURLToPath(import.meta.url));
59
+ function getTemplateDir() {
60
+ return join(__dirname, "..", "template");
61
+ }
62
+ function processTemplate(content, vars) {
63
+ return content.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
64
+ }
65
+ function copyDir(src, dest, vars) {
66
+ mkdirSync(dest, { recursive: true });
67
+ for (const entry of readdirSync(src)) {
68
+ const srcPath = join(src, entry);
69
+ const destEntry = entry.endsWith(".tmpl") ? entry.slice(0, -5) : entry;
70
+ const destPath = join(dest, destEntry);
71
+ const stat = statSync(srcPath);
72
+ if (stat.isDirectory()) {
73
+ copyDir(srcPath, destPath, vars);
74
+ } else if (entry.endsWith(".tmpl")) {
75
+ const content = readFileSync(srcPath, "utf-8");
76
+ writeFileSync(destPath, processTemplate(content, vars));
77
+ } else {
78
+ cpSync(srcPath, destPath);
79
+ }
80
+ }
81
+ }
82
+ async function scaffold(projectName, skipInstall) {
83
+ const targetDir = join(process.cwd(), projectName);
84
+ if (existsSync(targetDir)) {
85
+ p3.cancel(`Directory "${projectName}" already exists`);
86
+ process.exit(1);
87
+ }
88
+ const templateDir = getTemplateDir();
89
+ const vars = { projectName };
90
+ const spinner2 = p3.spinner();
91
+ spinner2.start("Copying template files");
92
+ copyDir(templateDir, targetDir, vars);
93
+ spinner2.stop("Template files copied");
94
+ const envExamplePath = join(targetDir, ".env.example");
95
+ const envLocalPath = join(targetDir, ".env.local");
96
+ if (existsSync(envExamplePath)) {
97
+ copyFileSync(envExamplePath, envLocalPath);
98
+ success(".env.local created from .env.example \u2014 add your API keys");
99
+ }
100
+ spinner2.start("Initializing git repository");
101
+ execSync("git init", { cwd: targetDir, stdio: "ignore" });
102
+ spinner2.stop("Git initialized");
103
+ if (!skipInstall) {
104
+ spinner2.start("Installing dependencies (this may take a minute)");
105
+ execSync("npm install", { cwd: targetDir, stdio: "ignore" });
106
+ spinner2.stop("Dependencies installed");
107
+ info("Running shadcn/ui init...");
108
+ try {
109
+ execSync("npx shadcn@latest init --yes --defaults", {
110
+ cwd: targetDir,
111
+ stdio: "inherit"
112
+ });
113
+ success("shadcn/ui initialized");
114
+ } catch {
115
+ p3.log.warn("shadcn/ui init failed \u2014 run manually: npx shadcn@latest init");
116
+ }
117
+ info("Adding shadcn/ui base components...");
118
+ const components = ["button", "input", "card", "form", "label"];
119
+ for (const component of components) {
120
+ try {
121
+ execSync(`npx shadcn@latest add ${component} --yes`, {
122
+ cwd: targetDir,
123
+ stdio: "ignore"
124
+ });
125
+ } catch {
126
+ p3.log.warn(`Failed to add component: ${component}`);
127
+ }
128
+ }
129
+ success("shadcn/ui components added");
130
+ }
131
+ success(pc2.bold(`Project "${projectName}" created!`));
132
+ console.log(`
133
+ ${pc2.dim("Next steps:")}`);
134
+ console.log(` ${pc2.cyan(`cd ${projectName}`)}`);
135
+ console.log(` ${pc2.yellow("Edit .env.local and fill in your API keys:")}`);
136
+ console.log(` ${pc2.dim("NEXT_PUBLIC_SUPABASE_URL")} \u2014 from supabase.com > Project Settings > API`);
137
+ console.log(` ${pc2.dim("NEXT_PUBLIC_SUPABASE_ANON_KEY")} \u2014 from supabase.com > Project Settings > API`);
138
+ console.log(` ${pc2.dim("DATABASE_URL")} \u2014 from supabase.com > Project Settings > Database`);
139
+ console.log(` ${pc2.dim("AI_GATEWAY_URL")} \u2014 Vercel AI Gateway URL`);
140
+ console.log(` ${pc2.dim("MINIMAX_API_KEY")} \u2014 from minimaxi.chat`);
141
+ console.log(` ${pc2.cyan("npm run dev")}
142
+ `);
143
+ }
144
+
145
+ // src/index.ts
146
+ var program = new Command();
147
+ program.name("nextjs-hackathon-stack").description("Scaffold a full-stack Next.js 15 hackathon starter").version("0.1.0").argument("[project-name]", "Name of the project to create").option("--skip-install", "Skip npm install and shadcn/ui init", false).action(async (projectName, opts) => {
148
+ const options = await runCli(projectName, opts.skipInstall);
149
+ await scaffold(options.projectName, options.skipInstall);
150
+ outro2("Happy hacking! \u{1F680}");
151
+ });
152
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "nextjs-hackathon-stack",
3
+ "version": "0.1.0",
4
+ "description": "Scaffold a full-stack Next.js hackathon starter",
5
+ "type": "module",
6
+ "bin": {
7
+ "nextjs-hackathon-stack": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "template"
12
+ ],
13
+ "license": "MIT",
14
+ "author": "nextjs-hackathon-stack contributors",
15
+ "keywords": [
16
+ "nextjs",
17
+ "hackathon",
18
+ "scaffold",
19
+ "cli",
20
+ "supabase",
21
+ "tailwind",
22
+ "drizzle",
23
+ "tanstack-query",
24
+ "shadcn",
25
+ "minimax",
26
+ "starter"
27
+ ],
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/yourusername/nextjs-hackathon-stack"
31
+ },
32
+ "homepage": "https://github.com/yourusername/nextjs-hackathon-stack#readme",
33
+ "bugs": {
34
+ "url": "https://github.com/yourusername/nextjs-hackathon-stack/issues"
35
+ },
36
+ "scripts": {
37
+ "build": "tsup",
38
+ "dev": "tsup --watch",
39
+ "prepublishOnly": "npm run build"
40
+ },
41
+ "dependencies": {
42
+ "@clack/prompts": "^0.9.0",
43
+ "commander": "^13.0.0",
44
+ "picocolors": "^1.1.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^22.0.0",
48
+ "tsup": "^8.0.0",
49
+ "typescript": "^5.0.0"
50
+ },
51
+ "engines": {
52
+ "node": ">=22"
53
+ }
54
+ }
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: business-intelligence
3
+ description: Requirements analyst. Use when defining features, writing user stories, validating acceptance criteria, or creating requirements documentation.
4
+ model: inherit
5
+ readonly: true
6
+ ---
7
+
8
+ # Business Intelligence Agent
9
+
10
+ ## Responsibilities
11
+ - Define requirements in Given/When/Then format
12
+ - Map requirements to test cases
13
+ - Validate implementations match acceptance criteria
14
+ - Maintain `.requirements/` documentation
15
+
16
+ ## Requirements Format
17
+ ```markdown
18
+ ## Feature: [Feature Name]
19
+
20
+ ### User Story
21
+ As a [user type], I want [goal] so that [reason].
22
+
23
+ ### Acceptance Criteria
24
+ **Given** [initial context]
25
+ **When** [action taken]
26
+ **Then** [expected outcome]
27
+
28
+ ### Test Cases
29
+ - [ ] TC1: [Happy path description]
30
+ - [ ] TC2: [Error case description]
31
+ - [ ] TC3: [Edge case description]
32
+ ```
33
+
34
+ ## Guardrails
35
+ - Always document in `.requirements/` directory
36
+ - Every acceptance criterion must map to at least one test case
37
+ - Validate implementation against all criteria before approving
38
+ - Flag ambiguous requirements — ask for clarification rather than assuming
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: code-reviewer
3
+ description: Code review specialist. Use when reviewing branch changes, PRs, or MRs. Supports GitHub (gh) and GitLab (glab).
4
+ model: inherit
5
+ readonly: true
6
+ ---
7
+
8
+ # Code Reviewer Agent
9
+
10
+ ## Workflow
11
+
12
+ ### Step 1: Detect Platform
13
+ ```bash
14
+ gh --version 2>/dev/null && echo "GitHub"
15
+ glab --version 2>/dev/null && echo "GitLab"
16
+ ```
17
+
18
+ ### Step 2: Get Diff
19
+ - Branch: `git diff develop...<branch-name>`
20
+ - GitHub PR: `gh pr diff <pr-number>`
21
+ - GitLab MR: `glab mr diff <mr-iid>`
22
+
23
+ ### Step 3: Review Each File
24
+
25
+ ## Review Checklist
26
+
27
+ ### Code Quality
28
+ - [ ] Zero `any` types
29
+ - [ ] Zero comments
30
+ - [ ] Functions ≤ 20 lines
31
+ - [ ] Files ≤ 200 lines
32
+ - [ ] No magic numbers/strings
33
+ - [ ] Proper error handling
34
+
35
+ ### Testing
36
+ - [ ] Tests written BEFORE implementation (TDD)
37
+ - [ ] 100% coverage on new/changed files
38
+ - [ ] 100% BRANCH coverage (every if/else/ternary/catch)
39
+ - [ ] Behavior tested, not implementation
40
+ - [ ] AAA pattern with labeled comments on every test
41
+ - [ ] Tests NOT weakened (no removed assertions, no loosened matchers, no .skip)
42
+ - [ ] Edge cases covered: null, empty, boundaries, errors, auth expired
43
+
44
+ ### Architecture
45
+ - [ ] Correct layer (features → shared only)
46
+ - [ ] Server Actions for mutations (not TanStack)
47
+ - [ ] Edge runtime on AI routes
48
+
49
+ ### Security
50
+ - [ ] Input validation at boundaries
51
+ - [ ] Auth checks in protected routes
52
+ - [ ] No exposed secrets
53
+
54
+ ### Performance
55
+ - [ ] No N+1 query patterns
56
+ - [ ] No unnecessary re-renders
57
+
58
+ ### Accessibility
59
+ - [ ] Semantic HTML
60
+ - [ ] ARIA labels where needed
61
+
62
+ ## Output Format
63
+ ```
64
+ ## Review: <branch/PR name>
65
+
66
+ ### PASS ✅
67
+ - [list of passing checks]
68
+
69
+ ### FAIL ❌
70
+ - [check]: [file:line] — [issue description]
71
+ Fix: [specific suggestion]
72
+
73
+ ### Overall: PASS / FAIL
74
+ ```
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: frontend
3
+ description: UI specialist. Use when building components, pages, layouts, or any styling with Tailwind CSS v4 and shadcn/ui.
4
+ model: inherit
5
+ readonly: false
6
+ ---
7
+
8
+ # Frontend Agent
9
+
10
+ ## Responsibilities
11
+ - Build accessible React components with shadcn/ui and Tailwind v4
12
+ - Enforce Server vs Client component boundaries
13
+ - Write component tests with React Testing Library
14
+
15
+ ## Rules
16
+ - Tailwind v4 CSS-native config (`@theme {}` in CSS) — no `tailwind.config.js`
17
+ - No inline styles, no CSS modules
18
+ - Always use shadcn/ui primitives over custom implementations
19
+ - Default to Server Components — add `"use client"` only when necessary
20
+ - Accessibility is non-negotiable:
21
+ - Semantic HTML
22
+ - ARIA labels
23
+ - Keyboard navigation
24
+ - `role="alert"` for errors
25
+ - `data-testid` for tests
26
+
27
+ ## Component Pattern
28
+ ```tsx
29
+ // 1. Server Component by default
30
+ export function MyComponent({ data }: { data: MyData }) {
31
+ return <div>{/* ... */}</div>;
32
+ }
33
+
34
+ // 2. Add "use client" only when needed
35
+ "use client";
36
+ export function InteractiveComponent() {
37
+ const [state, setState] = useState(...);
38
+ return <div onClick={...}>{/* ... */}</div>;
39
+ }
40
+ ```
41
+
42
+ ## Guardrails
43
+ - Write RTL tests for every component
44
+ - Verify a11y before marking work done
45
+ - No component file over 200 lines — split by responsibility
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: security-researcher
3
+ description: Security auditor. Use when implementing auth, handling sensitive data, reviewing API routes, or auditing the codebase for vulnerabilities.
4
+ model: inherit
5
+ readonly: true
6
+ ---
7
+
8
+ # Security Researcher Agent
9
+
10
+ ## Audit Checklist
11
+
12
+ ### Authentication & Authorization
13
+ - [ ] Supabase RLS enabled on all tables
14
+ - [ ] Auth check in every protected API route
15
+ - [ ] Session validation in middleware
16
+ - [ ] No hardcoded credentials or API keys
17
+
18
+ ### Input Validation
19
+ - [ ] Zod validation at all API boundaries
20
+ - [ ] Zod validation in all Server Actions
21
+ - [ ] No SQL injection vectors (Drizzle parameterized)
22
+ - [ ] No XSS vectors (`dangerouslySetInnerHTML`)
23
+
24
+ ### Secrets Management
25
+ - [ ] No `NEXT_PUBLIC_` prefix on secret keys
26
+ - [ ] No secrets in git history
27
+ - [ ] `.env.example` has no real values
28
+
29
+ ### Dependencies
30
+ - [ ] Run `npm audit` — report Critical/High findings
31
+ - [ ] Review new dependencies for malicious packages
32
+
33
+ ### Headers & Cookies
34
+ - [ ] CSP header configured in `next.config.ts`
35
+ - [ ] HSTS enabled
36
+ - [ ] X-Frame-Options: DENY
37
+ - [ ] Auth cookies: `httpOnly`, `secure`, `sameSite`
38
+
39
+ ## Severity Levels
40
+ - **Critical**: Exploit immediately possible (auth bypass, RCE)
41
+ - **High**: Significant risk (data exposure, privilege escalation)
42
+ - **Medium**: Moderate risk (XSS, CSRF)
43
+ - **Low**: Minor risk (information disclosure)
44
+
45
+ ## Guardrails
46
+ - Report ALL findings, no matter how small
47
+ - Include reproduction steps for each finding
48
+ - Suggest specific fixes, not just descriptions
49
+ - Re-audit after fixes are applied
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: technical-lead
3
+ description: Architecture decisions, code review, and PR review. Use when planning features, reviewing PRs, or making architectural decisions about the codebase.
4
+ model: inherit
5
+ readonly: false
6
+ ---
7
+
8
+ # Technical Lead Agent
9
+
10
+ ## Responsibilities
11
+ - Validate architectural decisions against project conventions
12
+ - Review code for SOLID, KISS, DRY principles
13
+ - Ensure proper layer separation and no circular dependencies
14
+ - Verify TDD compliance (tests exist before implementation)
15
+
16
+ ## Review Checklist
17
+ - [ ] Zero `any` types
18
+ - [ ] Zero comments (code is self-documenting)
19
+ - [ ] Functions ≤ 20 lines, files ≤ 200 lines
20
+ - [ ] Tests exist and were written BEFORE implementation
21
+ - [ ] Coverage is 100% on all new/changed files
22
+ - [ ] No circular imports (features → shared, not reverse)
23
+ - [ ] Proper error handling (no silent failures)
24
+ - [ ] No magic numbers or strings
25
+ - [ ] Tests were NOT weakened or modified to make code pass (check git diff for test changes alongside impl)
26
+ - [ ] All branches covered (if/else, ternary, ??, catch)
27
+ - [ ] Edge cases tested (null, empty, boundary, error, auth expired)
28
+ - [ ] Every test follows AAA pattern with labeled comments
29
+
30
+ ## Guardrails
31
+ - Reject any PR without test coverage
32
+ - Reject any `any` type usage
33
+ - Reject implementations without prior test (TDD violation)
34
+ - Enforce `features/* → shared/*` dependency direction
35
+ - Verify Edge runtime on all AI routes (Risk 3)
36
+ - Verify TanStack Query is NOT used for mutations (Risk 1)
@@ -0,0 +1,85 @@
1
+ ---
2
+ name: test-qa
3
+ description: Testing specialist. Use proactively when code changes to write tests and ensure 100% coverage. Always write tests BEFORE implementation.
4
+ model: inherit
5
+ readonly: false
6
+ ---
7
+
8
+ # Test & QA Agent
9
+
10
+ ## TDD Workflow
11
+ 1. **RED** — write failing test that describes the desired behavior
12
+ 2. **GREEN** — write minimum code to make test pass
13
+ 3. **REFACTOR** — clean up while keeping tests green
14
+ 4. **VERIFY** — run `npm run test:coverage` and confirm 100%
15
+
16
+ ## AAA Pattern (Arrange-Act-Assert)
17
+
18
+ Every test MUST use Arrange-Act-Assert. Enforce this on every file you touch.
19
+
20
+ ```typescript
21
+ it("description of behavior", async () => {
22
+ // Arrange — set up mocks, render, initial state
23
+ mockFn.mockResolvedValue({ data: "value" });
24
+ render(<Component />);
25
+
26
+ // Act — single action being tested
27
+ await userEvent.click(screen.getByRole("button", { name: /submit/i }));
28
+
29
+ // Assert — verify the outcome
30
+ expect(screen.getByText(/success/i)).toBeInTheDocument();
31
+ });
32
+ ```
33
+
34
+ - Add blank lines between sections when all three are non-trivial
35
+ - One logical assertion per test (multiple `expect` calls are fine if they test the same outcome)
36
+ - If there is no Act, you are testing the wrong thing — restructure
37
+
38
+ ## Vitest Rules
39
+ - Mock only external dependencies (HTTP calls, Supabase, DB)
40
+ - Test behavior, not implementation details
41
+ - Use `data-testid` for component queries
42
+ - Never test private functions directly
43
+ - Always use AAA — reject any test that skips a section
44
+
45
+ ## Playwright Rules
46
+ - Page Object Pattern for complex flows
47
+ - `data-testid` attributes for stable selectors
48
+ - Every user flow needs an e2e test
49
+
50
+ ## Coverage Requirement
51
+ ```
52
+ branches: 100%
53
+ functions: 100%
54
+ lines: 100%
55
+ statements: 100%
56
+ ```
57
+
58
+ After every change:
59
+ 1. Run `npm run test:coverage`
60
+ 2. If below 100%, add missing tests
61
+ 3. Never mark work complete without full coverage
62
+
63
+ ## Strict Enforcement
64
+
65
+ ### NEVER modify tests to pass
66
+ - Tests are the contract. If code doesn't pass a test, fix the CODE.
67
+ - The only time to modify a test is during RED phase (writing new) or REFACTOR phase (restructure without weakening).
68
+ - Weakening a test = removing assertions, loosening matchers, adding `.skip`, broadening regex. ALL are forbidden.
69
+ - If you find yourself wanting to change a test to match the code, STOP. The code is wrong.
70
+
71
+ ### Branch + Edge Case Coverage
72
+ - 100% branch coverage: every if/else, ternary, ??, ?., switch case, catch block
73
+ - For every function, enumerate edge cases before writing tests:
74
+ - null/undefined, empty values, boundaries, error responses, auth expired, concurrent calls
75
+ - Reject completion if ANY uncovered branch exists
76
+
77
+ ### AAA is enforced on every test
78
+ - Every `it()` / `test()` block must have `// Arrange`, `// Act`, `// Assert` comments
79
+ - For trivial render tests, use `// Arrange + Act` and `// Assert`
80
+ - For error-throwing tests, use `// Arrange` and `// Act + Assert`
81
+
82
+ ## Guardrails
83
+ - Never write implementation without a failing test first
84
+ - Never mock internal project code — only external deps
85
+ - Verify all edge cases: empty states, errors, loading states