Claude sub-agents, PRD, MCP improvements (#359)
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
This commit is contained in:
committed by
GitHub
parent
02e2502dcc
commit
2b8572baaa
@@ -2,28 +2,45 @@
|
||||
|
||||
This file contains instructions for working with Next.js utilities including server actions and route handlers.
|
||||
|
||||
## Guidelines
|
||||
|
||||
- Don't use Server Actions for data-fetching, use for mutations only
|
||||
- Best Practice: Keep actions light, move business logic to ad-hoc services
|
||||
- Authorization logic must be defined in RLS and DB, not Server Actions or application code (unless using the admin client, use sparinlgy!)
|
||||
- Do not expose sensitive data
|
||||
- Log async operations
|
||||
- Validate body with Zod
|
||||
- Use 'use server' at the top of the file. No need for 'server only';
|
||||
|
||||
## Server Actions Implementation
|
||||
|
||||
Always use `enhanceAction` from `@packages/next/src/actions/index.ts`:
|
||||
Always use `enhanceAction` from `@packages/next/src/actions/index.ts`.
|
||||
|
||||
```typescript
|
||||
'use server';
|
||||
Define a schema:
|
||||
|
||||
import { enhanceAction } from '@kit/next/actions';
|
||||
```tsx
|
||||
import { z } from 'zod';
|
||||
|
||||
// Define your schema
|
||||
const CreateNoteSchema = z.object({
|
||||
// Define your schema in its own file
|
||||
export 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
|
||||
|
||||
Then we define a service for crossing the network boundary:
|
||||
|
||||
```tsx
|
||||
import { CreateNoteSchema } from '../schemas/notes.schemas.ts';
|
||||
import * as z from 'zod';
|
||||
|
||||
export function createNotesService() {
|
||||
return new NotesService();
|
||||
}
|
||||
|
||||
class NotesService {
|
||||
createNote(data: z.infer<CreateNoteSchema>) {
|
||||
const client = getSupabaseServerClient();
|
||||
|
||||
const { data: note, error } = await client
|
||||
@@ -40,11 +57,51 @@ export const createNoteAction = enhanceAction(
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Finally, we use Server Actions for exposing POST handlers:
|
||||
|
||||
```typescript
|
||||
'use server';
|
||||
|
||||
import { enhanceAction } from '@kit/next/actions';
|
||||
import { createNotesService } from '../notes.service.ts';
|
||||
|
||||
export const createNoteAction = enhanceAction(
|
||||
async function (data, user) {
|
||||
// data is automatically validated against the schema
|
||||
// user is automatically authenticated if auth: true
|
||||
|
||||
return { success: true, note };
|
||||
const service = createNotesService();
|
||||
const logger = await getLogger();
|
||||
|
||||
logger.info({
|
||||
userId: user.id,
|
||||
}, `Creating note...`);
|
||||
|
||||
const { data: note, error } = await service.createNote(data);
|
||||
|
||||
if (error) {
|
||||
logger.error({
|
||||
error: error.message
|
||||
}, `Error creating note`);
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
logger.info({
|
||||
noteId: note.id
|
||||
}, `Note successfully created`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
note
|
||||
};
|
||||
},
|
||||
{
|
||||
auth: true, // Require authentication
|
||||
auth: true, // Require authentication (true by default, can omit)
|
||||
schema: CreateNoteSchema, // Validate input with Zod
|
||||
},
|
||||
);
|
||||
@@ -75,7 +132,15 @@ export const myAction = enhanceAction(
|
||||
|
||||
## Route Handlers (API Routes)
|
||||
|
||||
Use `enhanceRouteHandler` from `@packages/next/src/routes/index.ts`:
|
||||
Use `enhanceRouteHandler` from `@packages/next/src/routes/index.ts`.
|
||||
|
||||
### Guidelines
|
||||
|
||||
- Use when data must be exposed to externally
|
||||
- Use for receiving requests from external clients (such as webhooks)
|
||||
- Can be used for fetching data to client side fetchers (such as React Query) if cannot use client-side Supabase queries
|
||||
|
||||
### Usage
|
||||
|
||||
```typescript
|
||||
import { enhanceRouteHandler } from '@kit/next/routes';
|
||||
@@ -370,44 +435,6 @@ const handleCreateItem = async (data) => {
|
||||
};
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
Reference in New Issue
Block a user