Aller au contenu principal

Server Actions

Patrimo utilise Server Actions comme API principale, et non REST. Les deux endpoints REST existants sont /api/auth/* (NextAuth) et /api/health.

Pourquoi pas REST

  • Couplage naturel avec Next.js App Router : une Server Action est appelée directement depuis un composant React sans duplication de types (Zod côté serveur + fetch typé côté client).
  • Revalidation automatique : revalidatePath() invalide le cache RSC en retour d'action, sans client state manager.
  • Sécurité par défaut : les actions ne sont pas exposées sur des URLs publiques ; chaque appel embarque un token anti-CSRF géré par Next.js.
  • Mono-utilisateur : pas besoin d'API versionnée pour un intranet personnel.

Voir la décision complète dans l'intro API.

Localisation

src/app/actions/
├── accounts.ts
├── analytics.ts
├── budget.ts
├── dashboard.ts
├── import.ts
├── settings.ts
└── users.ts

Chaque fichier commence par la directive :

'use server';

Convention d'une action

'use server';

import { z } from 'zod';
import { auth } from '@/lib/auth';
import { prisma } from '@/lib/db';
import { revalidatePath } from 'next/cache';

const CreateAccountSchema = z.object({
name: z.string().min(1),
type: z.enum(['CHECKING', 'SAVINGS', /* … */]),
currency: z.string().length(3),
});

/**
* Crée un compte pour l'utilisateur connecté.
*
* @auth requise
* @returns Le compte créé
* @throws UNAUTHORIZED si la session est absente
* @throws VALIDATION_ERROR si le payload est invalide
*/
export async function createAccount(input: z.infer<typeof CreateAccountSchema>) {
// 1. Auth guard
const session = await auth();
if (!session?.user) throw new Error('UNAUTHORIZED');

// 2. Validation Zod
const data = CreateAccountSchema.parse(input);

// 3. Mutation Prisma
const account = await prisma.account.create({ data });

// 4. Revalidation RSC
revalidatePath('/accounts');

return account;
}

Règles

  • Auth guard en premier : await auth() avant toute lecture/écriture
  • Ownership check : pour les entités utilisateur, vérifier que entity.userId === session.user.id (même si mono-user aujourd'hui, pour survivre à une future migration multi-user)
  • Validation Zod sur tous les inputs — pas de any
  • JSDoc obligatoire : description, @auth, @returns, @throws. Le script docs:generate-api en extrait les signatures.
  • Revalidation explicite via revalidatePath() ou revalidateTag() après mutation
  • Erreurs typées : lever des erreurs métier (UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR, CONFLICT) — voir catalogue d'erreurs

Génération automatique de la doc

Le script npm run docs:generate-api extrait les signatures (via ts-morph) dans docs-site/docs/api/server-actions/_generated/<module>.mdx. Les pages manuelles (accounts.md, transactions.md, etc.) importent ces snippets et ajoutent pré-conditions, exemples et erreurs métier à la main.

Ne jamais éditer _generated/*.mdx manuellement — régénérer.

Voir aussi