| name | new-action |
| description | Scaffold a new Server Action with auth, Zod validation, Prisma mutation, revalidation, and ActionResult types |
| disable-model-invocation | true |
New Server Action
Scaffolds a Server Action following the project's established pattern.
Arguments
Accepts a name and optional description (e.g., /new-action updatePlayerStatus "Update a player's active/inactive status").
Steps
- Determine file location — New action goes in
lib/actions/<name>.ts (or add to an existing file if it fits)
- Check the Prisma schema — Read
prisma/schema.prisma to understand the relevant models and relations
- Check existing validation schemas — Read
lib/utils/validation.ts for existing Zod schemas to reuse
- Create the Zod schema — Add to
lib/utils/validation.ts with proper constraints
- Create the Server Action — Following the template below
- Type-check — Run
bun run type-check to verify
Template
"use server";
import { z } from "zod";
import { prisma } from "@/lib/db/prisma";
import { requireUserId, requireTeamAdmin } from "@/lib/auth/session";
import { revalidatePath } from "next/cache";
export type ActionResult<T> =
| { success: true; data: T }
| { success: false; error: string; details?: unknown };
const inputSchema = z.object({
});
export async function actionName(
input: z.infer<typeof inputSchema>
): Promise<ActionResult<ReturnType>> {
try {
const userId = await requireUserId();
const validated = inputSchema.parse(input);
await requireTeamAdmin(validated.teamId);
const result = await prisma.model.create({
data: { ...validated },
});
revalidatePath("/affected-path");
return { success: true, data: result };
} catch (error) {
if (error instanceof z.ZodError) {
return { success: false, error: "Invalid input", details: error.flatten() };
}
return { success: false, error: "An unexpected error occurred" };
}
}
Rules
- Always use
requireUserId() as the first operation
- Always validate with Zod before any database access
- Always check authorization for team/league scoped operations
- Always use
revalidatePath() after mutations
- Never expose internal error messages to the client
- Never return sensitive fields (password hashes, tokens, emergency contacts for non-admins)
- Use Prisma — never raw SQL