Skip to content

Commit dd1a8a9

Browse files
committed
Initial commit: Vibe Stack - Next.js 15 boilerplate with 17 AI architecture rules
0 parents  commit dd1a8a9

54 files changed

Lines changed: 3503 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cursor/mcp.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"mcpServers": {
3+
"github": {
4+
"command": "npx",
5+
"args": [
6+
"-y",
7+
"@modelcontextprotocol/server-github"
8+
],
9+
"env": {
10+
"GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_GITHUB_PAT>"
11+
}
12+
},
13+
"filesystem": {
14+
"command": "npx",
15+
"args": [
16+
"-y",
17+
"@modelcontextprotocol/server-filesystem",
18+
"./"
19+
]
20+
},
21+
"supabase": {
22+
"command": "npx",
23+
"args": [
24+
"-y",
25+
"@supabase/mcp-server-supabase@latest",
26+
"--read-only"
27+
],
28+
"env": {
29+
"SUPABASE_ACCESS_TOKEN": "<YOUR_SUPABASE_PAT>"
30+
}
31+
},
32+
"browser": {
33+
"command": "npx",
34+
"args": [
35+
"-y",
36+
"@anthropic-ai/mcp-server-puppeteer"
37+
]
38+
}
39+
}
40+
}

.cursor/rules/ai-collaboration.mdc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
description: Instructions for AI agent code generation workflow
3+
globs: ["*"]
4+
---
5+
6+
# AI Collaboration Guidelines
7+
8+
The 3-stage agentic loop:
9+
10+
1. **PLAN:**
11+
"Analyze the current codebase and plan how to implement [feature]. List the files you'll modify and why. Don't write code yet."
12+
13+
2. **IMPLEMENT:**
14+
"Implement the plan. Follow all `.cursor/rules/` guidelines. If you're unsure about auth or RLS, check `supabase-auth-security.mdc`."
15+
16+
3. **REVIEW:**
17+
"Review what you just generated. Check for:
18+
- `getSession()` usage (MUST be `getUser()`)
19+
- Missing error boundaries or `loading.tsx`
20+
- Next.js 15 async layout/page params
21+
- TypeScript `any` types (use `unknown` or define interface)
22+
Report any issues before I run it."
23+
24+
Constraints:
25+
- NEVER give the AI a task longer than 200 words.
26+
- NEVER let the AI implement more than 3-4 files in one turn.
27+
- ALWAYS review the Git diff before committing.

.cursor/rules/api-design.mdc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
description: API route handler design patterns
3+
globs: ["**/app/api/**", "**/route.ts"]
4+
---
5+
6+
# API Design Patterns
7+
8+
Standard response format for Route Handlers:
9+
Success: `{ data: T, error: null }`
10+
Error: `{ data: null, error: { code: string, message: string } }`
11+
12+
HTTP status codes:
13+
- 200: Success (GET, PATCH)
14+
- 201: Created (POST)
15+
- 204: No content (DELETE)
16+
- 400: Validation error
17+
- 401: Unauthenticated
18+
- 403: Unauthorized
19+
- 404: Not found
20+
- 500: Server error
21+
22+
Route handler template:
23+
```typescript
24+
import { NextResponse } from 'next/server'
25+
import { createServerClient } from '@supabase/ssr'
26+
27+
export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) {
28+
const { id } = await params
29+
const supabase = createServerClient(...)
30+
31+
const { data: { user } } = await supabase.auth.getUser()
32+
if (!user) {
33+
return NextResponse.json(
34+
{ data: null, error: { code: 'UNAUTHORIZED', message: 'Login required' } },
35+
{ status: 401 }
36+
)
37+
}
38+
39+
// ... fetch data
40+
return NextResponse.json({ data: { id, status: 'ok' }, error: null })
41+
}
42+
```

.cursor/rules/error-handling.mdc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
description: Error boundaries and loading states guidelines
3+
globs: ["**/app/**"]
4+
---
5+
6+
# Error Handling and Loading States
7+
8+
EVERY page in `app/` router MUST have sibling files if it does data fetching:
9+
- `loading.tsx` (Suspense boundary)
10+
- `error.tsx` (Error boundary — must be `'use client'`)
11+
12+
`loading.tsx` template:
13+
```tsx
14+
export default function Loading() {
15+
return <div className="animate-pulse">Loading...</div>
16+
}
17+
```
18+
19+
`error.tsx` template:
20+
```tsx
21+
'use client'
22+
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
23+
return (
24+
<div>
25+
<h2>Something went wrong</h2>
26+
<button onClick={reset}>Try again</button>
27+
</div>
28+
)
29+
}
30+
```
31+
32+
Server Action error pattern:
33+
```typescript
34+
export async function createItem(formData: FormData) {
35+
try {
36+
// ... operation
37+
return { success: true }
38+
} catch (error) {
39+
return { error: 'Failed to create item' }
40+
}
41+
}
42+
```

.cursor/rules/git-conventions.mdc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
description: Git workflow and commit conventions for AI-assisted development
3+
globs: ["*"]
4+
---
5+
6+
# Git Conventions for Vibe Coders
7+
8+
Commit convention (Conventional Commits):
9+
- `feat:` add user authentication
10+
- `fix:` resolve RLS policy for shared projects
11+
- `chore:` update dependencies
12+
- `docs:` add API documentation
13+
- `refactor:` extract auth helper to separate module
14+
15+
Branch naming:
16+
- `feature/auth-flow`
17+
- `fix/rls-policy-bug`
18+
- `chore/update-dependencies`
19+
20+
ALWAYS run before commit (if available):
21+
1. `npm run lint`
22+
2. `npm run type-check`
23+
3. `npm test`
24+
25+
AI session workflow:
26+
- Create a new branch before starting any AI session
27+
- Review ALL AI-generated code before committing
28+
- Break large AI generations into multiple focused commits

.cursor/rules/nextjs15-params.mdc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
description: Critical Next.js 15 breaking changes regarding async params and searchParams
3+
globs: ["**/app/**/page.tsx", "**/app/**/layout.tsx", "**/app/**/route.ts"]
4+
alwaysApply: false
5+
---
6+
7+
# Next.js 15 Async Params (BREAKING CHANGE)
8+
9+
CRITICAL: In Next.js 15+, `params` and `searchParams` are ASYNC Promises.
10+
This is a breaking change from Next.js 14. The AI MUST await them.
11+
12+
## Rule: Always Use Promise Types
13+
14+
✅ CORRECT (Next.js 15):
15+
```tsx
16+
type PageProps = {
17+
params: Promise<{ slug: string }>
18+
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
19+
}
20+
21+
export default async function Page({ params, searchParams }: PageProps) {
22+
const { slug } = await params;
23+
const search = await searchParams;
24+
}
25+
```
26+
27+
❌ WRONG (outdated Next.js 14 pattern — will crash silently):
28+
```tsx
29+
// DO NOT GENERATE THIS PATTERN
30+
export default function Page({ params }: { params: { slug: string } }) {
31+
const { slug } = params; // BREAKS: params is a Promise in Next.js 15
32+
}
33+
```
34+
35+
## Rule: generateMetadata Also Uses Async Params
36+
```tsx
37+
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
38+
const { slug } = await params;
39+
return { title: `Post: ${slug}` }
40+
}
41+
```
42+
43+
## Rule: Layout Components MUST Await Params
44+
```tsx
45+
export default async function Layout({
46+
children,
47+
params,
48+
}: {
49+
children: React.ReactNode
50+
params: Promise<{ teamId: string }>
51+
}) {
52+
const { teamId } = await params;
53+
return <div>{children}</div>
54+
}
55+
```

.cursor/rules/performance.mdc

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
description: Next.js performance optimization — caching, bundle size, and Core Web Vitals
3+
globs: ["**/app/**", "**/components/**", "**/*.tsx"]
4+
alwaysApply: false
5+
---
6+
7+
# Performance & Caching
8+
9+
## Data Fetching Rules
10+
1. Use parallel fetching with `Promise.all()` when data is independent:
11+
```tsx
12+
// ✅ CORRECT: Parallel — both requests fire simultaneously
13+
const [user, posts] = await Promise.all([
14+
getUser(userId),
15+
getPosts(userId),
16+
])
17+
18+
// ❌ WRONG: Sequential — second request waits for first to finish
19+
const user = await getUser(userId)
20+
const posts = await getPosts(userId)
21+
```
22+
23+
2. NEVER fetch in loops (N+1 problem):
24+
```tsx
25+
// ❌ N+1: Fires 100 queries
26+
for (const id of userIds) {
27+
const user = await supabase.from('profiles').select().eq('id', id).single()
28+
}
29+
30+
// ✅ Batch: Fires 1 query
31+
const { data } = await supabase.from('profiles').select().in('id', userIds)
32+
```
33+
34+
3. Use `unstable_cache()` for expensive server-side computations:
35+
```tsx
36+
import { unstable_cache } from 'next/cache'
37+
38+
const getCachedPosts = unstable_cache(
39+
async (userId: string) => {
40+
return supabase.from('posts').select().eq('user_id', userId)
41+
},
42+
['user-posts'],
43+
{ revalidate: 60, tags: ['posts'] }
44+
)
45+
```
46+
47+
## Bundle Size Rules
48+
- Dynamic import heavy libraries: `const { Chart } = await import('chart.js')`
49+
- Use `next/dynamic` for client components that don't need SSR:
50+
```tsx
51+
import dynamic from 'next/dynamic'
52+
const RichTextEditor = dynamic(() => import('@/components/editor'), {
53+
ssr: false,
54+
loading: () => <div className="animate-pulse h-40 bg-muted rounded" />,
55+
})
56+
```
57+
- NEVER import entire icon libraries: `import { Search } from 'lucide-react'` not `import * as icons`
58+
59+
## Image Optimization
60+
- ALWAYS use `next/image` with explicit `width` and `height`
61+
- Set `priority={true}` on above-the-fold hero images for LCP
62+
- Use `placeholder="blur"` with `blurDataURL` for smooth loading
63+
- Serve modern formats: Next.js automatically converts to WebP/AVIF
64+
65+
## Core Web Vitals Targets
66+
- LCP (Largest Contentful Paint): < 2.5s
67+
- FID (First Input Delay): < 100ms
68+
- CLS (Cumulative Layout Shift): < 0.1

.cursor/rules/project-context.mdc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
description: Core project context — tech stack, folder structure, and global conventions
3+
alwaysApply: true
4+
---
5+
6+
# Vibe Stack — Project Context
7+
8+
## Tech Stack
9+
- Framework: Next.js 15 (App Router) with React 19
10+
- Language: TypeScript (strict mode)
11+
- Styling: Tailwind CSS + shadcn/ui components
12+
- Database: Supabase (PostgreSQL + RLS)
13+
- Auth: Supabase SSR (cookie-based, @supabase/ssr)
14+
- Validation: Zod
15+
- Payments: Stripe (server-side only)
16+
- Email: Resend
17+
- Icons: lucide-react
18+
19+
## Architecture Rules
20+
1. Default to Server Components. Only add 'use client' when the component needs interactivity.
21+
2. Push 'use client' to the smallest leaf component possible.
22+
3. All data fetching happens in Server Components or Server Actions.
23+
4. All mutations happen via Server Actions, never client-side fetch().
24+
5. All external input MUST be validated with Zod schemas.
25+
6. Never use getSession() on the server — always use getUser().
26+
7. All database tables MUST have Row Level Security (RLS) enabled.
27+
28+
## Folder Structure
29+
```
30+
src/
31+
├── app/ # Next.js App Router pages & layouts
32+
│ ├── (auth)/ # Auth route group (login, signup)
33+
│ ├── dashboard/ # Protected pages (behind middleware)
34+
│ └── api/ # Route handlers (webhooks, public APIs)
35+
├── components/ # Reusable React components
36+
│ ├── ui/ # shadcn/ui primitives
37+
│ └── [feature]/ # Feature-specific components
38+
├── lib/ # Utilities & third-party configs
39+
│ ├── supabase/ # Supabase client factories
40+
│ ├── stripe/ # Stripe helpers (server-only)
41+
│ └── utils.ts # General utilities (cn helper)
42+
└── types/ # Shared TypeScript types
43+
```
44+
45+
## Naming Conventions
46+
- Files: kebab-case (e.g., `user-profile.tsx`)
47+
- Components: PascalCase (e.g., `UserProfile`)
48+
- Server Actions: camelCase verbs (e.g., `createTodo`, `updateProfile`)
49+
- Types/Interfaces: PascalCase with `interface` preferred over `type`
50+
- Database tables: snake_case (e.g., `user_profiles`)

0 commit comments

Comments
 (0)