saas

Skill agent pour produits SaaS modernes : multi-tenancy, facturation à l'usage, PLG, intégration IA, observabilité, conformité et sécurité.

Qu'est-ce que saas ?

Ce skill fournit un guide complet et opérationnel pour construire un produit SaaS prêt pour la production, couvrant tous les aspects critiques : du multi-tenancy (modèles partagés, par schéma, par base ou hybrides) à la facturation (flat-rate et à l'usage via Stripe/Paddle/LemonSqueezy), en passant par le Product-Led Growth (freemium, PQL, viralité), l'intégration de fonctionnalités IA (streaming, RAG, contrôle des coûts), l'observabilité (logging structuré, tracing distribué, alerting par tenant), la gestion des feature flags, la conformité (RGPD, SOC 2) et la sécurité (RLS PostgreSQL, isolation des données). Il est conçu pour être utilisé avec des assistants de codage comme Claude Code, Cursor ou Codex, et propose des règles précises, des exemples de code concrets (TypeScript, SQL) et des bonnes pratiques pour chaque domaine. L'objectif est d'éviter les erreurs courantes et d'accélérer la mise en œuvre de fonctionnalités SaaS robustes et évolutives.

Compatible avec~Claude Code✓Codex CLI~Cursor
npx skills add Satcomx00-x00/skills-db

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Que fait saas ?

L'état de l'art SaaS — multi-tenancy, facturation à l'usage, PLG, intégration de fonctionnalités IA, observabilité moderne, conformité et sécurité pour les produits SaaS en production.

Instructions

Multi-tenancy

Choisissez le modèle d'isolation adapté à votre cas d'usage :

ModèleDescriptionQuand l'utiliser
Schéma partagéTous les tenants partagent les tables ; les lignes sont marquées avec tenant_idStade précoce, sensible aux coûts, conformité simple
Schéma par tenantSchéma de base de données séparé par tenantIsolation moyenne, migrations faciles par tenant
Base par tenantBase de données séparée par tenantEntreprise, résidence stricte des données, conformité élevée (SOC 2, HIPAA)
HybrideDonnées centrales partagées ; données sensibles isoléesSecteurs réglementés avec offres multi-niveaux

Règles pour la location de schéma partagé :

  • Chaque requête doit filtrer par tenant_id — appliquez via un dépôt de base ou un middleware ORM, pas par la discipline du développeur
  • Utilisez la Sécurité au niveau des lignes (RLS) de PostgreSQL comme deuxième couche de défense :
    ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
    CREATE POLICY tenant_isolation ON orders
      USING (tenant_id = current_setting('app.current_tenant')::uuid);
    
  • Indexez tenant_id sur chaque table à portée de tenant
  • Écrivez des tests d'intégration qui vérifient l'isolation des données entre tenants
  • Limitez tous les chemins de stockage d'objets : s3://bucket/{tenantId}/uploads/{fileId}
  • N'exposez jamais d'ID séquentiels prévisibles — utilisez des UUID (v7 pour la triabilité)

Abonnements & Facturation

Abonnements à tarif fixe

  • Déléguez la facturation à un fournisseur (Stripe, Paddle, LemonSqueezy) — n'implémentez jamais le traitement des paiements en interne
  • Stockez uniquement customerId et subscriptionId dans votre base de données ; jamais les données de carte
  • Synchronisez l'état via des webhooks — traitez votre base de données comme une réplique en lecture cohérente en dernier ressort de la vérité du fournisseur de facturation :
    customer.subscription.created  → activer le plan
    customer.subscription.updated  → mise à niveau / rétrogradation / changement de siège
    customer.subscription.deleted  → annuler + commencer la période de grâce
    invoice.payment_failed         → dunning : notifier → restreindre → annuler
    
  • Utilisez l'id de l'événement webhook comme clé d'idempotence — stockez-la avant le traitement ; ignorez si déjà vue
  • Stockez les payloads bruts des webhooks pour l'audit et la relecture

Facturation à l'usage / mesurée (par défaut moderne)

  • Suivez les événements d'utilisation au fur et à mesure (appels API, sièges, jetons consommés, Go de stockage) :
    await stripe.subscriptionItems.createUsageRecord(subscriptionItemId, {
      quantity: tokensUsed,
      timestamp: Math.floor(Date.now() / 1000),
      action: 'increment',
    });
    
  • Exposez un tableau de bord d'utilisation en direct aux clients — les surprises le jour de la facturation provoquent le désabonnement
  • Implémentez des limites souples (avertir à 80 %) et des limites strictes (bloquer à 100 %) par période de facturation
  • Envisagez un niveau gratuit + une vente incitative basée sur l'utilisation comme rampe d'accès à la Croissance pilotée par le produit (PLG)

Croissance pilotée par le produit (PLG)

  • Niveau gratuit / freemium — laissez les utilisateurs expérimenter la valeur avant de demander un paiement ; fixez des limites qui rendent les offres payantes manifestement intéressantes
  • Délai de valorisation (TTV) — mesurez et minimisez le temps entre l'inscription et la première action significative ("moment aha")
  • Invitations à la mise à niveau dans l'application — affichez des appels à l'action de mise à niveau de manière contextuelle au moment où une limite du plan est atteinte, pas dans une page de paramètres générique
  • Leads qualifiés par le produit (PQL) — notez les utilisateurs en fonction des signaux d'utilisation du produit (pas seulement des demandes de démo) pour les orienter vers les ventes
  • Fonctionnalités virales / collaboratives — invitez des coéquipiers, partagez des rapports, des pages publiques — chaque action est un canal de distribution

Intégration de fonctionnalités IA

Les produits SaaS modernes sont censés proposer des capacités natives d'IA. Appliquez ces modèles :

Assistants IA et copilotes :

  • Utilisez des réponses en streaming (SSE / ReadableStream) afin que les utilisateurs voient les jetons arriver — ne leur faites jamais attendre une réponse complète
  • Rendez toujours la sortie de l'IA modifiable — les utilisateurs doivent pouvoir corriger, affiner et s'approprier le résultat
  • Affichez des signaux de confiance et citez les sources (RAG) pour instaurer la confiance

Génération augmentée par récupération (RAG) :

  • Stockez les embeddings vectoriels par tenant dans un espace de noms isolé (Pinecone, pgvector, Qdrant) — ne mélangez jamais les données des tenants
  • Intégrez le contenu lors de l'écriture ; interrogez lors de la lecture avec similarité cosinus
  • Découpez les documents intelligemment (512–1024 jetons avec chevauchement) ; réintégrez lorsque le contenu source change

Contrôles d'utilisation et des coûts :

  • Suivez la consommation de jetons LLM par tenant — facturez ou limitez le débit en conséquence
  • Mettez en cache les prompts déterministes (même entrée → même sortie) pour réduire les coûts
  • Utilisez des modèles moins chers pour la classification/le triage ; réservez les modèles de pointe pour les tâches de génération

Confidentialité des données :

  • Proposez un avenant de traitement des données (DPA) qui indique explicitement si les données des locataires sont utilisées pour la formation du modèle
  • Offrez une option de retrait ; les clients Enterprise l'exigeront

Feature Flags & Gestion des fonctionnalités par plan

  • Limitez l'accès aux fonctionnalités au niveau du service — le masquage côté client est une question d'apparence, pas de sécurité
  • Centralisez la logique des droits dans un helper unique can(tenant, feature) :
    function can(tenant: Tenant, feature: Feature): boolean {
      return tenant.plan.features.includes(feature);
    }
    
  • Dissociez le déploiement de la fonctionnalité de sa mise à disposition à l'aide d'un système de flags (LaunchDarkly, Unleash, GrowthBook ou une simple table dans la base de données)
  • Utilisez les flags pour : déploiements progressifs (% de tenants), programmes bêta, tests A/B, interrupteurs d'arrêt d'urgence

Intégration

  • Minimisez le TTV : guidez les utilisateurs vers leur première action significative en moins de 5 minutes
  • Utilisez un flux d'intégration basé sur une liste de tâches avec des indicateurs de progression clairs
  • Pré-remplissez des exemples / données de démonstration pour que le produit ne semble pas vide lors de la première utilisation
  • Collectez le minimum de données absolu dès le départ ; reportez tout le reste
  • Déclenchez les e-mails d'intégration en fonction d'événements produit (pas seulement du temps) : bienvenue lors de l'inscription, rappel s'ils n'ont pas terminé l'étape 2 après 24h, félicitations pour le premier jalon
  • Proposez une visite interactive du produit (pas une vidéo) afin que les utilisateurs apprennent en faisant

Observabilité & Opérations

Journalisation structurée — chaque ligne de journal doit inclure :

{ "level": "info", "msg": "...", "tenantId": "...", "userId": "...", "requestId": "...", "timestamp": "..." }

Traçage distribué avec OpenTelemetry :

  • Instrumentez au niveau du framework (Next.js instrumentation.ts, middleware Express)
  • Propagez le contexte de trace entre les limites des services (en-tête traceparent)
  • Exportez vers votre backend de choix (Jaeger, Honeycomb, Datadog, Grafana Tempo)

Indicateurs par tenant à suivre :

  • Utilisateurs actifs (DAU/MAU), volume d'appels API, taux d'erreur, latence p50/p95/p99, adoption des fonctionnalités, stockage consommé

Alerting :

  • Alertez sur les anomalies au niveau du tenant — pic d'erreur soudain, baisse d'utilisation, échecs de facturation
  • Définissez des SLO par niveau : gratuit (au mieux), pro (99,5 %), enterprise (99,9 %)

Outils d'administration (internes) :

  • Usurpez l'identité d'un tenant pour le support (auditez chaque usurpation)
  • Consultez le journal d'audit, gérez les abonnements, remplacez les feature flags, déclenchez une ré-intégration
  • Construisez un tableau de bord d'état : statut par tenant, erreurs récentes, tendances d'utilisation

Données, Analytique & Conformité

Suivi d'événements :

  • Émettez des événements produit structurés (user.signed_up, feature.used, subscription.upgraded) vers un entrepôt de données (Snowflake, BigQuery) ou un CDP (Segment, PostHog, RudderStack)
  • Utilisez ces événements pour la prédiction de désabonnement, l'analyse de cohorte et la notation PLG

RGPD / confidentialité :

  • Fournissez un point de terminaison d'exportation de données et un point de terminaison de suppression de compte — requis par le RGPD et attendu par les acheteurs enterprise
  • Documentez votre politique de conservation des données ; mettez en œuvre des purges automatisées
  • Utilisez la gestion du consentement pour les cookies marketing et l'analyse

SOC 2 / Hygiène de conformité (prêt pour l'enterprise) :

  • Maintenez un journal d'audit de toutes les actions utilisateur modifiant l'état (qui, quoi, quand, depuis quelle IP)
  • Implémentez un contrôle d'accès basé sur les rôles (RBAC) avec des privilèges minimaux par défaut
  • Appliquez le MFA pour tous les comptes administrateur ; proposez le SSO (SAML/OIDC) pour les clients enterprise
  • Effectuez régulièrement des analyses de vulnérabilité des dépendances et des tests d'intrusion
  • Maintenez une politique de divulgation des vulnérabilités

Isolation & Sécurité des Données

  • Validez tenant_id sur chaque appel API par rapport à la session authentifiée — ne faites jamais confiance au corps de la requête
  • Limitez le débit par tenant pour éviter les effets de voisinage bruyant
  • Hachez les clés API dans la base de données (bcrypt ou Argon2) ; ne stockez jamais en texte clair
  • Exigez HTTPS ; définissez Strict-Transport-Security avec un max-age long
  • Utilisez HttpOnly ; Secure ; SameSite=Lax pour les cookies de session

Exemples

// Dépôt à portée de tenant avec contexte RLS
class TenantRepository<T> {
  constructor(
    private readonly tenantId: string,
    private readonly db: PrismaClient,
  ) {}

  protected async withTenantContext<R>(fn: () => Promise<R>): Promise<R> {
    return this.db.$transaction(async (tx) => {
      await tx.$executeRaw`SELECT set_config('app.current_tenant', ${this.tenantId}, true)`;
      return fn();
    });
  }

  async findById(id: string): Promise<T | null> {
    return this.withTenantContext(() =>
      (this.db as any).findFirst({ where: { id, tenantId: this.tenantId } })
    );
  }
}

// Point de terminaison de streaming IA avec comptage d'utilisation par tenant
export async function POST(req: Request) {
  const session = await getSession(req);
  const { prompt } = await req.json();

  const stream = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [{ role: 'user', content: prompt }],
    stream: true,
  });

  let tokensUsed = 0;
  const readable = new ReadableStream({
    async start(controller) {
      for await (const chunk of stream) {
        const text = chunk.choices[0]?.delta?.content ?? '';
        controller.enqueue(new TextEncoder().encode(text));
        tokensUsed += chunk.usage?.completion_tokens ?? 0;
      }
      controller.close();
      // mesurer l'utilisation après la fin du streaming
      await meteringService.record(session.tenantId, 'ai_tokens', tokensUsed);
    },
  });

  return new Response(readable, { headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
}

// Webhook Stripe avec idempotence
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), async (req, res) => {
  const event = stripe.webhooks.constructEvent(
    req.body, req.headers['stripe-signature']!, process.env.STRIPE_WEBHOOK_SECRET!
  );

  const seen = await db.webhookEvent.findUnique({ where: { stripeEventId: event.id } });
  if (seen) return res.sendStatus(200);
  await db.webhookEvent.create({ data: { stripeEventId: event.id, payload: event } });

  switch (event.type) {
    case 'customer.subscription.updated':
      await subscriptionService.sync(event.data.object);
      break;
    case 'customer.subscription.deleted':
      await subscriptionService.cancel(event.data.object.metadata.tenantId);
      break;
  }

  res.sendStatus(200);
});

Références

Skills associés