Documentation

Limites du plan

Application server-side des limites du plan avec le catalogue de billing et checkLimit().

Ouvrir dansChatGPT (s’ouvre dans un nouvel onglet)Claude (s’ouvre dans un nouvel onglet)Cursor (s’ouvre dans un nouvel onglet)Application server-side des limites du plan avec le catalogue de billing et checkLimit().

Motoko Base définit des limites numériques du plan dans src/lib/billing/config/plans.ts (PLAN_CATALOG). La page des paramètres Usage affiche la progression par rapport à ces limites. L'application s'effectue côté serveur dans les mutations de features — jamais dans l'UI seule.

Architecture

PLAN_CATALOG.limits
   ↓
getBillingSummary(userId) → summaryGetLimit()
   ↓
checkLimit(userId, limitId, currentUsage, delta)
   ↓
Server Action / route handler rejects or allows mutation

Les limites sont résolues à partir du résumé de billing de l'utilisateur. Les utilisateurs sans accès payant (y compris past_due) reçoivent les limites du plan Free. Lorsque Polar n'est pas configuré, checkLimit() autorise les mutations pour que le développement local avec configuration minimale continue de fonctionner.

checkLimit API

import { checkLimit } from "@/lib/billing";

const result = await checkLimit(userId, "links", currentCount, 1);

if (result.status === "limit_reached") {
  // reject mutation with user-facing message
}

if (result.status === "unavailable") {
  // billing lookup failed — fail closed with safe error
}

Résultats :

StatusMeaning
allowedLa mutation peut continuer (limit: null = illimité)
limit_reachedDépasserait la limite du plan
unavailableImpossible de résoudre le résumé de billing

Shipped enforcement

FeatureBoundaryNotes
LinkscreateLinkActionUpdate/delete ne sont pas bloqués par la limite
StoragecreateUploadAction + confirmUploadActionPré-vérification à l'init ; vérification autoritaire à la confirmation (cycle de vie d'upload presigné)

L'utilisation du stockage compte les lignes files avec status = "ready", en additionnant sizeBytes. Les uploads en attente ne sont inclus que dans la pré-vérification à l'init.

Usage metrics registry

La visualisation de l'utilisation (src/lib/billing/usage.ts) lit les métriques depuis un registre. Chaque feature enregistre sa mesure :

// src/features/links/usage-metric.ts
registerUsageMetric({
  id: "links",
  limitId: "links",
  label: "Links",
  measure: countLinksForUser,
});

Importez @/features/dashboard/lib/bootstrap-usage-metrics (ou les modules individuels usage-metric.ts) avant d'appeler getUsageSnapshot() pour que les métriques soient enregistrées.

Supprimer une démo : supprimez le dossier du feature et son usage-metric.ts. Aucune modification de src/lib/billing/usage.ts n'est requise.

Adding limits to a new feature

  1. Ajoutez un LimitId et une valeur de limite à PLAN_CATALOG dans config/plans.ts.
  2. Exportez une fonction measure(userId) depuis les queries de votre feature.
  3. Enregistrez la métrique dans <feature>/usage-metric.ts.
  4. Appelez checkLimit() dans la mutation serveur avant de persister le nouvel état consommant du quota.
  5. Passez l'utilisation current en paramètre — ne hardcodez pas les limites du plan dans le feature.

Concurrency

Links et le stockage utilisent une application best-effort : deux créations concurrentes près de la limite peuvent toutes deux réussir brièvement. C'est acceptable pour le starter et documenté honnêtement. Une application stricte nécessiterait des transactions ou des verrous par utilisateur — ajoutez cela dans votre produit si vous avez besoin de garanties fermes.

Les uploads de stockage concurrents suivent le même modèle : la vérification autoritaire s'exécute à la confirmation/finalisation, mais deux confirmations près de la limite peuvent toutes deux passer en conditions de course.

  • Payments (Polar) — résumé de billing et entitlements
  • Storage — cycle de vie des uploads
  • src/lib/security/README.md — valeurs par défaut de sécurité