- Use ESM for building the MCP Server - Added own Postgres dependency to MCP Server for querying tables and other entities in MCP - Vastly improved AI Agent rules - Added MCP Prompts for reviewing code and planning features - Minor refactoring
5.8 KiB
This file provides guidance to Claude Code when working with code in this repository.
Core Technologies
- Next.js 15 with App Router
- Supabase for database, auth, and storage
- React 19
- TypeScript
- Tailwind CSS 4 and Shadcn UI
- Turborepo
Monorepo Structure
apps/web- Main Next.js SaaS applicationapps/web/supabase- Supabase folder (migrations, schemas, tests)apps/e2e- Playwright end-to-end testspackages/features/*- Feature packagespackages/- Shared packages and utilitiestooling/- Build tools and development scripts
Multi-Tenant Architecture
Personal Accounts: Individual user accounts (auth.users.id = accounts.id) Team Accounts: Shared workspaces with members, roles, and permissions
Data associates with accounts via foreign keys for proper access control.
Essential Commands
Development Workflow
pnpm dev # Start all apps
pnpm --filter web dev # Main app (port 3000)
Database Operations
pnpm supabase:web:start # Start Supabase locally
pnpm --filter web supabase migration up # Apply new migrations
pnpm supabase:web:reset # Reset with latest schema (clean rebuild)
pnpm supabase:web:typegen # Generate TypeScript types
pnpm --filter web supabase:db:diff # Create migration
The typegen command must be run after applying migrations or resetting the database.
Database Workflow - CRITICAL SEQUENCE ⚠️
When adding new database features, ALWAYS follow this exact order:
- Create/modify schema file in
apps/web/supabase/schemas/XX-feature.sql - Generate migration:
pnpm --filter web supabase:db:diff -f <migration_name> - Apply changes:
pnpm --filter web supabase migration up(orpnpm supabase:web:resetfor clean rebuild) - Generate types:
pnpm supabase:web:typegen - Verify types exist before using in code
⚠️ NEVER skip step 2 - schema files alone don't create tables! The migration step is required to apply changes to the database.
Migration vs Reset:
- Use
migration upfor normal development (applies only new migrations) - Use
resetwhen you need a clean database state or have schema conflicts
Code Quality
pnpm format:fix
pnpm lint:fix
pnpm typecheck
- Run the typecheck command regularly to ensure your code is type-safe.
- Run the linter and the formatter when your task is complete.
Typescript
- Write clean, clear, well-designed, explicit TypeScript
- Avoid obvious comments
- Avoid unnecessary complexity or overly abstract code
- Always use implicit type inference, unless impossible
- You must avoid using
any - Handle errors gracefully using try/catch and appropriate error types
- Use service pattern for server-side APIs
- Add
server-onlyto code that is exclusively server-side - Never mix client and server imports from a file or a package
- Extract self-contained classes/utilities (ex. algortihmic code) from classes that cross the network boundary
React
- Encapsulate repeated blocks of code into reusable local components
- Write small, composable, explicit, well-named components
- Always use
react-hook-formand@kit/ui/formfor writing forms - Always use 'use client' directive for client components
- Add
data-testfor E2E tests where appropriate useEffectis a code smell and must be justified - avoid if possible- Do not write many (such as 4-5) separate
useState, prefer single state object (unless required) - Prefer server-side data fetching using RSC
- Display loading indicators (ex. with LoadingSpinner) component where appropriate
Next.js
- Use
enhanceActionfor Server Actions - Use
enhanceRouteHandlerfor API Routes - Export page components using the
withI18nutility - Add well-written page metadata to pages
- Redirect using
redirectfollowing a server action instead of using client-side router - Since
redirectthrows an error, handlecatchblock usingisRedirectErrorfromnext/dist/client/components/redirect-error
UI Components
- UI Components are placed at
packages/ui. Call MCP tool to list components to verify they exist.
Form Architecture
Always organize schemas for reusability between server actions and client forms:
_lib/
├── schemas/
│ └── feature.schema.ts # Shared Zod schemas
├── server/
│ └── server-actions.ts # Server actions import schemas
└── client/
└── forms.tsx # Forms import same schemas
Example implementation:
// _lib/schemas/project.schema.ts
export const CreateProjectSchema = z.object({
name: z.string().min(1).max(255),
description: z.string().optional(),
});
// _lib/server/project.mutations.ts
import { CreateProjectSchema } from '../schemas/project.schema';
export const createProjectAction = enhanceAction(
async (data) => { /* implementation */ },
{ schema: CreateProjectSchema }
);
// _components/create-project-form.tsx
import { CreateProjectSchema } from '../_lib/schemas/project.schema';
const form = useForm({
resolver: zodResolver(CreateProjectSchema)
});
Import Guidelines - ALWAYS Check These
UI Components: Always check @kit/ui first before external packages:
- Toast notifications:
import { toast } from '@kit/ui/sonner' - Forms:
import { Form, FormField, ... } from '@kit/ui/form' - All UI components: Use MCP tool to verify:
mcp__makerkit__get_components
React Hook Form Pattern:
// ❌ WRONG - Redundant generic with resolver
const form = useForm<FormData>({
resolver: zodResolver(Schema)
});
// ✅ CORRECT - Type inference from resolver
const form = useForm({
resolver: zodResolver(Schema)
});
Verification Steps
After implementation:
- Run
pnpm typecheck- Must pass without errors - Run
pnpm lint:fix- Auto-fix issues - Run
pnpm format:fix- Format code