Optimized agents rules subfolders, dependencies updates (#355)

* Update AGENTS.md and CLAUDE.md for improved clarity and structure
* Added MCP Server
* Added missing triggers to tables that should have used them
* Updated all dependencies
* Fixed rare bug in React present in the Admin layout which prevents navigating to pages (sometimes...)
This commit is contained in:
Giancarlo Buomprisco
2025-09-17 11:36:02 +08:00
committed by GitHub
parent 9fae142f2d
commit 533dfba5b9
83 changed files with 9223 additions and 2974 deletions

435
packages/next/CLAUDE.md Normal file
View File

@@ -0,0 +1,435 @@
# Next.js Utilities Instructions
This file contains instructions for working with Next.js utilities including server actions and route handlers.
## Server Actions Implementation
Always use `enhanceAction` from `@packages/next/src/actions/index.ts`:
```typescript
'use server';
import { enhanceAction } from '@kit/next/actions';
import { z } from 'zod';
// Define your schema
const CreateNoteSchema = z.object({
title: z.string().min(1, 'Title is required'),
content: z.string().min(1, 'Content is required'),
accountId: z.string().uuid('Invalid account ID'),
});
export const createNoteAction = enhanceAction(
async function (data, user) {
// data is automatically validated against the schema
// user is automatically authenticated if auth: true
const client = getSupabaseServerClient();
const { data: note, error } = await client
.from('notes')
.insert({
title: data.title,
content: data.content,
account_id: data.accountId,
user_id: user.id,
})
.select()
.single();
if (error) {
throw error;
}
return { success: true, note };
},
{
auth: true, // Require authentication
schema: CreateNoteSchema, // Validate input with Zod
},
);
```
### Server Action Examples
- Team billing: `@apps/web/app/home/[account]/billing/_lib/server/server-actions.ts`
- Personal settings: `@apps/web/app/home/(user)/settings/_lib/server/server-actions.ts`
### Server Action Options
```typescript
export const myAction = enhanceAction(
async function (data, user, requestData) {
// data: validated input data
// user: authenticated user (if auth: true)
// requestData: additional request information
return { success: true };
},
{
auth: true, // Require authentication (default: false)
schema: MySchema, // Zod schema for validation (optional)
// Additional options available
},
);
```
## Route Handlers (API Routes)
Use `enhanceRouteHandler` from `@packages/next/src/routes/index.ts`:
```typescript
import { enhanceRouteHandler } from '@kit/next/routes';
import { NextResponse } from 'next/server';
import { z } from 'zod';
// Define your schema
const CreateItemSchema = z.object({
name: z.string().min(1),
description: z.string().optional(),
});
export const POST = enhanceRouteHandler(
async function ({ body, user, request }) {
// body is validated against schema
// user is available if auth: true
// request is the original NextRequest
const client = getSupabaseServerClient();
const { data, error } = await client
.from('items')
.insert({
name: body.name,
description: body.description,
user_id: user.id,
})
.select()
.single();
if (error) {
return NextResponse.json(
{ error: 'Failed to create item' },
{ status: 500 }
);
}
return NextResponse.json({ success: true, data });
},
{
auth: true, // Require authentication
schema: CreateItemSchema, // Validate request body
},
);
export const GET = enhanceRouteHandler(
async function ({ user, request }) {
const url = new URL(request.url);
const limit = url.searchParams.get('limit') || '10';
const client = getSupabaseServerClient();
const { data, error } = await client
.from('items')
.select('*')
.eq('user_id', user.id)
.limit(parseInt(limit));
if (error) {
return NextResponse.json(
{ error: 'Failed to fetch items' },
{ status: 500 }
);
}
return NextResponse.json({ data });
},
{
auth: true,
// No schema needed for GET requests
},
);
```
### Route Handler Options
```typescript
export const POST = enhanceRouteHandler(
async function ({ body, user, request }) {
// Handler function
return NextResponse.json({ success: true });
},
{
auth: true, // Require authentication (default: false)
schema: MySchema, // Zod schema for body validation (optional)
// Additional options available
},
);
```
## Error Handling Patterns
### Server Actions with Error Handling
```typescript
export const createNoteAction = enhanceAction(
async function (data, user) {
const logger = await getLogger();
const ctx = { name: 'create-note', userId: user.id };
try {
logger.info(ctx, 'Creating note');
const client = getSupabaseServerClient();
const { data: note, error } = await client
.from('notes')
.insert({
title: data.title,
content: data.content,
user_id: user.id,
})
.select()
.single();
if (error) {
logger.error({ ...ctx, error }, 'Failed to create note');
throw error;
}
logger.info({ ...ctx, noteId: note.id }, 'Note created successfully');
return { success: true, note };
} catch (error) {
logger.error({ ...ctx, error }, 'Create note action failed');
throw error;
}
},
{
auth: true,
schema: CreateNoteSchema,
},
);
```
### Route Handler with Error Handling
```typescript
export const POST = enhanceRouteHandler(
async function ({ body, user }) {
const logger = await getLogger();
const ctx = { name: 'api-create-item', userId: user.id };
try {
logger.info(ctx, 'Processing API request');
// Process request
const result = await processRequest(body, user);
logger.info({ ...ctx, result }, 'API request successful');
return NextResponse.json({ success: true, data: result });
} catch (error) {
logger.error({ ...ctx, error }, 'API request failed');
if (error.message.includes('validation')) {
return NextResponse.json(
{ error: 'Invalid input data' },
{ status: 400 }
);
}
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
},
{
auth: true,
schema: CreateItemSchema,
},
);
```
## Client-Side Integration
### Using Server Actions in Components
```tsx
'use client';
import { useTransition } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { toast } from '@kit/ui/sonner';
import { Button } from '@kit/ui/button';
import { createNoteAction } from './actions';
import { CreateNoteSchema } from './schemas';
function CreateNoteForm() {
const [isPending, startTransition] = useTransition();
const form = useForm({
resolver: zodResolver(CreateNoteSchema),
defaultValues: {
title: '',
content: '',
},
});
const onSubmit = (data) => {
startTransition(async () => {
try {
const result = await createNoteAction(data);
if (result.success) {
toast.success('Note created successfully!');
form.reset();
}
} catch (error) {
toast.error('Failed to create note');
console.error('Create note error:', error);
}
});
};
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
{/* Form fields */}
<Button type="submit" disabled={isPending}>
{isPending ? 'Creating...' : 'Create Note'}
</Button>
</form>
);
}
```
### Using Route Handlers with Fetch
```typescript
'use client';
async function createItem(data: CreateItemInput) {
const response = await fetch('/api/items', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Failed to create item');
}
return response.json();
}
// Usage in component
const handleCreateItem = async (data) => {
try {
const result = await createItem(data);
toast.success('Item created successfully!');
return result;
} catch (error) {
toast.error('Failed to create item');
throw error;
}
};
```
## Security Best Practices
### Input Validation
Always use Zod schemas for input validation:
```typescript
// Define strict schemas
const UpdateUserSchema = z.object({
name: z.string().min(1).max(100),
email: z.string().email(),
age: z.number().int().min(18).max(120),
});
// Server action with validation
export const updateUserAction = enhanceAction(
async function (data, user) {
// data is guaranteed to match the schema
// Additional business logic validation can go here
if (data.email !== user.email) {
// Check if email change is allowed
const canChangeEmail = await checkEmailChangePermission(user);
if (!canChangeEmail) {
throw new Error('Email change not allowed');
}
}
// Update user
return await updateUser(user.id, data);
},
{
auth: true,
schema: UpdateUserSchema,
},
);
```
### Authorization Checks
```typescript
export const deleteAccountAction = enhanceAction(
async function (data, user) {
const client = getSupabaseServerClient();
// Verify user owns the account
const { data: account, error } = await client
.from('accounts')
.select('id, primary_owner_user_id')
.eq('id', data.accountId)
.single();
if (error || !account) {
throw new Error('Account not found');
}
if (account.primary_owner_user_id !== user.id) {
throw new Error('Only account owners can delete accounts');
}
// Additional checks
const hasActiveSubscription = await client
.rpc('has_active_subscription', { account_id: data.accountId });
if (hasActiveSubscription) {
throw new Error('Cannot delete account with active subscription');
}
// Proceed with deletion
await deleteAccount(data.accountId);
return { success: true };
},
{
auth: true,
schema: DeleteAccountSchema,
},
);
```
## Middleware Integration
The `enhanceAction` and `enhanceRouteHandler` utilities integrate with the application middleware for:
- CSRF protection
- Authentication verification
- Request logging
- Error handling
- Input validation
This ensures consistent security and monitoring across all server actions and API routes.