Règles Métier SSII/ESN
Purpose
Fournir les connaissances métier essentielles pour développer des fonctionnalités business dans une application de gestion de consultants.
Glossaire Métier
TJM (Taux Journalier Moyen)
Prix facturé au client par jour de prestation d'un consultant.
- •Fourchette: 300€ - 1000€/jour
- •Facteurs: seniority, compétences rares, marché, client
Taux d'Occupation (Utilization Rate)
Taux = (Jours Facturables / Jours Ouvrés) × 100 Exemple: 18 jours facturés sur 22 jours ouvrés = 81.8%
Benchmarks:
- •< 70%: Sous-activité, problème commercial
- •75-85%: Objectif optimal
- •
90%: Surcharge, risque burnout
Intercontrat (Bench)
Période où un consultant n'est pas en mission cliente.
Causes:
- •Fin de mission sans enchaînement
- •Rupture de contrat client
- •Période de formation
Coûts:
- •Salaire versé sans revenu généré
- •Impact direct sur la rentabilité
Gestion:
- •Objectif: < 15 jours moyens
- •Utilisation: formation, avant-vente, R&D interne
Marge Brute
Marge Brute = CA - Coûts Salariaux Taux de Marge = (Marge / CA) × 100 Objectif: 30-40%
Facteurs d'optimisation:
- •TJM élevé
- •Coûts salariaux maîtrisés
- •Taux d'occupation élevé
Pipeline Commercial
Ensemble des opportunités commerciales en cours.
Étapes:
- •Lead (contact initial)
- •Prospect (besoin qualifié)
- •Proposition (offre commerciale)
- •Négociation
- •Signé / Perdu
Taux de conversion typique: 20-30%
Règles Métier Critiques
Règle 1: Unicité Mission Active
Un consultant ne peut avoir qu'UNE SEULE mission active à la fois.
Validation:
// Vérifier pas de chevauchement avant création
const overlap = await prisma.mission.findFirst({
where: {
consultantId: mission.consultantId,
OR: [
{
dateDebut: { lte: mission.dateFin },
dateFin: { gte: mission.dateDebut }
}
]
}
});
if (overlap) {
throw new Error('Consultant déjà en mission sur cette période');
}
Règle 2: Cohérence des Dates
dateFin doit toujours être postérieure à dateDebut.
Validation:
if (mission.dateFin <= mission.dateDebut) {
throw new Error('Date de fin doit être après date de début');
}
Règle 3: Préservation Historique
Les missions terminées ne doivent jamais être supprimées.
Raisons:
- •Calcul du CA historique
- •Reporting client
- •Audit et conformité
Solution: Soft delete ou statut "TERMINEE"
Règle 4: Calcul du Statut en Temps Réel
Le statut d'un consultant est calculé basé sur ses missions actives, pas stocké.
Logique:
function calculateStatus(consultant: ConsultantWithMissions): string {
const now = new Date();
const activeMission = consultant.missions.find(m =>
m.dateDebut <= now && now <= m.dateFin
);
return activeMission ? 'EN_MISSION' : consultant.statut;
}
Règle 5: TJM Cohérent
Le TJM appliqué sur une mission doit être cohérent avec le TJM du consultant.
Warning si:
- •TJM appliqué < 80% du TJM consultant
- •TJM appliqué > 150% du TJM consultant
if (mission.tjmApplique < consultant.tjm * 0.8) {
console.warn('TJM appliqué anormalement bas');
}
KPIs Essentiels
1. Taux d'Occupation Global
async function calculateTauxOccupation(debut: Date, fin: Date) {
const consultants = await prisma.consultant.findMany({
include: { missions: true }
});
const joursOuvres = calculateBusinessDays(debut, fin);
let joursFacturables = 0;
for (const consultant of consultants) {
for (const mission of consultant.missions) {
const joursMission = calculateOverlap(
mission.dateDebut,
mission.dateFin,
debut,
fin
);
joursFacturables += joursMission;
}
}
const totalJours = consultants.length * joursOuvres;
return (joursFacturables / totalJours) * 100;
}
2. CA Réalisé
async function getCARealisePeriode(debut: Date, fin: Date) {
const missions = await prisma.mission.findMany({
where: {
dateDebut: { lte: fin },
dateFin: { gte: debut }
}
});
return missions.reduce((ca, mission) => {
const joursFact = calculateBillableDays(mission, debut, fin);
return ca + (mission.tjmApplique * joursFact);
}, 0);
}
3. Consultants Disponibles
async function getConsultantsDisponibles(date: Date) {
const consultants = await prisma.consultant.findMany({
include: {
missions: {
where: {
dateDebut: { lte: date },
dateFin: { gte: date }
}
}
}
});
return consultants.filter(c => c.missions.length === 0);
}
4. Missions Se Terminant Bientôt
async function getMissionsEndingSoon(jours: number = 30) {
const now = new Date();
const limite = new Date();
limite.setDate(limite.getDate() + jours);
return await prisma.mission.findMany({
where: {
dateFin: {
gte: now,
lte: limite
}
},
include: { consultant: true },
orderBy: { dateFin: 'asc' }
});
}
5. Durée Moyenne Intercontrat
async function getDureeIntercontratMoyenne() {
const consultants = await prisma.consultant.findMany({
include: {
missions: {
orderBy: { dateFin: 'desc' }
}
}
});
let totalJours = 0;
let nbPeriodes = 0;
for (const consultant of consultants) {
for (let i = 0; i < consultant.missions.length - 1; i++) {
const finMission = consultant.missions[i].dateFin;
const debutSuivante = consultant.missions[i + 1].dateDebut;
const joursBench = calculateDays(finMission, debutSuivante);
if (joursBench > 0) {
totalJours += joursBench;
nbPeriodes++;
}
}
}
return nbPeriodes > 0 ? totalJours / nbPeriodes : 0;
}
Cycles de Gestion
Cycle Mensuel (1er de chaque mois)
- •
Facturation du mois écoulé
- •Missions facturées → Statut "FACTUREE"
- •Calcul CA réalisé
- •
Staffing du mois à venir
- •Identifier fins de mission (J+30)
- •Matcher consultants disponibles / opportunités
- •Planifier les intercontrats
- •
Calcul des KPIs
- •Taux d'occupation du mois
- •CA vs objectifs
- •Intercontrat moyen
Cycle Trimestriel
- •
Bilan KPIs trimestriels
- •Évolution taux d'occupation
- •Croissance CA
- •Marge brute
- •
Forecast trimestre suivant
- •Pipeline × taux de conversion
- •Missions signées à démarrer
- •Estimation CA
- •
Ajustements
- •Plan commercial
- •Recrutements
- •Formations
Alertes Business
Alertes Critiques (Action Immédiate)
- •Consultant en intercontrat > 30 jours
- •Mission sans facturation > 90 jours
- •Taux d'occupation < 60%
- •Consultant sans mission dans 15 jours
Alertes Warning (Surveillance)
- •Mission se termine dans 30 jours
- •Intercontrat > 15 jours
- •TJM < seuil minimum
Formules de Calcul
Jours Ouvrés entre 2 Dates
function calculateBusinessDays(start: Date, end: Date): number {
let count = 0;
const current = new Date(start);
while (current <= end) {
const day = current.getDay();
if (day !== 0 && day !== 6) { // Pas weekend
count++;
}
current.setDate(current.getDate() + 1);
}
return count;
}
Revenus Générés Mission
function calculateRevenue(tjm: number, debut: Date, fin: Date): number {
const jours = calculateBusinessDays(debut, fin);
return tjm * jours;
}
Chevauchement entre 2 Périodes
function calculateOverlap(
start1: Date,
end1: Date,
start2: Date,
end2: Date
): number {
const overlapStart = new Date(Math.max(start1.getTime(), start2.getTime()));
const overlapEnd = new Date(Math.min(end1.getTime(), end2.getTime()));
if (overlapStart > overlapEnd) return 0;
return calculateBusinessDays(overlapStart, overlapEnd);
}
Features Business Prioritaires
🔥 Haute Priorité
1. Forecast de CA
- •Calcul CA réalisé + prévu + potentiel
- •Visibilité 3-6 mois
- •Aide à la prise de décision
2. Pipeline Commercial
- •Gestion des opportunités
- •Calcul CA prévisionnel × probabilité
- •Alerte staffing requis
3. Alertes Proactives
- •Missions se terminant
- •Intercontrat prolongé
- •Taux d'occupation faible
📊 Moyenne Priorité
4. Reporting & Analytics
- •Export Excel missions/consultants
- •Graphiques évolution CA
- •Comparaisons MoM/YoY
5. Gestion Intercontrat
- •Tracking des périodes bench
- •Activités (formation, avant-vente)
- •Coût total intercontrat
6. Analyse Marges
- •Marge par client
- •Marge par consultant
- •Optimisation TJM
💡 Basse Priorité
7. Multi-Clients Avancé
- •Contrats cadres
- •Tarifs négociés par client
- •Historique négociations
8. Gestion des Compétences
- •Matrice compétences × consultants
- •Gaps de compétences
- •Plan de formation
Validations Recommandées
Frontend (UX)
// Validation formulaire mission
const validateMission = (data: MissionForm) => {
const errors: string[] = [];
if (data.dateFin <= data.dateDebut) {
errors.push('Date de fin doit être après date de début');
}
if (data.tjmApplique <= 0) {
errors.push('TJM doit être positif');
}
const duree = calculateDays(data.dateDebut, data.dateFin);
if (duree > 730) { // 2 ans
errors.push('Mission > 2 ans, vérifier les dates');
}
return errors;
};
Backend (Business Logic)
// Validation métier complète
const validateNewMission = async (mission: MissionInput) => {
// 1. Dates cohérentes
if (mission.dateFin <= mission.dateDebut) {
throw new BusinessError('Dates incohérentes');
}
// 2. Pas de chevauchement
const overlap = await checkMissionOverlap(mission);
if (overlap) {
throw new BusinessError('Consultant déjà en mission');
}
// 3. Consultant existe et actif
const consultant = await prisma.consultant.findUnique({
where: { id: mission.consultantId }
});
if (!consultant) {
throw new BusinessError('Consultant introuvable');
}
// 4. TJM cohérent (warning)
if (mission.tjmApplique < consultant.tjm * 0.8) {
console.warn(`TJM bas: ${mission.tjmApplique} vs ${consultant.tjm}`);
}
return true;
};
Anti-Patterns à Éviter
❌ Mauvais: Calculs Frontend
// Ne PAS faire les calculs métier dans le frontend const ca = (dateFin - dateDebut) * tjm; // Faux!
✅ Bon: Calculs Backend
// API retourne les calculs
GET /api/missions/:id
{
"revenusGeneres": 50000, // Calculé par backend
"dureeJours": 100
}
❌ Mauvais: Supprimer Missions
// Ne JAMAIS supprimer une mission terminée
await prisma.mission.delete({ where: { id } });
✅ Bon: Soft Delete ou Archiver
// Marquer comme archivée
await prisma.mission.update({
where: { id },
data: { archived: true }
});
❌ Mauvais: Statut Stocké
// Ne pas stocker le statut dérivé
await prisma.consultant.update({
data: { statut: 'EN_MISSION' }
});
✅ Bon: Statut Calculé
// Calculer à la volée depuis les missions const statut = calculateConsultantStatus(consultant);
Checklist Feature Business
Avant de livrer une feature métier:
- • Règles métier validées (CLAUDE.md)
- • Calculs testés (formules correctes)
- • Edge cases couverts (dates limites, etc.)
- • Pas de suppression de données historiques
- • KPIs impactés identifiés
- • UX validée par users métier
- • Performance acceptable (< 2s)
- • Documentation des formules
- • Tests des règles critiques
Ressources
- •Project Rules:
/CLAUDE.md - •Agent Expert:
@ssii-expert- Pour features complexes - •Technical Skills:
- •
@prisma-conventions- Modèles de données - •
@api-conventions- Design API - •
@typescript-standards- Types métier
- •