Documentação

Limites do plano

Aplicação server-side de limites do plano com o catálogo de billing e checkLimit().

Abrir emChatGPT (abre em uma nova aba)Claude (abre em uma nova aba)Cursor (abre em uma nova aba)Aplicação server-side de limites do plano com o catálogo de billing e checkLimit().

O Motoko Base define limites numéricos do plano em src/lib/billing/config/plans.ts (PLAN_CATALOG). A página de configurações de Usage exibe o progresso em relação a esses limites. A aplicação acontece no servidor nas mutações de features — nunca apenas na UI.

Architecture

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

Os limites são resolvidos a partir do resumo de billing do usuário. Usuários sem acesso pago (incluindo past_due) recebem limites do plano Free. Quando o Polar não está configurado, checkLimit() permite mutações para que o desenvolvimento local com configuração mínima continue 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
allowedA mutação pode prosseguir (limit: null = ilimitado)
limit_reachedUltrapassaria o limite do plano
unavailableNão foi possível resolver o resumo de billing

Shipped enforcement

FeatureBoundaryNotes
LinkscreateLinkActionUpdate/delete não são bloqueados pelo limite
StoragecreateUploadAction + confirmUploadActionPré-verificação no init; verificação definitiva no confirm (ciclo de vida de upload presignado)

O uso de storage conta linhas files com status = "ready", somando sizeBytes. Uploads pendentes são incluídos apenas na pré-verificação do init.

Usage metrics registry

A exibição de uso (src/lib/billing/usage.ts) lê métricas de um registro. Cada feature registra sua medida:

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

Importe @/features/dashboard/lib/bootstrap-usage-metrics (ou os módulos individuais usage-metric.ts) antes de chamar getUsageSnapshot() para que as métricas estejam registradas.

Remover um demo: exclua a pasta do feature e seu usage-metric.ts. Não é necessário editar src/lib/billing/usage.ts.

Adding limits to a new feature

  1. Adicione um LimitId e um valor de limite ao PLAN_CATALOG em config/plans.ts.
  2. Exporte uma função measure(userId) das queries do seu feature.
  3. Registre a métrica em <feature>/usage-metric.ts.
  4. Chame checkLimit() na mutação do servidor antes de persistir o novo estado que consome quota.
  5. Passe o uso current como parâmetro — não hardcode limites do plano no feature.

Concurrency

Links e storage usam aplicação best-effort: duas criações concorrentes perto do limite podem ter sucesso brevemente. Isso é aceitável para o starter e documentado com honestidade. Aplicação estrita exigiria transações ou locks por usuário — adicione isso no seu produto se precisar de garantias rígidas.

Uploads concorrentes de storage seguem o mesmo modelo: a verificação definitiva roda no confirm/finalização, mas dois confirms perto do limite podem passar ambos em condições de corrida.

  • Payments (Polar) — resumo de billing e entitlements
  • Storage — ciclo de vida de upload
  • src/lib/security/README.md — padrões de segurança