Skip to content

Commit d415dbd

Browse files
committed
chore: add security doc, comparison page, tailwind config, agents guide
1 parent f1d6344 commit d415dbd

6 files changed

Lines changed: 379 additions & 1 deletion

File tree

AGENTS.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# AGENTS.md — AI Coding Agent Instructions
2+
3+
> This file provides project context and instructions for AI coding agents (Cursor, Claude, Copilot, Windsurf, Cline) working within this codebase.
4+
5+
## Project Overview
6+
7+
**Vibe Stack** is a production-ready Next.js 15 + Supabase boilerplate designed for AI-assisted development. It includes 22 `.mdc` architecture rule files that constrain AI models to generate secure, modern, production-grade code.
8+
9+
### Tech Stack
10+
- **Framework:** Next.js 15 (App Router, Server Components, Server Actions)
11+
- **Runtime:** React 19
12+
- **Database & Auth:** Supabase (PostgreSQL, Auth with SSR, Row Level Security)
13+
- **Payments:** Stripe (Checkout Sessions, Webhooks, Customer Portal)
14+
- **Email:** Resend (transactional email with HTML templates)
15+
- **Validation:** Zod (runtime validation at every boundary)
16+
- **Styling:** Tailwind CSS + shadcn/ui
17+
- **Language:** TypeScript (strict mode, no `any`)
18+
19+
### Architecture Principles
20+
1. **Server Components by default** — Only use `'use client'` when hooks or event handlers are required
21+
2. **`getUser()` over `getSession()`** — Server-side auth MUST use `getUser()` for JWT verification
22+
3. **`@supabase/ssr` only** — Never import from the deprecated `@supabase/auth-helpers-nextjs`
23+
4. **Zod at every boundary** — All user input validated before processing
24+
5. **RLS on every table** — Row Level Security is mandatory, never optional
25+
26+
## Directory Structure
27+
28+
```
29+
src/
30+
├── app/ # Next.js App Router pages and layouts
31+
│ ├── (auth)/ # Auth route group (login, signup)
32+
│ │ ├── actions.ts # Auth server actions with Zod validation
33+
│ │ ├── login/page.tsx # Login page (Server Component)
34+
│ │ └── signup/page.tsx # Signup page (Server Component)
35+
│ ├── auth/confirm/ # PKCE email verification callback
36+
│ ├── dashboard/ # Protected pages (requires auth)
37+
│ ├── api/webhooks/ # External webhook handlers (Stripe)
38+
│ ├── layout.tsx # Root layout (fonts, metadata, dark mode)
39+
│ ├── page.tsx # Landing page
40+
│ ├── loading.tsx # Global loading state
41+
│ ├── error.tsx # Global error boundary
42+
│ └── not-found.tsx # Custom 404
43+
├── lib/ # Business logic & integrations
44+
│ ├── supabase/ # Server + Client factories + middleware helper
45+
│ ├── stripe/ # Checkout session + customer portal helpers
46+
│ ├── email/ # Resend email templates (welcome, password reset)
47+
│ ├── env.ts # Type-safe environment variable access
48+
│ └── utils.ts # cn() helper and general utilities
49+
├── types/ # Shared TypeScript types
50+
│ └── index.ts # ActionResponse<T>, UserProfile, PaginatedResponse
51+
└── middleware.ts # Session refresh entry point
52+
53+
.cursor/
54+
├── rules/ # 22 .mdc architecture rules (auto-loaded by Cursor)
55+
└── mcp.json # 4 MCP server configurations
56+
57+
docs/
58+
├── VIBE-CODING.md # The 3-stage agentic loop framework
59+
├── ARCHITECTURE.md # 8 Architecture Decision Records
60+
└── MCP-SETUP.md # MCP server setup guide
61+
62+
n8n-workflows/ # 3 importable n8n automation templates
63+
```
64+
65+
## Key Patterns
66+
67+
### Server Actions
68+
All mutations use Server Actions with this pattern:
69+
```typescript
70+
'use server'
71+
import { z } from 'zod'
72+
import { createClient } from '@/lib/supabase/server'
73+
74+
const schema = z.object({ /* fields */ })
75+
76+
export async function myAction(formData: FormData): Promise<ActionResponse<T>> {
77+
const parsed = schema.safeParse(Object.fromEntries(formData))
78+
if (!parsed.success) return { error: 'Validation failed' }
79+
80+
const supabase = await createClient()
81+
const { data: { user } } = await supabase.auth.getUser()
82+
if (!user) return { error: 'Not authenticated' }
83+
84+
// ... business logic
85+
return { data: result }
86+
}
87+
```
88+
89+
### Auth Check Pattern
90+
```typescript
91+
// ALWAYS use this pattern in Server Components and Server Actions
92+
const supabase = await createClient()
93+
const { data: { user }, error } = await supabase.auth.getUser()
94+
if (error || !user) redirect('/login')
95+
```
96+
97+
### Environment Variables
98+
- `NEXT_PUBLIC_*` — Safe to expose to client (Supabase URL, app URL)
99+
- Everything else — Server-only (Stripe secret, Supabase service role, Resend key)
100+
- Access via `src/lib/env.ts` for type safety
101+
102+
## Rules System
103+
104+
The `.cursor/rules/` directory contains 22 `.mdc` files that auto-activate based on file globs. These rules override AI training data defaults to prevent:
105+
- Insecure auth patterns (`getSession()``getUser()`)
106+
- Deprecated package imports
107+
- Next.js 15 breaking changes (async params)
108+
- Missing RLS policies
109+
- Client-side Stripe usage
110+
- Hydration mismatches
111+
- N+1 query patterns
112+
113+
When adding new features, the AI should read and follow all applicable rules automatically.
114+
115+
## MCP Integrations
116+
117+
4 MCP servers are pre-configured in `.cursor/mcp.json`:
118+
- **GitHub MCP** — Read repos, PRs, issues, commits
119+
- **Supabase MCP** — Inspect database schema and RLS policies (read-only)
120+
- **Filesystem MCP** — Navigate project structure
121+
- **Browser MCP** — Take screenshots and test the running app
122+
123+
## Contributing
124+
125+
When adding new features:
126+
1. Follow the 3-stage agentic loop: Plan → Implement (in batches) → Verify
127+
2. Check applicable `.mdc` rules before writing code
128+
3. Use Server Components by default
129+
4. Validate all input with Zod
130+
5. Add RLS policies for any new tables
131+
6. Use conventional commits (`feat:`, `fix:`, `docs:`)

SECURITY.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Security Guide
2+
3+
Vibe Stack enforces security at the architecture level through `.mdc` rules that physically prevent AI coding assistants from generating insecure patterns.
4+
5+
## Security Rules Included
6+
7+
### Authentication Security
8+
| Rule | Threat Prevented |
9+
|---|---|
10+
| `supabase-auth-security.mdc` | **JWT forgery**`getSession()` accepts unverified tokens; `getUser()` cryptographically verifies every JWT |
11+
| `supabase-ssr-only.mdc` | **Deprecated auth** — blocks `@supabase/auth-helpers-nextjs` which mishandles App Router cookies |
12+
| `middleware-auth.mdc` | **Silent session expiry** — enforces `updateSession()` middleware to refresh tokens |
13+
14+
### Data Security
15+
| Rule | Threat Prevented |
16+
|---|---|
17+
| `supabase-rls.mdc` | **Data exposure** — every table must have RLS policies; without them, the anon key reads all data |
18+
| `database-design.mdc` | **Schema vulnerabilities** — enforces UUID primary keys, proper foreign key constraints, and audit columns |
19+
| `env-management.mdc` | **Secret leakage** — classifies env vars and prevents `NEXT_PUBLIC_` exposure of secrets |
20+
21+
### Input Validation
22+
| Rule | Threat Prevented |
23+
|---|---|
24+
| `typescript-strict.mdc` | **Type bypass** — bans `any`, enforces Zod schemas at every input boundary |
25+
| `server-actions.mdc` | **Injection attacks** — all Server Action inputs must pass Zod validation before processing |
26+
| `api-validation.mdc` | **Malformed requests** — Route Handler inputs validated and sanitized |
27+
28+
### Payment Security
29+
| Rule | Threat Prevented |
30+
|---|---|
31+
| `stripe-payments.mdc` | **PCI liability** — forces Stripe Checkout (never custom card forms); requires webhook signature verification |
32+
33+
### Application Security
34+
| Rule | Threat Prevented |
35+
|---|---|
36+
| `security.mdc` | **OWASP Top 10** — rate limiting, CSRF protection, XSS prevention, secure headers |
37+
| `hydration-safety.mdc` | **Hydration attacks** — prevents client/server mismatches that expose internal state |
38+
| `file-uploads.mdc` | **Malicious uploads** — file type validation, size limits, secure Supabase Storage patterns |
39+
40+
## Security Architecture
41+
42+
### The Secure Auth Flow
43+
```
44+
User submits login form
45+
→ Server Action validates input with Zod
46+
→ supabase.auth.signInWithPassword()
47+
→ Supabase issues JWT (cookie-based, httpOnly)
48+
→ Middleware refreshes token on every request
49+
→ Server Components verify with getUser() (NEVER getSession())
50+
```
51+
52+
### Why `getUser()` is Non-Negotiable
53+
54+
`getSession()` reads the JWT from cookies and trusts it at face value. An attacker can:
55+
1. Craft a fake JWT with any `user_id`
56+
2. Set it as a cookie
57+
3. `getSession()` will return it as a valid session
58+
59+
`getUser()` sends the JWT to Supabase's auth server for cryptographic verification. If the token is forged, tampered, or expired, it returns an error.
60+
61+
**Every AI model defaults to `getSession()` because the training data contains years of pre-2024 tutorials.** Our rule overrides this default.
62+
63+
### Row Level Security Pattern
64+
65+
Every table in the `public` schema must follow this pattern:
66+
67+
```sql
68+
-- 1. Create the table
69+
CREATE TABLE public.projects (
70+
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
71+
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
72+
name TEXT NOT NULL,
73+
created_at TIMESTAMPTZ DEFAULT now()
74+
);
75+
76+
-- 2. Enable RLS (MANDATORY)
77+
ALTER TABLE public.projects ENABLE ROW LEVEL SECURITY;
78+
79+
-- 3. Create policies
80+
CREATE POLICY "Users can only access own projects"
81+
ON public.projects FOR ALL
82+
USING (auth.uid() = user_id);
83+
```
84+
85+
Without step 2, any user with the `anon` key can read ALL rows in the table.
86+
87+
## Reporting Vulnerabilities
88+
89+
If you discover a security vulnerability in Vibe Stack, please [open a private issue](https://github.com/vibestackdev/vibe-stack/security/advisories/new) or email security concerns directly.
90+
91+
Do NOT open a public issue for security vulnerabilities.
92+
93+
---
94+
95+
*Vibe Stack security rules are updated whenever Next.js, Supabase, or Stripe release security-relevant changes. All paid tiers include lifetime updates.*

docs/COMPARISON.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Vibe Stack vs Other Boilerplates
2+
3+
A detailed, honest comparison of Vibe Stack against the major Next.js/Supabase boilerplates.
4+
5+
> **Our philosophy:** Other boilerplates sell you a locked box of code and 400 pages of docs. Vibe Stack gives your AI the intelligence to build the right architecture from scratch.
6+
7+
---
8+
9+
## The Fundamental Difference
10+
11+
| Approach | Traditional Boilerplate | Vibe Stack |
12+
|---|---|---|
13+
| **What you get** | A giant codebase you must learn | Architecture rules your AI follows |
14+
| **Learning curve** | Read 200-400 pages of docs | Clone, open in Cursor, start building |
15+
| **Customization** | Deviate from the "happy path" and things break | Rules adapt to YOUR architecture |
16+
| **AI compatibility** | AI doesn't know their conventions | AI reads `.mdc` rules automatically |
17+
| **Updates** | Merge conflicts when upgrading | Drop in new rule files — zero conflicts |
18+
19+
---
20+
21+
## Feature-by-Feature Comparison
22+
23+
| Feature | Vibe Stack ($149) | ShipFast ($169) | supastarter ($249) | MakerKit ($299) |
24+
|---|:---:|:---:|:---:|:---:|
25+
| **AI Architecture Rules** | ✅ 25 rules ||||
26+
| **MCP Server Configs** | ✅ 4 servers ||||
27+
| **AGENTS.md** |||||
28+
| **n8n Automations** | ✅ 3 workflows ||||
29+
| **Next.js 15 Support** |||||
30+
| **React 19** |||||
31+
| **Supabase Auth (SSR)** | ✅ (getUser) ||||
32+
| **Stripe Payments** |||||
33+
| **Email (Resend)** |||||
34+
| **Multi-tenancy** |||||
35+
| **Internationalization** |||||
36+
| **Admin Dashboard** | Basic ||||
37+
| **Blog/CMS** |||||
38+
| **Documentation Size** | 3 short docs | 400+ pages | 300+ pages | 200+ pages |
39+
| **Time to Understand** | 20 minutes | 3-4 hours | 2-3 hours | 1-2 days |
40+
| **Free Tier** | ✅ (5 rules) ||||
41+
42+
---
43+
44+
## When to Choose Each
45+
46+
### Choose **Vibe Stack** if:
47+
- You're building with AI (Cursor, Claude, Copilot) and want guardrails
48+
- You want to understand and control your architecture, not inherit someone else's
49+
- You prefer lightweight foundations over feature-heavy monoliths
50+
- You want your AI to read GitHub PRs and inspect your database (MCP)
51+
- You're a solo developer who ships fast
52+
53+
### Choose **ShipFast** if:
54+
- You want a complete, opinionated SaaS template out of the box
55+
- You're comfortable reading extensive documentation
56+
- You don't use AI coding tools heavily
57+
- You need SEO pages, blog, and admin panel from day one
58+
59+
### Choose **supastarter** if:
60+
- You need multi-tenancy and team/organization features
61+
- You need internationalization (i18n)
62+
- You're building a B2B SaaS with complex access control
63+
- You have budget for a premium price point
64+
65+
### Choose **MakerKit** if:
66+
- You need the most feature-complete solution available
67+
- You're building an enterprise-grade product
68+
- You need extensive customization documentation
69+
- Budget is not a primary constraint
70+
71+
---
72+
73+
## The AI-Native Advantage
74+
75+
Here's what happens when you ask Cursor to "add a settings page with profile editing" in each boilerplate:
76+
77+
**In ShipFast/MakerKit:**
78+
1. The AI doesn't know their conventions
79+
2. It generates patterns that conflict with their architecture
80+
3. You spend 30 minutes fixing the integration
81+
4. You read docs to understand what went wrong
82+
83+
**In Vibe Stack:**
84+
1. The AI reads the `.mdc` rules automatically
85+
2. It knows to use Server Components, `getUser()`, and Zod validation
86+
3. The generated code follows your project's architecture correctly
87+
4. You review and ship — 5 minutes total
88+
89+
This is the core insight: **Traditional boilerplates were designed for humans to read. Vibe Stack was designed for AI to read.**
90+
91+
---
92+
93+
*Last updated: April 2026. We regularly review competitor offerings to keep this comparison accurate.*

postcss.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
}

src/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const metadata: Metadata = {
2020
openGraph: {
2121
title: 'Vibe Stack — AI-Powered Next.js Boilerplate',
2222
description:
23-
'Ship production apps in hours, not months. 15 battle-tested AI rules prevent hallucinations.',
23+
'Ship production apps in hours, not months. 22 battle-tested AI architecture rules prevent hallucinations.',
2424
type: 'website',
2525
},
2626
}

tailwind.config.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import type { Config } from 'tailwindcss'
2+
3+
const config: Config = {
4+
darkMode: 'class',
5+
content: [
6+
'./src/app/**/*.{ts,tsx}',
7+
'./src/components/**/*.{ts,tsx}',
8+
'./src/lib/**/*.{ts,tsx}',
9+
],
10+
theme: {
11+
extend: {
12+
colors: {
13+
border: 'hsl(var(--border))',
14+
input: 'hsl(var(--input))',
15+
ring: 'hsl(var(--ring))',
16+
background: 'hsl(var(--background))',
17+
foreground: 'hsl(var(--foreground))',
18+
primary: {
19+
DEFAULT: 'hsl(var(--primary))',
20+
foreground: 'hsl(var(--primary-foreground))',
21+
},
22+
secondary: {
23+
DEFAULT: 'hsl(var(--secondary))',
24+
foreground: 'hsl(var(--secondary-foreground))',
25+
},
26+
destructive: {
27+
DEFAULT: 'hsl(var(--destructive))',
28+
foreground: 'hsl(var(--destructive-foreground))',
29+
},
30+
muted: {
31+
DEFAULT: 'hsl(var(--muted))',
32+
foreground: 'hsl(var(--muted-foreground))',
33+
},
34+
accent: {
35+
DEFAULT: 'hsl(var(--accent))',
36+
foreground: 'hsl(var(--accent-foreground))',
37+
},
38+
card: {
39+
DEFAULT: 'hsl(var(--card))',
40+
foreground: 'hsl(var(--card-foreground))',
41+
},
42+
},
43+
borderRadius: {
44+
lg: 'var(--radius)',
45+
md: 'calc(var(--radius) - 2px)',
46+
sm: 'calc(var(--radius) - 4px)',
47+
},
48+
},
49+
},
50+
plugins: [],
51+
}
52+
53+
export default config

0 commit comments

Comments
 (0)