Dokumentation
Plan-Limits
Serverseitige Durchsetzung von Plan-Limits mit dem Billing-Katalog und checkLimit().
Motoko Base definiert numerische Plan-Limits in src/lib/billing/config/plans.ts (PLAN_CATALOG). Die Usage-Einstellungsseite zeigt den Fortschritt gegenüber diesen Limits. Die Durchsetzung erfolgt serverseitig in Feature-Mutationen — niemals allein in der UI.
Architecture
PLAN_CATALOG.limits
↓
getBillingSummary(userId) → summaryGetLimit()
↓
checkLimit(userId, limitId, currentUsage, delta)
↓
Server Action / route handler rejects or allows mutationLimits werden aus der Billing-Zusammenfassung des Nutzers aufgelöst. Nutzer ohne bezahlten Zugang (einschließlich past_due) erhalten Free-Tier-Limits. Wenn Polar nicht konfiguriert ist, erlaubt checkLimit() Mutationen, damit lokale Entwicklung mit Minimal-Konfiguration weiter funktioniert.
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
}Ergebnisse:
| Status | Meaning |
|---|---|
allowed | Mutation darf fortgesetzt werden (limit: null = unbegrenzt) |
limit_reached | Würde das Plan-Limit überschreiten |
unavailable | Billing-Zusammenfassung konnte nicht aufgelöst werden |
Shipped enforcement
| Feature | Boundary | Notes |
|---|---|---|
| Links | createLinkAction | Update/Delete werden nicht am Limit blockiert |
| Storage | createUploadAction + confirmUploadAction | Vorabprüfung beim Init; maßgebliche Prüfung bei Confirm (Presigned-Upload-Lebenszyklus) |
Storage-Nutzung zählt files-Zeilen mit status = "ready" und summiert sizeBytes. Ausstehende Uploads sind nur bei der Init-Vorabprüfung enthalten.
Usage metrics registry
Die Nutzungsanzeige (src/lib/billing/usage.ts) liest Metriken aus einer Registry. Jedes Feature registriert seine Messung:
// src/features/links/usage-metric.ts
registerUsageMetric({
id: "links",
limitId: "links",
label: "Links",
measure: countLinksForUser,
});Importiere @/features/dashboard/lib/bootstrap-usage-metrics (oder die einzelnen usage-metric.ts-Module), bevor du getUsageSnapshot() aufrufst, damit die Metriken registriert sind.
Demo entfernen: Lösche den Feature-Ordner und dessen usage-metric.ts. Eine Bearbeitung von src/lib/billing/usage.ts ist nicht erforderlich.
Adding limits to a new feature
- Füge eine
LimitIdund einen Limit-Wert zuPLAN_CATALOGinconfig/plans.tshinzu. - Exportiere eine
measure(userId)-Funktion aus deinen Feature-Queries. - Registriere die Metrik in
<feature>/usage-metric.ts. - Rufe
checkLimit()in der Server-Mutation vor dem Persistieren neuen quota-verbrauchenden Zustands auf. - Übergebe die
current-Nutzung als Parameter — hardcode keine Plan-Limits im Feature.
Concurrency
Links und Storage verwenden best-effort-Durchsetzung: Zwei gleichzeitige Creates nahe am Limit können kurzzeitig beide erfolgreich sein. Das ist für den Starter akzeptabel und ehrlich dokumentiert. Strikte Durchsetzung würde Transaktionen oder pro-Nutzer-Sperren erfordern — füge das in deinem Produkt hinzu, wenn du harte Garantien brauchst.
Gleichzeitige Storage-Uploads folgen dem gleichen Modell: Die maßgebliche Prüfung läuft bei Confirm/Finalisierung, aber zwei Confirms nahe am Limit können unter Race-Bedingungen beide durchgehen.
Related docs
- Payments (Polar) — Billing-Zusammenfassung und Entitlements
- Storage — Upload-Lebenszyklus
src/lib/security/README.md— Sicherheits-Defaults