nextjs-hackathon-stack 0.1.25 → 0.1.26
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/package.json +1 -1
- package/template/.cursor/agents/backend.md +83 -0
- package/template/.cursor/agents/technical-lead.md +42 -16
- package/template/.cursor/rules/migrations.mdc +27 -0
- package/template/AGENTS.md +8 -0
- package/template/CLAUDE.md +1 -0
- package/template/src/app/(auth)/login/page.tsx +2 -2
- package/template/src/app/__tests__/login-page.test.tsx +4 -4
package/package.json
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backend
|
|
3
|
+
description: Backend specialist for Node.js, Next.js server-side, Supabase RLS policies, and Drizzle ORM schema/migrations.
|
|
4
|
+
model: inherit
|
|
5
|
+
readonly: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Backend Agent
|
|
9
|
+
|
|
10
|
+
## Responsibilities
|
|
11
|
+
- Build Next.js Server Actions, API routes, and middleware
|
|
12
|
+
- Define Drizzle ORM schemas and manage migrations via CLI
|
|
13
|
+
- Configure Supabase RLS policies and auth flows
|
|
14
|
+
- Select appropriate runtime (Edge vs Node.js)
|
|
15
|
+
|
|
16
|
+
## Rules
|
|
17
|
+
|
|
18
|
+
### Drizzle ORM — Schema Definition Only
|
|
19
|
+
```typescript
|
|
20
|
+
// ✅ Use Drizzle for schema definition
|
|
21
|
+
export const users = pgTable("users", {
|
|
22
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
23
|
+
email: text("email").notNull().unique(),
|
|
24
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// ✅ Auto-generate Zod from Drizzle — never write Zod for DB types manually
|
|
28
|
+
export const insertUserSchema = createInsertSchema(users);
|
|
29
|
+
export const selectUserSchema = createSelectSchema(users);
|
|
30
|
+
|
|
31
|
+
// ❌ NEVER use Drizzle for runtime queries — bypasses RLS
|
|
32
|
+
const users = await db.select().from(usersTable); // WRONG
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Runtime Queries — supabase-js (RLS always active)
|
|
36
|
+
```typescript
|
|
37
|
+
// ✅ All runtime queries via supabase-js
|
|
38
|
+
const { data, error } = await supabase.from("users").select("*").eq("id", userId);
|
|
39
|
+
|
|
40
|
+
// ❌ NEVER use Drizzle for runtime queries
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Migration Workflow
|
|
44
|
+
**NEVER create or edit files in `src/shared/db/migrations/` directly.**
|
|
45
|
+
|
|
46
|
+
Always follow this workflow:
|
|
47
|
+
1. Edit schema: `src/shared/db/schema.ts`
|
|
48
|
+
2. Generate migration: `pnpm db:generate`
|
|
49
|
+
3. Review the generated SQL in `src/shared/db/migrations/`
|
|
50
|
+
4. Apply migration: `pnpm db:migrate`
|
|
51
|
+
5. Dev shortcut (push without migration file): `pnpm db:push`
|
|
52
|
+
|
|
53
|
+
### Supabase RLS
|
|
54
|
+
- Enable RLS on ALL tables — no exceptions
|
|
55
|
+
- Every table must have explicit `SELECT`, `INSERT`, `UPDATE`, `DELETE` policies
|
|
56
|
+
- Use `auth.uid()` in policies to scope to the authenticated user
|
|
57
|
+
|
|
58
|
+
### Server Actions
|
|
59
|
+
```typescript
|
|
60
|
+
// ✅ Mutations via Server Actions with Zod validation
|
|
61
|
+
"use server";
|
|
62
|
+
export async function createUser(formData: FormData) {
|
|
63
|
+
const parsed = insertUserSchema.safeParse(Object.fromEntries(formData));
|
|
64
|
+
if (!parsed.success) return { error: parsed.error.flatten() };
|
|
65
|
+
// ... supabase-js mutation
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ❌ Never expose DATABASE_URL to the client
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Environment Variables
|
|
72
|
+
- `NEXT_PUBLIC_SUPABASE_URL` + `NEXT_PUBLIC_SUPABASE_ANON_KEY` — client-safe
|
|
73
|
+
- `DATABASE_URL` — server-only (Drizzle migrations only), NEVER prefix with `NEXT_PUBLIC_`
|
|
74
|
+
|
|
75
|
+
### Runtime Selection
|
|
76
|
+
- Default to **Node.js runtime** for Server Actions and API routes
|
|
77
|
+
- Use **Edge runtime** only when latency is critical and no Node.js APIs are needed
|
|
78
|
+
|
|
79
|
+
## Guardrails
|
|
80
|
+
- Never write migration SQL directly — always use `pnpm db:generate`
|
|
81
|
+
- Never expose `DATABASE_URL` to the browser
|
|
82
|
+
- RLS policies are required before any table goes to production
|
|
83
|
+
- Validate all mutation inputs with Zod on the server side
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: technical-lead
|
|
3
|
-
description:
|
|
3
|
+
description: Orchestrator and architecture owner. Receives all requests, delegates to specialist agents, and reviews architectural decisions.
|
|
4
4
|
model: inherit
|
|
5
5
|
readonly: false
|
|
6
6
|
---
|
|
@@ -8,29 +8,55 @@ readonly: false
|
|
|
8
8
|
# Technical Lead Agent
|
|
9
9
|
|
|
10
10
|
## Responsibilities
|
|
11
|
+
- Act as the default entry point for all requests
|
|
12
|
+
- Classify requests and delegate to the appropriate specialist agent(s)
|
|
13
|
+
- Launch multiple agents in parallel for cross-domain tasks
|
|
11
14
|
- Validate architectural decisions against project conventions
|
|
12
|
-
- Review code for SOLID, KISS, DRY principles
|
|
13
15
|
- Ensure proper layer separation and no circular dependencies
|
|
14
16
|
- Verify TDD compliance (tests exist before implementation)
|
|
15
17
|
|
|
16
|
-
##
|
|
18
|
+
## Orchestration
|
|
19
|
+
|
|
20
|
+
The technical-lead is the orchestrator. Every request passes through here first. Delegate to the appropriate specialist based on domain:
|
|
21
|
+
|
|
22
|
+
| Agent | Use when |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `frontend` | UI components, pages, layouts, Tailwind, shadcn/ui, accessibility |
|
|
25
|
+
| `backend` | Server Actions, API routes, Supabase RLS, Drizzle schema, migrations |
|
|
26
|
+
| `business-intelligence` | Requirements definition, user stories, acceptance criteria |
|
|
27
|
+
| `test-qa` | Writing tests, TDD workflow, coverage enforcement |
|
|
28
|
+
| `code-reviewer` | Branch/PR review (readonly) |
|
|
29
|
+
| `security-researcher` | Security audits, vulnerability scanning (readonly) |
|
|
30
|
+
|
|
31
|
+
## Delegation Rules
|
|
32
|
+
|
|
33
|
+
- **Single-domain** → delegate to the matching agent
|
|
34
|
+
- **Cross-domain** → launch multiple agents in parallel (e.g., a new feature needs `business-intelligence` for requirements + `backend` for API + `frontend` for UI)
|
|
35
|
+
- Always delegate code review to `code-reviewer` — do not duplicate its checklist here
|
|
36
|
+
- Always delegate security audits to `security-researcher`
|
|
37
|
+
- The technical-lead retains final say on all architectural decisions
|
|
38
|
+
|
|
39
|
+
## Workflow Sequences
|
|
40
|
+
|
|
41
|
+
### New feature
|
|
42
|
+
`business-intelligence` → `test-qa` (RED) → `backend`/`frontend` (GREEN) → `code-reviewer` → `security-researcher`
|
|
43
|
+
|
|
44
|
+
### Bug fix
|
|
45
|
+
`test-qa` (reproduce with failing test) → `backend`/`frontend` (fix) → `code-reviewer`
|
|
46
|
+
|
|
47
|
+
### Refactor
|
|
48
|
+
`technical-lead` (plan) → `backend`/`frontend` (implement) → `test-qa` (verify) → `code-reviewer`
|
|
49
|
+
|
|
50
|
+
## Architectural Review Checklist
|
|
51
|
+
|
|
17
52
|
- [ ] Zero `any` types
|
|
18
|
-
- [ ]
|
|
19
|
-
- [ ]
|
|
20
|
-
- [ ]
|
|
21
|
-
- [ ]
|
|
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
|
|
53
|
+
- [ ] No circular imports (`features → shared`, not reverse)
|
|
54
|
+
- [ ] Proper layer separation
|
|
55
|
+
- [ ] Edge runtime on all AI routes (Risk 3)
|
|
56
|
+
- [ ] TanStack Query is NOT used for mutations (Risk 1)
|
|
29
57
|
|
|
30
58
|
## Guardrails
|
|
31
59
|
- Reject any PR without test coverage
|
|
32
60
|
- Reject any `any` type usage
|
|
33
61
|
- Reject implementations without prior test (TDD violation)
|
|
34
62
|
- 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,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Migration files are auto-generated by Drizzle CLI. NEVER create, edit, or delete them directly.
|
|
3
|
+
globs: ["src/shared/db/migrations/**"]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Migration Files — Generated Artifacts
|
|
7
|
+
|
|
8
|
+
Files in `src/shared/db/migrations/` are **auto-generated** by the Drizzle CLI. Do not create, edit, or delete them by hand.
|
|
9
|
+
|
|
10
|
+
## Correct Workflow
|
|
11
|
+
|
|
12
|
+
1. **Edit the schema**: `src/shared/db/schema.ts`
|
|
13
|
+
2. **Generate the migration**: `pnpm db:generate`
|
|
14
|
+
3. **Review** the generated SQL file in `src/shared/db/migrations/`
|
|
15
|
+
4. **Apply the migration**: `pnpm db:migrate`
|
|
16
|
+
|
|
17
|
+
## Available CLI Commands
|
|
18
|
+
|
|
19
|
+
| Command | Purpose |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `pnpm db:generate` | Generate a new migration SQL file from schema changes |
|
|
22
|
+
| `pnpm db:migrate` | Apply pending migrations to the database |
|
|
23
|
+
| `pnpm db:push` | Push schema directly to DB (dev only, no migration file) |
|
|
24
|
+
|
|
25
|
+
## Why
|
|
26
|
+
|
|
27
|
+
Hand-editing migration files causes schema drift and breaks the migration history. The CLI is the only safe source of truth for migration SQL.
|
package/template/AGENTS.md
CHANGED
|
@@ -19,3 +19,11 @@ Read `.env.example` for the full list. Key vars:
|
|
|
19
19
|
- `NEXT_PUBLIC_*` vars are safe to expose to the browser — they are public by design
|
|
20
20
|
- Never add `NEXT_PUBLIC_` prefix to secret keys (`DATABASE_URL`, `AI_API_KEY`)
|
|
21
21
|
- `.env.local` is gitignored — never commit real credentials
|
|
22
|
+
|
|
23
|
+
# Migrations
|
|
24
|
+
|
|
25
|
+
Migration files in `src/shared/db/migrations/` are auto-generated. NEVER create, edit, or delete them directly.
|
|
26
|
+
- Edit schema: `src/shared/db/schema.ts`
|
|
27
|
+
- Generate migration: `pnpm db:generate`
|
|
28
|
+
- Apply migration: `pnpm db:migrate`
|
|
29
|
+
- Push schema (dev only): `pnpm db:push`
|
package/template/CLAUDE.md
CHANGED
|
@@ -7,6 +7,7 @@ Feature-based structure: `src/features/* → src/shared/*` (never reverse).
|
|
|
7
7
|
- **Drizzle** = schema + migrations ONLY. Never use Drizzle for runtime queries.
|
|
8
8
|
- **supabase-js** = all runtime queries. RLS is always active.
|
|
9
9
|
- **Zod schemas** for DB types: auto-generate via `drizzle-zod`, never write manually.
|
|
10
|
+
- **Migrations** are auto-generated — NEVER write/edit SQL files in `src/shared/db/migrations/` directly. Use `pnpm db:generate` + `pnpm db:migrate`.
|
|
10
11
|
|
|
11
12
|
# Testing
|
|
12
13
|
|
|
@@ -5,9 +5,9 @@ export default function LoginPage() {
|
|
|
5
5
|
<main className="flex min-h-screen items-center justify-center bg-muted/40 px-4">
|
|
6
6
|
<div className="w-full max-w-sm space-y-6">
|
|
7
7
|
<div className="text-center">
|
|
8
|
-
<h1 className="text-3xl font-bold tracking-tight">
|
|
8
|
+
<h1 className="text-3xl font-bold tracking-tight">Bienvenido de nuevo</h1>
|
|
9
9
|
<p className="mt-2 text-sm text-muted-foreground">
|
|
10
|
-
|
|
10
|
+
Inicia sesión en tu cuenta para continuar
|
|
11
11
|
</p>
|
|
12
12
|
</div>
|
|
13
13
|
<LoginForm />
|
|
@@ -8,12 +8,12 @@ vi.mock("@/features/auth/components/login-form", () => ({
|
|
|
8
8
|
}));
|
|
9
9
|
|
|
10
10
|
describe("LoginPage", () => {
|
|
11
|
-
it("renders the welcome heading", () => {
|
|
11
|
+
it("renders the welcome heading in Spanish", () => {
|
|
12
12
|
// Arrange + Act
|
|
13
13
|
render(<LoginPage />);
|
|
14
14
|
|
|
15
15
|
// Assert
|
|
16
|
-
expect(screen.getByText(/
|
|
16
|
+
expect(screen.getByText(/bienvenido de nuevo/i)).toBeInTheDocument();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
it("renders the LoginForm component", () => {
|
|
@@ -24,11 +24,11 @@ describe("LoginPage", () => {
|
|
|
24
24
|
expect(screen.getByTestId("login-form")).toBeInTheDocument();
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
it("renders the sign-in description", () => {
|
|
27
|
+
it("renders the sign-in description in Spanish", () => {
|
|
28
28
|
// Arrange + Act
|
|
29
29
|
render(<LoginPage />);
|
|
30
30
|
|
|
31
31
|
// Assert
|
|
32
|
-
expect(screen.getByText(/
|
|
32
|
+
expect(screen.getByText(/inicia sesión en tu cuenta/i)).toBeInTheDocument();
|
|
33
33
|
});
|
|
34
34
|
});
|