Prerequisites
- Cursor editor installed
- Access to your documentation repository
Project rules
Create project rules that all team members can use. In your documentation repository root:Copy
mkdir -p .cursor
.cursor/rules.md for the Starter Kit project:
Copy
# Starter Kit Development Rule
You are an AI coding assistant specialized in building AI-powered SaaS applications using the Dev Kit for AI Starter Kit. You excel at Next.js 15, React 19 Server Components, TypeScript, and Tailwind CSS.
## Project Context
The Starter Kit is a production-ready Next.js template for building AI-powered applications that connect to the Dev Kit for AI Cloud API. It includes:
- **Framework**: Next.js 15.5.6 with App Router and Turbopack
- **UI**: React 19, TypeScript 5, Tailwind CSS 3.4.18, Radix UI
- **Authentication**: JWT-based via Cloud API with httpOnly cookies
- **Deployment**: Connects to hosted Cloud API at https://api.vibecoding.ad
- **Testing**: Vitest for integration, Playwright for E2E
## Core Development Principles
- Optimize for clarity: write explicit, well-structured code
- Use Server Components by default, "use client" only when necessary
- Follow TypeScript strict mode - explicit types for all functions
- Maintain consistent patterns with existing codebase
- Write user-friendly error messages
- Keep components focused and reusable
## Architecture Patterns
### Server Components First
Default to Server Components for better performance:
```tsx app/dashboard/page.tsx
// Server Component (default)
import { requireAuth } from '@/lib/auth-server'
export default async function DashboardPage() {
const user = await requireAuth()
return (
<div>
<h1>Welcome, {user.email}</h1>
</div>
)
}
```
Use "use client" only for interactivity:
```tsx components/theme-switcher.tsx
'use client'
import { useTheme } from 'next-themes'
export function ThemeSwitcher() {
const { theme, setTheme } = useTheme()
// Client-side interactivity
}
```
### Authentication Patterns
Protected pages use requireAuth():
```tsx app/protected/page.tsx
import { requireAuth } from '@/lib/auth-server'
export default async function ProtectedPage() {
const user = await requireAuth() // Auto-redirects if not authenticated
return <div>Protected content</div>
}
```
Client-side auth checks use hooks:
```tsx
'use client'
import { useCurrentUser, useIsAuthenticated } from '@/lib/auth-context'
export function UserProfile() {
const user = useCurrentUser()
const isAuthenticated = useIsAuthenticated()
if (!isAuthenticated) return <LoginPrompt />
return <div>{user.email}</div>
}
```
### Server Actions
All mutations use Server Actions:
```tsx app/actions.ts
'use server'
import { redirect } from 'next/navigation'
import { storeTokensInCookies } from '@/lib/auth-server'
export async function loginAction(formData: FormData) {
const email = formData.get('email') as string
const password = formData.get('password') as string
// Call Cloud API
const response = await fetch(`${apiUrl}/api/v1/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
})
if (!response.ok) {
return { error: 'Invalid credentials' }
}
const tokens = await response.json()
storeTokensInCookies(tokens)
redirect('/dashboard')
}
```
### Component Structure
Follow the component organization:
```
components/
├── ui/ # Radix UI primitives (buttons, forms, cards)
├── generic/ # Reusable cross-app components
├── project/ # App-specific (header, footer)
└── starter/ # Homepage marketing sections
```
Create reusable components:
```tsx components/generic/info-box.tsx
import { cn } from '@/lib/utils'
interface InfoBoxProps {
title: string
description: string
className?: string
}
export function InfoBox({ title, description, className }: InfoBoxProps) {
return (
<div className={cn('rounded-lg border p-4', className)}>
<h3 className="font-semibold">{title}</h3>
<p className="text-sm text-muted-foreground">{description}</p>
</div>
)
}
```
### Styling with Tailwind
Use Tailwind utilities with cn() helper:
```tsx
import { cn } from '@/lib/utils'
export function Button({ variant, className, ...props }: ButtonProps) {
return (
<button
className={cn(
'rounded-lg px-4 py-2 font-medium transition-colors',
variant === 'primary' && 'bg-primary text-primary-foreground',
variant === 'secondary' && 'bg-secondary text-secondary-foreground',
className
)}
{...props}
/>
)
}
```
Support dark mode with dark: prefix:
```tsx
<div className="bg-white dark:bg-gray-900 text-black dark:text-white">
Content adapts to theme
</div>
```
### Configuration
App config in config/app.config.ts:
```tsx
export const appConfig = {
name: 'My AI App',
description: 'AI-powered application',
logo: { text: 'MyApp', href: '/' },
header: {
nav: [
{ label: 'Home', href: '/' },
{ label: 'Dashboard', href: '/dashboard' },
]
},
footer: {
sections: [
{
title: 'Product',
links: [
{ label: 'Features', href: '/features' },
{ label: 'Pricing', href: '/pricing' },
]
}
]
}
}
```
Environment variables validated at startup:
```bash .env.local
DEVKIT4AI_MODE=project
NEXT_PUBLIC_API_URL=https://api.vibecoding.ad
DEVKIT4AI_DEVELOPER_KEY=dk_your_developer_key
DEVKIT4AI_PROJECT_ID=your-project-uuid
DEVKIT4AI_PROJECT_KEY=pk_your_project_key
```
### Error Handling
User-friendly error messages:
```tsx
try {
const response = await fetch(apiUrl)
if (!response.ok) {
throw new Error('Failed to fetch data')
}
return await response.json()
} catch (error) {
console.error('API Error:', error)
return {
error: 'Unable to load data. Please try again later.'
}
}
```
Form validation with clear feedback:
```tsx
'use client'
export function LoginForm() {
const [error, setError] = useState('')
async function handleSubmit(formData: FormData) {
const result = await loginAction(formData)
if (result?.error) {
setError(result.error)
}
}
return (
<form action={handleSubmit}>
{error && (
<div className="text-sm text-red-600 dark:text-red-400">
{error}
</div>
)}
{/* form fields */}
</form>
)
}
```
## File Naming Conventions
- **Components**: PascalCase (UserProfile.tsx, LoginForm.tsx)
- **Pages**: lowercase (page.tsx, layout.tsx, error.tsx)
- **Utilities**: kebab-case (auth-server.ts, deployment-mode.ts)
- **Config**: kebab-case with .config.ts (app.config.ts)
- **Actions**: actions.ts in relevant directory
## TypeScript Guidelines
Explicit function types:
```tsx
// Good - explicit types
async function fetchUser(userId: string): Promise<User | null> {
// implementation
}
// Avoid - implicit any
async function fetchUser(userId) {
// implementation
}
```
Interface for props:
```tsx
interface CardProps {
title: string
description?: string
onClick?: () => void
className?: string
}
export function Card({ title, description, onClick, className }: CardProps) {
// implementation
}
```
## Common Patterns
### Protected Routes
```tsx app/dashboard/layout.tsx
import { requireAuth } from '@/lib/auth-server'
export default async function DashboardLayout({
children
}: {
children: React.ReactNode
}) {
await requireAuth() // Redirects if not authenticated
return <div>{children}</div>
}
```
### API Integration
```tsx app/dashboard/actions.ts
'use server'
import { cookies } from 'next/headers'
import { hydrateDeploymentMode } from '@/lib/deployment-mode'
export async function fetchUserData() {
const config = await hydrateDeploymentMode()
const token = cookies().get('devkit4ai-token')?.value
const response = await fetch(`${config.backendApiUrl}/api/v1/user/data`, {
headers: {
'Authorization': `Bearer ${token}`,
...config.headers
}
})
if (!response.ok) {
return { error: 'Failed to fetch data' }
}
return response.json()
}
```
### Theme-Aware Components
```tsx
import { useTheme } from 'next-themes'
export function Logo() {
const { theme } = useTheme()
return (
<img
src={theme === 'dark' ? '/logo-dark.png' : '/logo-light.png'}
alt="Logo"
/>
)
}
```
## Testing Patterns
Integration tests with Vitest:
```tsx __tests__/auth.test.ts
import { describe, it, expect } from 'vitest'
import { sanitizeReturnUrl } from '@/lib/return-url'
describe('sanitizeReturnUrl', () => {
it('allows valid relative paths', () => {
expect(sanitizeReturnUrl('/dashboard')).toBe('/dashboard')
})
it('rejects absolute URLs', () => {
expect(sanitizeReturnUrl('https://evil.com')).toBe(null)
})
})
```
E2E tests with Playwright:
```tsx tests/e2e/login.spec.ts
import { test, expect } from '@playwright/test'
test('user can log in', async ({ page }) => {
await page.goto('/login')
await page.fill('[name="email"]', '[email protected]')
await page.fill('[name="password"]', 'password123')
await page.click('button[type="submit"]')
await expect(page).toHaveURL('/dashboard')
})
```
## Best Practices
1. **Server Components**: Default choice for better performance
2. **Type Safety**: Explicit types for all props and functions
3. **Error Handling**: User-friendly messages, console.error in development
4. **Security**: Never expose API keys, validate all inputs
5. **Accessibility**: Semantic HTML, proper ARIA labels, keyboard navigation
6. **Performance**: Use React cache() for expensive operations
7. **Code Organization**: Group related files, follow existing patterns
8. **Responsive Design**: Mobile-first with Tailwind breakpoints
## What to Avoid
- ❌ Client Components when Server Components suffice
- ❌ Inline styles instead of Tailwind classes
- ❌ Direct database access (use Cloud API)
- ❌ Storing tokens in localStorage (use httpOnly cookies)
- ❌ Generic error messages ("Something went wrong")
- ❌ Inconsistent naming conventions
- ❌ Hardcoded values instead of config files
- ❌ Missing TypeScript types or using `any`
## Quick Reference
**Key Files:**
- `lib/deployment-mode.ts` - Environment validation
- `lib/auth-server.ts` - Server-side auth helpers
- `lib/auth-context.tsx` - Client-side auth hooks
- `app/actions.ts` - Server actions for auth
- `config/app.config.ts` - App configuration
- `components/ui/` - Base UI primitives
- `app/layout.tsx` - Root layout with providers
**Common Commands:**
```bash
npm run dev # Start development server (port 3004)
npm run build # Production build
npm run test # Run all tests
npm run lint # Lint codebase
```
**Environment Setup:**
1. Clone repository
2. Copy `.env.local` with Cloud Admin credentials
3. Run `npm install`
4. Run `npm run dev`
5. Visit `http://localhost:3004`
**Resources:**
- [Starter Kit Documentation](https://docs.devkit4ai.com/starter-kit/installation)
- [Cloud API Reference](https://docs.devkit4ai.com/cloud-api/introduction)
- [Cloud Admin Guide](https://docs.devkit4ai.com/cloud-admin/getting-started)
- [GitHub Repository](https://github.com/VibeCodingStarter/starter-kit)
- Next.js 15 patterns: Server Components, Server Actions, App Router
- TypeScript best practices: Strict types, explicit interfaces
- Authentication: JWT-based with Cloud API integration
- Styling: Tailwind CSS with dark mode support
- Testing: Vitest and Playwright patterns
- Project structure: Component organization and file naming
Save configuration
Commit.cursor/rules.md to version control:
Copy
git add .cursor/rules.md
git commit -m "Add Cursor rules for Starter Kit development"
Usage tips
- Reference project files: Ask “How does authentication work?” and Cursor will use the rules as context
- Generate components: “Create a new dashboard card component” follows established patterns
- Debug issues: “Why isn’t my Server Component working?” gets context-aware help
- Code reviews: Cursor checks against project standards automatically

