Apparence
Plans & Abonnements
Klapy propose trois plans : Gratuit (essai limité), Starter (entrée de gamme) et Premium (complet). La stratégie de monétisation repose sur des plafonds de volume sur le plan Gratuit et un découpage de fonctionnalités entre Starter et Premium.
Vue d'ensemble
| Plan | Tarif (lancement) | Tarif normal | Cible |
|---|---|---|---|
| Gratuit | 0 € | 0 € | Découverte, 30 jours, sans carte bancaire |
| Starter | 9 € HT/mois | 15 € HT/mois | Vidéaste freelance qui veut centraliser sa prospection |
| Premium | 19 € HT/mois | 29 € HT/mois | Vidéaste qui facture régulièrement, a besoin d'acomptes et de support prioritaire |
Pas d'engagement, résiliable à tout moment.
Fonctionnalités par plan
Gratuit (essai)
- Accès complet 30 jours
- Plafond strict : 5 clients
- Toutes les fonctionnalités Starter sont accessibles pendant la période d'essai
Starter
- Clients & contacts illimités
- Pipeline commercial complet
- Suivi prospects avancé
- Dashboard CA temps réel
- Gestion des tâches
- Synchronisation Google Calendar
- Ressources & accompagnement
- Portfolio
- Devis & factures (basique)
Premium
- Tout Starter, plus :
- Devis professionnels vidéaste
- Factures & acomptes intégrés
- Support prioritaire
Les libellés exacts et les plafonds sont la source de vérité publiée sur klapy.fr. Cette page reflète l'état actuel du site marketing.
Principe de gating
Le découpage suit deux axes :
- Plafonds de volume : actuellement appliqués uniquement sur le plan Gratuit (5 clients). Au-delà du palier, l'utilisateur doit passer à Starter ou Premium.
- Fonctionnalités payantes : certaines fonctionnalités sont réservées aux plans payants (ex. import CSV en masse), ou réparties entre Starter et Premium (ex. acomptes intégrés sont Premium uniquement).
Pour les comptes Gratuit qui tentent d'utiliser une fonctionnalité réservée, le bouton reste visible avec un badge Pro et ouvre une fenêtre d'incitation à passer au plan supérieur. Cela favorise la découverte du produit pendant la période d'essai sans frustrer l'utilisateur.
Quotas et compteurs (système technique)
Compteurs dénormalisés
Chaque utilisateur a un document users/{uid} avec des champs compteurs maintenus en temps réel :
contacts_countquotes_active_countinvoices_month_countstorage_bytes_usedemails_month_count
Les compteurs sont mis à jour par des triggers Firestore à chaque création / suppression de document. L'utilisateur voit son usage actualisé instantanément dans l'interface (binding réactif via VueFire useDocument), sans rechargement.
Application serveur
Avant chaque écriture concernée, la Cloud Function appelle assertQuota(uid, resource, increment). Si l'opération dépasserait le plafond, la fonction lève une erreur resource-exhausted avec le code quota_exceeded:<resource> et un payload { plan, used, cap, requested } que le client utilise pour afficher une fenêtre d'upsell ciblée.
Source de vérité côté serveur : functions/src/lib/quotas.ts. Côté client (UX uniquement) : src/constants/plans.ts.
Sécurité
Les champs compteurs sont en écriture serveur uniquement (règles Firestore). Aucun client ne peut les modifier, ce qui empêche un utilisateur Gratuit de remettre son compteur à zéro pour contourner la limite.
Réconciliation
En cas de dérive (échec d'un trigger, migration), la Cloud Function admin adminBackfillUsage recalcule les compteurs à partir de la source de vérité (les documents eux-mêmes) et normalise les téléphones legacy au format E.164. Idempotente : peut être lancée manuellement ou planifiée hebdomadairement.
Expérience utilisateur
Avertissement à 80%
Quand un utilisateur atteint 80 % de son plafond sur une ressource, l'interface affiche un message discret (ex. « 4/5 clients, bientôt la limite ») près de l'action concernée. Le composable usePlanLimits() expose nearCap(resource) pour câbler ce comportement.
Blocage à 100%
À l'atteinte du plafond :
- Côté serveur : la Cloud Function rejette la création.
- Côté client : la fenêtre
UpgradeModals'ouvre avec le contexte (« Limite de 5 clients atteinte. Passez à Starter pour continuer. ») et un bouton qui redirige vers/app/settings?tab=billing.
Bouton « Pro » sur fonctionnalités payantes
Pour les actions réservées aux plans payants :
- Comptes Gratuit : bouton visible avec badge ; clic ouvre la fenêtre d'upsell.
- Comptes Starter / Premium : bouton sans badge ; clic ouvre la fonctionnalité.
Le composable usePlanLimits().canBulk(feature) centralise la décision côté client. Le serveur applique sa propre vérification, indépendante du badge.
Relation avec Stripe
Le champ plan du document users/{uid} est synchronisé via le webhook Stripe (à venir, voir technical/stripe.md). Lorsque l'utilisateur change de plan, son champ plan change instantanément et toutes les vérifications de quota basculent vers les plafonds du nouveau plan lors de la requête suivante. Aucun cache local à invalider grâce aux bindings VueFire réactifs.
Conventions pour les futures fonctionnalités
Quand on ajoute une fonctionnalité qui consomme une ressource :
- Ajouter (ou réutiliser) une entrée dans
LIMITScôté serveur et côté client (functions/src/lib/quotas.ts+src/constants/plans.ts, à garder en miroir). - Si la ressource est nouvelle : ajouter le champ compteur sur
users/{uid}, créer le triggeronCreate / onDelete, ajouter le champ à la liste des champs protégés dansfirestore.rules, et étendreadminBackfillUsage. - Côté Cloud Function d'écriture : appeler
assertQuota()avant l'opération (transactionnel pour les ressources hot-path). - Côté UI : utiliser
usePlanLimits()pour les avertissements à 80 % et le composantUpgradeModalpour les blocages. - Les valeurs exactes des plafonds restent à valider en interne avant toute communication externe.