Documentación

Límites del plan

Aplicación server-side de límites del plan con el catálogo de billing y checkLimit().

Abrir enChatGPT (se abre en una pestaña nueva)Claude (se abre en una pestaña nueva)Cursor (se abre en una pestaña nueva)Aplicación server-side de límites del plan con el catálogo de billing y checkLimit().

Motoko Base define límites numéricos del plan en src/lib/billing/config/plans.ts (PLAN_CATALOG). La página de ajustes de Usage muestra el progreso respecto a esos límites. La aplicación ocurre en el servidor en las mutaciones de features — nunca solo en la UI.

Architecture

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

Los límites se resuelven a partir del resumen de billing del usuario. Los usuarios sin acceso de pago (incluido past_due) reciben límites del plan Free. Cuando Polar no está configurado, checkLimit() permite las mutaciones para que el desarrollo local con configuración mínima siga funcionando.

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
}

Resultados:

StatusMeaning
allowedLa mutación puede continuar (limit: null = ilimitado)
limit_reachedExcedería el límite del plan
unavailableNo se pudo resolver el resumen de billing

Shipped enforcement

FeatureBoundaryNotes
LinkscreateLinkActionUpdate/delete no se bloquean por el límite
StoragecreateUploadAction + confirmUploadActionPre-verificación al iniciar; verificación definitiva al confirmar (ciclo de vida de subida presignada)

El uso de storage cuenta filas files con status = "ready", sumando sizeBytes. Las subidas pendientes solo se incluyen en la pre-verificación de init.

Usage metrics registry

La visualización de uso (src/lib/billing/usage.ts) lee métricas de un registro. Cada feature registra su medida:

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

Importa @/features/dashboard/lib/bootstrap-usage-metrics (o los módulos individuales usage-metric.ts) antes de llamar a getUsageSnapshot() para que las métricas estén registradas.

Eliminar un demo: borra la carpeta del feature y su usage-metric.ts. No hace falta editar src/lib/billing/usage.ts.

Adding limits to a new feature

  1. Añade un LimitId y un valor de límite a PLAN_CATALOG en config/plans.ts.
  2. Exporta una función measure(userId) desde las queries de tu feature.
  3. Registra la métrica en <feature>/usage-metric.ts.
  4. Llama a checkLimit() en la mutación del servidor antes de persistir el nuevo estado que consume cuota.
  5. Pasa el uso current como parámetro — no codifiques límites del plan en el feature.

Concurrency

Links y storage usan aplicación best-effort: dos creaciones concurrentes cerca del límite pueden tener éxito brevemente. Esto es aceptable para el starter y está documentado con honestidad. Una aplicación estricta requeriría transacciones o bloqueos por usuario — añádelo en tu producto si necesitas garantías fuertes.

Las subidas concurrentes de storage siguen el mismo modelo: la verificación definitiva se ejecuta en confirm/finalización, pero dos confirmaciones cerca del límite pueden pasar ambas en condiciones de carrera.

  • Payments (Polar) — resumen de billing y entitlements
  • Storage — ciclo de vida de subida
  • src/lib/security/README.md — valores por defecto de seguridad