Skip to content

Opportunity

Opportunité commerciale : une carte du Kanban (/pipeline) ou une ligne du tableau (/opportunities). C'est la même entité, vue sous deux angles. L'étape (stage) détermine la colonne dans laquelle elle apparaît dans la kanban.

  • Path Firestore : users/{userId}/opportunities/{opportunityId}
  • Source TS : klapy-crm/src/types/index.ts

Interface

ts
interface Opportunity {
  id: string;
  title: string;
  contact_id?: string;
  company_id?: string;
  stage: OpportunityStage;
  amount?: number;
  project_type?: ProjectType;
  expected_close_date?: Timestamp;
  shoot_date?: Timestamp;
  notes?: string;
  lost_reason?: string;
  last_activity_at?: Timestamp;
  created_at: Timestamp;
  updated_at: Timestamp;
}

Champs

ChampNotes
titleObligatoire
contact_idRéférence optionnelle vers un Contact
company_idRéférence optionnelle vers une Company. null = engagement particulier
stageÉtape du pipeline. Une des 7 valeurs de OPPORTUNITY_STAGE
amountMontant estimé en euros (HT par convention, voir Quote/Invoice pour le détail TVA)
project_typeUne des valeurs de PROJECT_TYPE (typologie de prestation)
expected_close_dateDate estimée de signature / validation
shoot_dateDate de tournage prévue (peut différer de expected_close_date)
lost_reasonTexte libre. Requis quand stage === 'lost' (validation form, pas une contrainte de type)
last_activity_atMis à jour par Cloud Function quand une activité est loggée. Pilote le badge "stale" sur la kanban
notesTexte libre

Validation contact_id / company_id

Au moins un des deux doit être renseigné (règle de validation form, pas de contrainte au niveau du type). Une opportunité sans contact ni entreprise n'a pas de sens métier.

Pro vs particulier

La nature de l'engagement vit sur l'opportunité, pas sur le contact. company_id renseigné = engagement professionnel. company_id vide = engagement particulier (mariage, vidéo perso). Un même contact peut donc être lié à plusieurs opportunités, certaines pro et d'autres particulières.

Constantes liées

OPPORTUNITY_STAGE

Les 7 étapes du pipeline, ordonnées comme dans la kanban :

CléLabel UIGroupe
leadLeadProspection
first_contactPremier échangeProspection
quoteDevis envoyéEngagement
negotiationEn discussionEngagement
verbalAccord verbalAccord
wonGagnéAccord
lostPerduÉchec

Le champ STAGE_TO_GROUP mappe chaque étape vers son groupe. La kanban utilise ces groupes pour rendre des séparateurs visuels entre les phases (Prospection → Engagement → Accord → Échec).

PROJECT_TYPE

Typologie courte de la prestation : shoot (tournage seul), edit (montage seul), shoot_and_edit (tournage + montage), photo, other.

Cycle de vie

Transitions libres

Les transitions ne sont pas contraintes par les règles Firestore : un utilisateur peut sauter directement d'une étape à n'importe quelle autre (par drag & drop dans la kanban ou via le sélecteur d'étape dans le DetailPane). Le diagramme ci-dessus est le flux nominal, pas une machine d'état stricte. Cas typique : un client revient après plusieurs mois en lost, on rebascule en negotiation sans repasser par lead.

won n'est pas la fin du métier

stage === 'won' matérialise l'accord commercial conclu, pas la production réalisée. Quand le projet entre en phase de production effective (acompte encaissé, dates de tournage planifiées, livrables à produire), il est destiné à être dérivé en entité Project distincte qui rejoindra le Portfolio. L'opportunité won reste alors archivée en l'état pour les KPIs commerciaux (taux de conversion, CA pipeline).

Voir aussi

  • Contact, Company : références cibles de l'opportunité
  • Quote : un devis peut être créé depuis une opportunité (et inversement, l'envoi d'un devis fait passer l'opportunité en quote)
  • Task : peut être rattachée à une opportunité via opportunity_id
  • CalendarEvent : tournage planifié rattaché à une opportunité
  • Activity : appels, emails, notes loggés contre l'opportunité (alimente last_activity_at)