Skip to content

Modèles de données

Les interfaces TypeScript qui décrivent toutes les entités persistées par Klapy. Source unique : klapy-crm/src/types/index.ts.

TL;DR

  • Toutes les interfaces vivent dans un seul fichier : klapy-crm/src/types/index.ts. Si tu modifies un modèle, c'est là.
  • Convention de nommage : champs Firestore en snake_case, types TS en PascalCase, constantes en UPPER_SNAKE_CASE.
  • Pas de vrais enum TypeScript : on utilise des objets as const + un type dérivé. Tree-shake friendly et compatible avec les valeurs Firestore (strings).
  • Timestamps Firestore, jamais Date. Alias Timestamp ré-exporté depuis firebase/firestore.
  • PII isolée : UserProfile est dans une sous-collection (users/{uid}/profile/main), pas dans UserAccount. Ne jamais fusionner les deux.
  • Champs protégés sur UserAccount : plan, subscription_status, stripe_customer_id. Le client ne peut pas les écrire (voir Règles de sécurité).

Vue d'ensemble

Toutes les entités sont scopées par utilisateur : aucune collection partagée entre comptes. Voir Base de données pour l'arbre Firestore complet.

Index des modèles

ModèleDescriptionPath Firestore
UserAccountCompte utilisateur, plan, consentement RGPDusers/{uid}
UserProfilePII et paramètres facturationusers/{uid}/profile/main
ContactPersonne (prospect, client, partenaire)users/{uid}/contacts/{id}
CompanySociété rattachable à un contactusers/{uid}/companies/{id}
OpportunityCarte du Kanban commercialusers/{uid}/opportunities/{id}
QuoteDevisusers/{uid}/quotes/{id}
InvoiceFactureusers/{uid}/invoices/{id}
TaskTâche à faireusers/{uid}/tasks/{id}
CalendarEventÉvènement du calendrier (tournage, rdv, etc.)users/{uid}/events/{id}
ActivityLog d'interaction (append-only)users/{uid}/activities/{id}

Conventions

Constantes typées (pseudo-enums)

ts
export const QUOTE_STATUS = {
  BROUILLON: 'draft',
  ENVOYE: 'sent',
  ACCEPTE: 'accepted',
  REFUSE: 'refused',
  EXPIRE: 'expired'
} as const;

export type QuoteStatus = (typeof QUOTE_STATUS)[keyof typeof QUOTE_STATUS];

À utiliser systématiquement comme suit :

ts
import { QUOTE_STATUS, type QuoteStatus } from '@/types';

const status: QuoteStatus = QUOTE_STATUS.BROUILLON; // preferred
const status: QuoteStatus = 'draft';                // works but magic string

Timestamps

Tous les champs date Firestore utilisent l'alias :

ts
export type Timestamp = import('firebase/firestore').Timestamp;

Jamais Date, jamais string. Pour convertir à l'affichage : ts.toDate().

Sérialisation Cloud Functions

Quand un objet est passé à une Cloud Function via httpsCallable, les Timestamp Firestore sont sérialisés en { _seconds, _nanoseconds }. La fonction doit reconstruire un Timestamp côté serveur si elle veut comparer des dates.

Constantes (enums)

ConstanteValeursUtilisé par
CONTACT_TYPEindividual, company, prospect, client, partnerContact.type
OPPORTUNITY_STATUSnew, contacted, quote_sent, negotiating, won, lostOpportunity.status (colonnes Kanban)
QUOTE_STATUSdraft, sent, accepted, refused, expiredQuote.status
INVOICE_STATUSdraft, sent, partially_paid, paid, overdueInvoice.status
TASK_PRIORITYlow, normal, highTask.priority
TASK_STATUSto_do, in_progress, doneTask.status
EVENT_TYPEshoot, meeting, deliveryCalendarEvent.type
ACTIVITY_TYPEcall, email, note, meetingActivity.type
PLANstarter, proUserAccount.plan
SUBSCRIPTION_STATUSpending, active, past_due, canceledUserAccount.subscription_status

Source de vérité

Les valeurs de ces constantes sont dupliquées dans firestore.rules pour valider à l'écriture côté serveur. Toute modification doit se faire dans les deux fichiers, sans quoi un nouvel état sera rejeté à l'écriture.

Pièges & gotchas (transversaux)

À ne pas faire

  • Mettre une PII dans UserAccount. Toujours dans UserProfile.
  • Écrire un champ 🔒 protégé depuis le client (plan, subscription_status, stripe_customer_id, created_at, number). Les rules le rejettent.
  • Renommer un champ Firestore sans migration. Les documents existants gardent l'ancien nom.
  • Utiliser Date au lieu de Timestamp. Casse VueFire et la sérialisation Cloud Functions.
  • Ajouter un nouvel état d'enum sans mettre à jour firestore.rules en parallèle. Le nouvel état sera rejeté à l'écriture.
  • Supprimer une Activity, un Quote validé ou une Invoice validée. Audit et obligations légales.

Voir aussi