1. Added Claude Code sub-agents 2. Added PRD tool to MCP Server 3. Added MCP Server UI to Dev Tools 4. Improved MCP Server Database Tool 5. Updated dependencies
207 lines
6.6 KiB
Markdown
207 lines
6.6 KiB
Markdown
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**, Shadcn UI, Lucide React
|
|
- **Turborepo**
|
|
|
|
## Monorepo Structure
|
|
|
|
- `apps/web` - Main Next.js SaaS application
|
|
- `apps/web/supabase` - Supabase folder (migrations, schemas, tests)
|
|
- `apps/e2e` - Playwright end-to-end tests
|
|
- `packages/features/*` - Feature packages
|
|
- `packages/` - Shared packages and utilities
|
|
|
|
## 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
|
|
|
|
```bash
|
|
pnpm dev # Start all apps
|
|
```
|
|
|
|
### Database Operations
|
|
|
|
```bash
|
|
pnpm supabase:web:start # Start Supabase locally
|
|
pnpm --filter web supabase migrations 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.
|
|
|
|
## 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 `import 'server-only';` to 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-form` and `@kit/ui/form` for writing forms
|
|
- Always use 'use client' directive for client components
|
|
- Add `data-test` for E2E tests where appropriate
|
|
- `useEffect` is 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 `enhanceAction` for Server Actions
|
|
- Use `use server` in server actions files
|
|
- Use `enhanceRouteHandler` for API Routes
|
|
- Export page components using the `withI18n` utility
|
|
- Add well-written page metadata to pages
|
|
- Redirect using `redirect` following a server action instead of using client-side router
|
|
- Since `redirect` throws an error, handle `catch` block using `isRedirectError` from `next/dist/client/components/redirect-error` in client-side forms when calling the server action
|
|
|
|
|
|
## Data Fetching Architecture
|
|
|
|
Makerkit uses a clear separation between data fetching and mutations:
|
|
|
|
### Server Components with Loaders (Reading Data)
|
|
|
|
**Pattern**: Use async server components that call loader functions for initial data fetching.
|
|
|
|
```typescript
|
|
// Page component (apps/web/app/home/[account]/page.tsx)
|
|
async function TeamAccountPage({ params }: Props) {
|
|
const client = getSupabaseServerClient();
|
|
const slug = (await params).account;
|
|
|
|
const [projects, workspace] = await loadProjectsPageData(client, slug);
|
|
|
|
return <ProjectsList projects={projects} />;
|
|
}
|
|
|
|
// Loader function (_lib/server/projects-page.loader.ts)
|
|
import 'server-only';
|
|
|
|
export async function loadProjectsPageData(
|
|
client: SupabaseClient<Database>,
|
|
slug: string,
|
|
) {
|
|
return Promise.all([
|
|
loadProjects(client, slug),
|
|
loadTeamWorkspace(slug),
|
|
]);
|
|
}
|
|
|
|
async function loadProjects(client: SupabaseClient<Database>, slug: string) {
|
|
const { data, error } = await client.rpc('get_team_projects', {
|
|
account_slug: slug,
|
|
});
|
|
|
|
if (error) throw error;
|
|
return data ?? [];
|
|
}
|
|
```
|
|
|
|
### Server Actions (Mutations Only)
|
|
|
|
**Pattern**: Use `enhanceAction` for create/update/delete operations with schema validation.
|
|
|
|
```typescript
|
|
// server-actions.ts
|
|
'use server';
|
|
|
|
import { enhanceAction } from '@kit/next/actions';
|
|
|
|
export const createProject = enhanceAction(
|
|
async (data) => {
|
|
const client = getSupabaseServerClient();
|
|
const service = createProjectsService();
|
|
|
|
const response = await service.createProject(data);
|
|
|
|
if (response.error) {
|
|
throw response.error;
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: response.data,
|
|
};
|
|
},
|
|
{
|
|
schema: CreateProjectSchema,
|
|
},
|
|
);
|
|
```
|
|
|
|
### Authorization & RLS
|
|
|
|
- **Server Components**: RLS automatically enforces access control
|
|
- **Server Actions**: RLS validates permissions on mutations
|
|
- **No manual auth checks needed** when using standard Supabase client
|
|
- **Admin client**: Only for bypassing RLS (rare cases, requires careful manual validation)
|
|
|
|
## File Organization Patterns
|
|
|
|
### Route Structure
|
|
```
|
|
apps/web/app/home/[account]/
|
|
├── page.tsx # Team dashboard
|
|
├── members/
|
|
│ ├── page.tsx # Members listing
|
|
│ └── _lib/server/ # Server-side utilities
|
|
│ └── members-page.loader.ts
|
|
├── projects/ # New feature example
|
|
│ ├── page.tsx # Projects listing
|
|
│ ├── [id]/ # Individual project
|
|
│ │ └── page.tsx # Project detail page
|
|
│ ├── _components/ # Feature-specific components
|
|
│ │ ├── project-list.tsx
|
|
│ │ └── create-project-form.tsx
|
|
│ └── _lib/
|
|
│ ├── server/ # Server-side logic
|
|
│ │ ├── projects-page.loader.ts
|
|
│ │ └── projects-server-actions.ts
|
|
│ └── schemas/ # Zod validation schemas
|
|
│ └── project.schema.ts
|
|
└── _components/ # Shared team account components
|
|
└── team-account-layout-page-header.tsx
|
|
```
|
|
|
|
### Naming Conventions
|
|
- **Pages**: `page.tsx` (Next.js convention)
|
|
- **Loaders**: `{feature}-page.loader.ts`
|
|
- **Actions**: `{feature}-server-actions.ts`
|
|
- **Schemas**: `{feature}.schema.ts`
|
|
- **Components**: `kebab-case.tsx`
|
|
|
|
## UI Components
|
|
|
|
UI Components are placed at `packages/ui`. Call MCP tool to list components to verify they exist.
|
|
|
|
## Verification Steps
|
|
|
|
After implementation:
|
|
1. **Run `pnpm typecheck`** - Must pass without errors
|
|
2. **Run `pnpm lint:fix`** - Auto-fix issues
|
|
3. **Run `pnpm format:fix`** - Format code |