{
  "nom": "saas",
  "titre": "Abonnements SaaS : revenu recurrent, expansion, contraction, resiliation",
  "origine": "donnees synthetiques",
  "licence": "libre de reutilisation — aucune donnee personnelle reelle",
  "graine": 20261010,
  "script": "outils/donnees/saas.py",
  "separateur": ";",
  "encodage": "UTF-8",
  "invariant": "un seul abonnement actif par client a tout instant — c est ce qui rend le revenu recurrent calculable, et le generateur refuse d ecrire si l invariant est rompu",
  "tables": {
    "offres": {
      "granularite": "une ligne par offre du catalogue",
      "cle": "offre_id",
      "colonnes": {
        "offre_id": "identifiant de l offre — texte, unique",
        "nom": "nom commercial de l offre",
        "prix_mensuel": "forfait mensuel en euros, places incluses comprises",
        "places_incluses": "nombre de places comprises dans le forfait — entier",
        "prix_place_supplementaire": "prix mensuel de chaque place au-dela des incluses, en euros ; zero pour l offre illimitee"
      }
    },
    "clients": {
      "granularite": "une ligne par entreprise cliente",
      "cle": "client_id",
      "colonnes": {
        "client_id": "identifiant du client — texte, unique",
        "raison_sociale": "nom de l entreprise — synthetique, aucune entreprise reelle",
        "segment": "TPE | PME | ETI | Grand compte",
        "pays": "pays de facturation",
        "secteur": "secteur d activite declare",
        "date_premier_contact": "date du premier contact commercial — AAAA-MM-JJ, toujours anterieure au debut du premier abonnement"
      }
    },
    "abonnements": {
      "granularite": "une ligne par periode d abonnement d un client ; un changement d offre ferme la periode precedente et en ouvre une nouvelle",
      "cle": "abonnement_id",
      "colonnes": {
        "abonnement_id": "identifiant de la periode — texte, unique",
        "client_id": "cle vers clients.client_id",
        "offre_id": "cle vers offres.offre_id",
        "date_debut": "premier jour de la periode — AAAA-MM-JJ, toujours un 1er du mois",
        "date_fin": "dernier jour de la periode — AAAA-MM-JJ, VIDE si l abonnement est encore actif ; une cellule vide est donc une information, pas un manque",
        "places": "nombre de places payees — entier strictement positif",
        "montant_mensuel": "prix mensuel de la periode, en euros : forfait de l offre plus les places au-dela des incluses",
        "motif_fin": "budget | concurrent | projet termine | insatisfaction | fusion — VIDE si la periode s est terminee par un changement d offre ou si elle est encore active"
      }
    },
    "factures": {
      "granularite": "une ligne par mois et par abonnement actif, emise le 1er du mois",
      "cle": "facture_id",
      "colonnes": {
        "facture_id": "identifiant de la facture — texte, unique",
        "abonnement_id": "cle vers abonnements.abonnement_id",
        "client_id": "cle vers clients.client_id",
        "date_emission": "date d emission — AAAA-MM-JJ, toujours un 1er du mois",
        "periode": "mois facture — AAAA-MM",
        "montant_ht": "montant hors taxes, en euros — egal au montant mensuel de l abonnement",
        "tva": "20 % du hors taxes, arrondis au centime",
        "montant_ttc": "hors taxes plus TVA, au centime",
        "statut": "payee | en retard | impayee"
      }
    },
    "usage_mensuel": {
      "granularite": "une ligne par mois et par abonnement actif",
      "cle": "abonnement_id + annee_mois",
      "colonnes": {
        "client_id": "cle vers clients.client_id",
        "abonnement_id": "cle vers abonnements.abonnement_id",
        "annee_mois": "mois observe — AAAA-MM",
        "places_payees": "places facturees ce mois-la — entier",
        "places_utilisees": "places effectivement utilisees — entier, toujours inferieur ou egal aux places payees",
        "connexions": "nombre de connexions sur le mois",
        "exports": "nombre d exports de donnees sur le mois"
      }
    },
    "calendrier": {
      "granularite": "une ligne par jour de la periode, sans trou",
      "cle": "date",
      "colonnes": {
        "date": "jour — AAAA-MM-JJ",
        "annee": "annee sur quatre chiffres",
        "trimestre": "T1 a T4",
        "mois_numero": "numero du mois, 1 a 12",
        "mois_nom": "nom du mois en francais",
        "annee_mois": "AAAA-MM",
        "est_fin_de_mois": "1 si c est le dernier jour du mois, 0 sinon",
        "jour_semaine": "1 pour lundi a 7 pour dimanche"
      }
    }
  }
}