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.
- package/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/index.js +152 -0
- package/package.json +54 -0
- package/template/.cursor/agents/business-intelligence.md +38 -0
- package/template/.cursor/agents/code-reviewer.md +74 -0
- package/template/.cursor/agents/frontend.md +45 -0
- package/template/.cursor/agents/security-researcher.md +49 -0
- package/template/.cursor/agents/technical-lead.md +36 -0
- package/template/.cursor/agents/test-qa.md +85 -0
- package/template/.cursor/rules/ai.mdc +53 -0
- package/template/.cursor/rules/architecture.mdc +42 -0
- package/template/.cursor/rules/coding-standards.mdc +53 -0
- package/template/.cursor/rules/components.mdc +33 -0
- package/template/.cursor/rules/data-fetching.mdc +63 -0
- package/template/.cursor/rules/forms.mdc +59 -0
- package/template/.cursor/rules/general.mdc +52 -0
- package/template/.cursor/rules/nextjs.mdc +46 -0
- package/template/.cursor/rules/security.mdc +54 -0
- package/template/.cursor/rules/supabase.mdc +36 -0
- package/template/.cursor/rules/testing.mdc +116 -0
- package/template/.cursor/skills/create-api-route/SKILL.md +62 -0
- package/template/.cursor/skills/create-feature/SKILL.md +52 -0
- package/template/.cursor/skills/review-branch/SKILL.md +61 -0
- package/template/.cursor/skills/security-audit/SKILL.md +69 -0
- package/template/.env.example +24 -0
- package/template/.requirements/README.md +15 -0
- package/template/.requirements/auth.md +50 -0
- package/template/.requirements/template.md +25 -0
- package/template/README.md +98 -0
- package/template/components.json +19 -0
- package/template/drizzle.config.ts +10 -0
- package/template/eslint.config.ts +66 -0
- package/template/middleware.ts +10 -0
- package/template/next.config.ts +31 -0
- package/template/package.json.tmpl +62 -0
- package/template/playwright.config.ts +22 -0
- package/template/src/app/(auth)/login/page.tsx +12 -0
- package/template/src/app/(protected)/layout.tsx +19 -0
- package/template/src/app/(protected)/page.tsx +16 -0
- package/template/src/app/api/auth/callback/route.ts +21 -0
- package/template/src/app/globals.css +1 -0
- package/template/src/app/layout.tsx +21 -0
- package/template/src/e2e/chat.spec.ts +8 -0
- package/template/src/e2e/home.spec.ts +8 -0
- package/template/src/e2e/login.spec.ts +21 -0
- package/template/src/features/auth/__tests__/login-form.test.tsx +43 -0
- package/template/src/features/auth/__tests__/use-auth.test.ts +46 -0
- package/template/src/features/auth/actions/login.action.ts +38 -0
- package/template/src/features/auth/actions/logout.action.ts +10 -0
- package/template/src/features/auth/components/login-form.tsx +80 -0
- package/template/src/features/auth/hooks/use-auth.ts +17 -0
- package/template/src/features/chat/__tests__/chat-ui.test.tsx +30 -0
- package/template/src/features/chat/__tests__/route.test.ts +19 -0
- package/template/src/features/chat/api/route.ts +16 -0
- package/template/src/features/chat/components/chat-ui.tsx +47 -0
- package/template/src/features/chat/hooks/use-chat.ts +1 -0
- package/template/src/features/tts/__tests__/route.test.ts +13 -0
- package/template/src/features/tts/__tests__/tts-player.test.tsx +20 -0
- package/template/src/features/tts/api/route.ts +14 -0
- package/template/src/features/tts/components/tts-player.tsx +59 -0
- package/template/src/features/video/__tests__/route.test.ts +13 -0
- package/template/src/features/video/__tests__/video-generator.test.tsx +20 -0
- package/template/src/features/video/api/route.ts +14 -0
- package/template/src/features/video/components/video-generator.tsx +56 -0
- package/template/src/shared/__tests__/ai.test.ts +8 -0
- package/template/src/shared/__tests__/minimax-media.test.ts +57 -0
- package/template/src/shared/__tests__/providers.test.tsx +14 -0
- package/template/src/shared/__tests__/schema.test.ts +18 -0
- package/template/src/shared/__tests__/supabase-client.test.ts +13 -0
- package/template/src/shared/__tests__/supabase-server.test.ts +22 -0
- package/template/src/shared/components/providers.tsx +19 -0
- package/template/src/shared/db/index.ts +7 -0
- package/template/src/shared/db/schema.ts +15 -0
- package/template/src/shared/lib/ai.ts +8 -0
- package/template/src/shared/lib/minimax-media.ts +63 -0
- package/template/src/shared/lib/supabase/client.ts +8 -0
- package/template/src/shared/lib/supabase/middleware.ts +40 -0
- package/template/src/shared/lib/supabase/server.ts +26 -0
- package/template/src/test-setup.ts +1 -0
- package/template/tailwind.css +20 -0
- package/template/tsconfig.json +31 -0
- 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
|