# Makerkit Guidelines

## Project Stack
- Framework: Next.js 15 App Router, TypeScript, React, Node.js
- Backend: Supabase with Postgres
- UI: Shadcn UI, Tailwind CSS
- Key libraries: React Hook Form, React Query, Zod, Lucide React
- Focus: Code clarity, Readability, Best practices, Maintainability

## Project Structure
```
/apps/web/
  /app
    /home          # protected routes
      /(user)      # user workspace
      /[account]   # team workspace
    /(marketing)   # marketing pages
    /auth         # auth pages
  /components     # global components
  /config        # global config
  /lib           # global utils
  /content       # markdoc content
  /supabase      # supabase root
```

## Core Principles

### Data Flow
1. Server Components
   - Use Supabase Client directly via `getSupabaseServerClient`
   - Handle errors with proper boundaries
   - Example:
     ```tsx
     async function ServerComponent() {
       const client = getSupabaseServerClient();
       const { data, error } = await client.from('notes').select('*');
       if (error) return <ErrorComponent error={error} />;
       return <ClientComponent data={data} />;
     }
     ```

2. Client Components
   - Use React Query for data fetching
   - Implement proper loading states
   - Example:
     ```tsx
     function useNotes() {
       const { data, isLoading } = useQuery({
         queryKey: ['notes'],
         queryFn: async () => {
           const { data } = await fetch('/api/notes');
           return data;
         }
       });
       return { data, isLoading };
     }
     ```

### Server Actions
- Name files as "server-actions.ts" in `_lib/server` folder
- Export with "Action" suffix
- Use `enhanceAction` with proper typing
- Example:
  ```tsx
  export const createNoteAction = enhanceAction(
    async function (data, user) {
      const client = getSupabaseServerClient();
      const { error } = await client
        .from('notes')
        .insert({ ...data, user_id: user.id });
      if (error) throw error;
      return { success: true };
    },
    {
      auth: true,
      schema: NoteSchema,
    }
  );
  ```

### Route Handlers

- Use `enhanceRouteHandler` to wrap route handlers
- Use Route Handlers when data fetching from Client Components

## Database & Security

### RLS Policies
- Strive to create a safe, robust, secure and consistent database schema
- Always consider the compromises you need to make and explain them so I can make an educated decision. Follow up with the considerations make and explain them.
- Enable RLS by default and propose the required RLS policies
- `public.accounts` are the root tables for the application
- Implement cascading deletes when appropriate
- Ensure strong consistency considering triggers and constraints
- Always use Postgres schemas explicitly (e.g., `public.accounts`)

## Forms Pattern

### 1. Schema Definition
```tsx
// schema/note.schema.ts
import { z } from 'zod';

export const NoteSchema = z.object({
  title: z.string().min(1).max(100),
  content: z.string().min(1),
  category: z.enum(['work', 'personal']),
});
```

### 2. Form Component
```tsx
'use client';

export function NoteForm() {
  const [pending, startTransition] = useTransition();
  const form = useForm({
    resolver: zodResolver(NoteSchema),
    defaultValues: { title: '', content: '', category: 'personal' }
  });

  const onSubmit = (data: z.infer<typeof NoteSchema>) => {
    startTransition(async () => {
      try {
        await createNoteAction(data);
        form.reset();
      } catch (error) {
        // Handle error
      }
    });
  };

  return (
    <Form {...form}>
      <FormField name="title" render={({ field }) => (
        <FormItem>
          <FormLabel>Title</FormLabel>
          <FormControl>
            <Input {...field} />
          </FormControl>
          <FormMessage />
        </FormItem>
      )} />
      {/* Other fields */}
    </Form>
  );
}
```

## Error Handling

- Consider logging asynchronous requests in server code using the `@kit/shared/logger`
- Handle promises and async/await gracefully
- Consider the unhappy path and handle errors appropriately

### Structured Logging
```tsx
const ctx = {
  name: 'create-note',
  userId: user.id,
  noteId: note.id
};

logger.info(ctx, 'Creating new note...');

try {
  await createNote();
  logger.info(ctx, 'Note created successfully');
} catch (error) {
  logger.error(ctx, 'Failed to create note', { error });
  throw error;
}
```

## Context Management

In client components, we can use the `useUserWorkspace` hook to access the user's workspace data.

### Personal Account
```tsx
'use client';

function PersonalDashboard() {
  const { workspace, user } = useUserWorkspace();
  if (!workspace) return null;
  
  return (
    <div>
      <h1>Welcome, {user.email}</h1>
      <SubscriptionStatus status={workspace.subscription_status} />
    </div>
  );
}
```

### Team Account
In client components, we can use the `useTeamAccountWorkspace` hook to access the team account's workspace data. It only works under the `/home/[account]` route.

```tsx
'use client';

function TeamDashboard() {
  const { account, user } = useTeamAccountWorkspace();
  
  return (
    <div>
      <h1>{account.name}</h1>
      <RoleDisplay role={account.role} />
      <PermissionsList permissions={account.permissions} />
    </div>
  );
}
```

## UI Components

- Reusable UI components are defined in the "packages/ui" package named "@kit/ui".
- By exporting the component from the "exports" field, we can import it using the "@kit/ui/{component-name}" format.

## Creating Pages

When creating new pages ensure:
- The page is exported using `withI18n(Page)` to enable i18n.
- The page has the required and correct metadata using the `metadata` or `generateMetadata` function.
- Don't worry about authentication, it's handled in the middleware.
