smithery.ai

prisma-conventions

Standards Prisma et base de données. Use when "prisma", "database", "schema", "migration", "query".

First seen Mar 15, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Allowed toolsRead, Grep, Glob, Bash

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 10,108 B
  • docs SUMMARY.md 126 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 2 installs

SKILL.md

Prisma Conventions

Purpose

Standards pour utiliser Prisma dans le projet consultant-manager.

Architecture Base de Données

Modèles Principaux

model Consultant {
  id              String   @id @default(uuid())
  nom             String
  prenom          String
  email           String   @unique
  telephone       String?
  competences     String   // JSON array
  tjm             Float
  statut          String   @default("DISPONIBLE")
  dateCreation    DateTime @default(now())
  dateModification DateTime @updatedAt

  missions        Mission[]
}

model Mission {
  id                   String   @id @default(uuid())
  consultantId         String
  nomClient            String
  lieu                 String?
  dateDebut            DateTime
  dateFin              DateTime
  tjmApplique          Float
  description          String?
  competencesUtilisees String?  // JSON array
  statutFacturation    String   @default("EN_ATTENTE")
  dateCreation         DateTime @default(now())
  dateModification     DateTime @updatedAt

  consultant           Consultant @relation(fields: [consultantId], references: [id], onDelete: Cascade)

  @@index([consultantId])
  @@index([dateDebut, dateFin])
}

Principes de Design

  1. UUIDs pour les IDs: Plus sûrs que les auto-increment
  2. Timestamps automatiques: @default(now()) et @updatedAt
  3. Nullable approprié: ? uniquement si vraiment optionnel
  4. Indexes stratégiques: Sur foreign keys et champs de recherche
  5. Cascade Delete: Missions supprimées si consultant supprimé

Migrations

Créer une Migration

cd backend
npx prisma migrate dev --name description_du_changement

Conventions de nommage:

  • init - Migration initiale
  • addfieldname - Ajout d'un champ
  • renamefieldxtoy - Renommage
  • addtablename - Nouvelle table
  • createindexon_field - Nouvel index

Workflow de Migration

# 1. Modifier schema.prisma
# 2. Créer la migration
npx prisma migrate dev --name add_consultant_photo

# 3. Regénérer le client
npx prisma generate

# 4. Vérifier que tout compile
npm run build

Migration en Production

# Appliquer les migrations en prod
npx prisma migrate deploy

# Seed la base si nécessaire
npx prisma db seed

Queries Prisma

CRUD de Base

// CREATE
const consultant = await prisma.consultant.create({
  data: {
    nom: 'Dupont',
    prenom: 'Jean',
    email: '[email protected]',
    competences: JSON.stringify(['React', 'TypeScript']),
    tjm: 500,
    statut: 'DISPONIBLE'
  }
});

// READ avec relations
const consultant = await prisma.consultant.findUnique({
  where: { id: consultantId },
  include: {
    missions: {
      orderBy: { dateDebut: 'desc' }
    }
  }
});

// READ liste avec filtres
const consultants = await prisma.consultant.findMany({
  where: {
    statut: 'DISPONIBLE',
    email: { contains: '@example.com' }
  },
  orderBy: { nom: 'asc' }
});

// UPDATE
const updated = await prisma.consultant.update({
  where: { id: consultantId },
  data: { tjm: 550 }
});

// DELETE
await prisma.consultant.delete({
  where: { id: consultantId }
});

Queries Complexes

Filtres avancés:

// Consultants avec missions actives
const consultantsEnMission = await prisma.consultant.findMany({
  where: {
    missions: {
      some: {
        dateDebut: { lte: new Date() },
        dateFin: { gte: new Date() }
      }
    }
  },
  include: { missions: true }
});

// Missions se terminant bientôt
const in30Days = new Date();
in30Days.setDate(in30Days.getDate() + 30);

const missionsEndingSoon = await prisma.mission.findMany({
  where: {
    dateFin: {
      gte: new Date(),
      lte: in30Days
    }
  },
  include: { consultant: true }
});

Aggregations:

// Compter les consultants par statut
const stats = await prisma.consultant.groupBy({
  by: ['statut'],
  _count: true
});

// Revenus totaux
const totalRevenue = await prisma.mission.aggregate({
  _sum: {
    tjmApplique: true
  },
  where: {
    statutFacturation: 'PAYEE'
  }
});

Transactions:

// Créer consultant et mission en une transaction
const result = await prisma.$transaction(async (tx) => {
  const consultant = await tx.consultant.create({
    data: { /* ... */ }
  });

  const mission = await tx.mission.create({
    data: {
      consultantId: consultant.id,
      /* ... */
    }
  });

  return { consultant, mission };
});

Patterns Spécifiques au Projet

Gestion des JSON Fields

Competences (array):

// Écriture
await prisma.consultant.create({
  data: {
    competences: JSON.stringify(['React', 'Node.js'])
  }
});

// Lecture
const consultant = await prisma.consultant.findUnique({ where: { id } });
const competences: string[] = JSON.parse(consultant.competences);

Calcul du Statut Consultant

interface ConsultantWithMissions {
  missions: Mission[];
  statut: string;
}

async function getConsultantWithRealStatus(id: string) {
  const consultant = await prisma.consultant.findUnique({
    where: { id },
    include: {
      missions: {
        where: {
          dateDebut: { lte: new Date() },
          dateFin: { gte: new Date() }
        }
      }
    }
  });

  // Si mission active, forcer EN_MISSION
  const hasActiveMission = consultant.missions.length > 0;
  return {
    ...consultant,
    statut: hasActiveMission ? 'EN_MISSION' : consultant.statut
  };
}

Queries Optimisées

❌ N+1 Problem:

// Mauvais: N+1 queries
const consultants = await prisma.consultant.findMany();
for (const consultant of consultants) {
  const missions = await prisma.mission.findMany({
    where: { consultantId: consultant.id }
  });
}

✅ Solution: Include:

// Bon: 1 seule query
const consultants = await prisma.consultant.findMany({
  include: { missions: true }
});

Pagination:

const page = 1;
const pageSize = 20;

const consultants = await prisma.consultant.findMany({
  skip: (page - 1) * pageSize,
  take: pageSize,
  orderBy: { nom: 'asc' }
});

const total = await prisma.consultant.count();

Prisma Studio

Ouvrir l'Interface Graphique

cd backend
npx prisma studio

Ouvre un navigateur sur http://localhost:5555 pour:

  • Visualiser les données
  • Créer/Modifier/Supprimer des enregistrements
  • Tester les relations
  • Inspecter le schéma

Seed Data

Créer un Seed Script

// backend/prisma/seed.ts
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function main() {
  // Nettoyer
  await prisma.mission.deleteMany();
  await prisma.consultant.deleteMany();

  // Créer des données de test
  const consultant1 = await prisma.consultant.create({
    data: {
      nom: 'Dupont',
      prenom: 'Jean',
      email: '[email protected]',
      competences: JSON.stringify(['React', 'TypeScript', 'Node.js']),
      tjm: 500,
      statut: 'DISPONIBLE'
    }
  });

  const consultant2 = await prisma.consultant.create({
    data: {
      nom: 'Martin',
      prenom: 'Marie',
      email: '[email protected]',
      competences: JSON.stringify(['Python', 'Django', 'PostgreSQL']),
      tjm: 450,
      statut: 'DISPONIBLE'
    }
  });

  // Créer une mission active
  await prisma.mission.create({
    data: {
      consultantId: consultant1.id,
      nomClient: 'Acme Corp',
      lieu: 'Paris',
      dateDebut: new Date('2026-01-01'),
      dateFin: new Date('2026-06-30'),
      tjmApplique: 500,
      description: 'Développement application React',
      competencesUtilisees: JSON.stringify(['React', 'TypeScript']),
      statutFacturation: 'EN_ATTENTE'
    }
  });

  console.log('✅ Seed completed');
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

Configurer dans package.json:

{
  "prisma": {
    "seed": "tsx prisma/seed.ts"
  }
}

Exécuter:

npx prisma db seed

Bonnes Pratiques

Toujours Déconnecter

// À la fin du script ou au shutdown
await prisma.$disconnect();

Gérer les Erreurs

try {
  const consultant = await prisma.consultant.create({ data });
} catch (error) {
  if (error.code === 'P2002') {
    // Unique constraint violation
    throw new Error('Email déjà utilisé');
  }
  throw error;
}

Utiliser les Types Générés

import { Consultant, Mission, Prisma } from '@prisma/client';

// Type avec relations
type ConsultantWithMissions = Prisma.ConsultantGetPayload<{
  include: { missions: true }
}>;

Checklist

Avant de commiter des changements Prisma:

  • Migration créée avec nom descriptif
  • prisma generate exécuté
  • Schema valide (pas d'erreurs de compilation)
  • Indexes ajoutés sur foreign keys
  • Timestamps (dateCreation, dateModification) présents
  • Cascade delete configuré si approprié
  • Types TypeScript régénérés
  • Tests mis à jour si schéma changé
  • Seed data mis à jour si nécessaire

Commandes Utiles

# Ouvrir Prisma Studio
npx prisma studio

# Générer le client Prisma
npx prisma generate

# Créer et appliquer une migration
npx prisma migrate dev --name my_migration

# Appliquer migrations en prod
npx prisma migrate deploy

# Réinitialiser la base (dev only!)
npx prisma migrate reset

# Formater le schema
npx prisma format

# Valider le schema
npx prisma validate

# Seed la base
npx prisma db seed

Ressources