Use when implementing feature gating, quota enforcement, and plan-based access control. Covers entitlements vs feature flags, quota systems, and integration with subscription tiers.
Implements feature gating and quota enforcement based on subscription tiers. Use when building plan-based access control or usage limits for API calls, storage, and seats.
/plugin marketplace add melodic-software/claude-code-plugins/plugin install saas-patterns@melodic-softwareThis skill is limited to using the following tools:
Patterns for controlling feature access and enforcing usage quotas based on subscription plans.
Key Distinction:
┌────────────────────────────────────────────────────────────┐
│ │
│ FEATURE FLAGS ENTITLEMENTS │
│ ───────────── ──────────── │
│ Release management Access control │
│ A/B testing Plan-based gating │
│ Gradual rollouts Quota enforcement │
│ Kill switches Subscription features │
│ Temporary Permanent │
│ Dev/ops controlled Business controlled │
│ │
│ "Is this feature ready?" "Can this customer use it?" │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Example: │ │
│ │ - Feature Flag: "dark_mode_v2" = true (released) │ │
│ │ - Entitlement: "dark_mode" = Pro plan only │ │
│ │ │ │
│ │ Check: featureEnabled && hasEntitlement │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────┘
Entitlements Model:
┌────────────────────────────────────────────────────────────┐
│ │
│ PLAN DEFINITION │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Plan: Pro │ │
│ │ ├── Features: [analytics, api_access, custom_domain] │ │
│ │ ├── Quotas: │ │
│ │ │ ├── api_calls: 10,000/month │ │
│ │ │ ├── storage_gb: 50 │ │
│ │ │ └── team_members: 10 │ │
│ │ └── Limits: │ │
│ │ ├── projects: 100 │ │
│ │ └── integrations: 5 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ CUSTOMER ENTITLEMENTS │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Customer: Acme Corp │ │
│ │ Base Plan: Pro │ │
│ │ Overrides: │ │
│ │ ├── storage_gb: 100 (negotiated) │ │
│ │ └── api_calls: 50,000 (add-on purchased) │ │
│ │ Usage: │ │
│ │ ├── api_calls: 8,500 / 50,000 (17%) │ │
│ │ └── storage_gb: 42 / 100 (42%) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────┘
Entitlements Schema:
┌────────────────────────────────────────────────────────────┐
│ │
│ plans │
│ ├── id: UUID │
│ ├── name: "Pro" │
│ ├── price_monthly: 99.00 │
│ └── is_active: true │
│ │
│ plan_features (many-to-many) │
│ ├── plan_id: FK → plans │
│ ├── feature_id: FK → features │
│ └── enabled: true │
│ │
│ plan_quotas │
│ ├── plan_id: FK → plans │
│ ├── quota_type: "api_calls" │
│ ├── limit_value: 10000 │
│ ├── period: "monthly" | "daily" | "unlimited" │
│ └── enforcement: "hard" | "soft" | "warning" │
│ │
│ customer_entitlements (per-customer overrides) │
│ ├── customer_id: FK → customers │
│ ├── feature_id: FK → features (nullable) │
│ ├── quota_type: string (nullable) │
│ ├── override_value: varies │
│ └── expires_at: timestamp (nullable) │
│ │
│ usage_records │
│ ├── customer_id: FK → customers │
│ ├── quota_type: "api_calls" │
│ ├── period_start: date │
│ ├── current_usage: 8500 │
│ └── last_updated: timestamp │
│ │
└────────────────────────────────────────────────────────────┘
Simple Feature Check:
┌────────────────────────────────────────────────────────────┐
│ // Service layer │
│ public async Task<bool> CanAccessFeatureAsync( │
│ string customerId, string featureKey) │
│ { │
│ var entitlements = await _entitlementService │
│ .GetCustomerEntitlementsAsync(customerId); │
│ │
│ return entitlements.HasFeature(featureKey); │
│ } │
│ │
│ // Usage │
│ if (await CanAccessFeatureAsync(customerId, "analytics")) │
│ { │
│ // Show analytics dashboard │
│ } │
│ else │
│ { │
│ // Show upgrade prompt │
│ } │
└────────────────────────────────────────────────────────────┘
Feature with Tier Levels:
┌────────────────────────────────────────────────────────────┐
│ Feature: "export" │
│ ├── Free: CSV only │
│ ├── Pro: CSV, Excel │
│ └── Enterprise: CSV, Excel, PDF, API │
│ │
│ // Implementation │
│ public async Task<ExportCapabilities> GetExportCapabilities│
│ (string customerId) │
│ { │
│ var tier = await GetCustomerTier(customerId); │
│ │
│ return tier switch │
│ { │
│ "free" => new([ExportFormat.Csv]), │
│ "pro" => new([ExportFormat.Csv, ExportFormat.Excel]), │
│ "enterprise" => new([..all formats..]), │
│ _ => throw new InvalidTierException() │
│ }; │
│ } │
└────────────────────────────────────────────────────────────┘
Quota Categories:
┌────────────────────────────────────────────────────────────┐
│ Type │ Examples │ Reset │
│ ──────────────┼─────────────────────────┼──────────────── │
│ Rate Limits │ API calls/minute │ Rolling window │
│ Usage Quotas │ API calls/month │ Billing cycle │
│ Storage │ GB stored │ Never (current) │
│ Count Limits │ Projects, team members │ Never (current) │
│ Bandwidth │ GB transferred/month │ Billing cycle │
└────────────────────────────────────────────────────────────┘
Enforcement Strategies:
┌────────────────────────────────────────────────────────────┐
│ │
│ WARNING (Soft Limit) │
│ ├── Notify user approaching limit │
│ ├── Continue allowing usage │
│ ├── Log for billing/upsell │
│ └── Example: "You've used 80% of your API quota" │
│ │
│ SOFT LIMIT │
│ ├── Allow overage with warning │
│ ├── May incur overage charges │
│ ├── Grace period before hard enforcement │
│ └── Example: Storage overage at $0.10/GB │
│ │
│ HARD LIMIT │
│ ├── Block access when limit reached │
│ ├── Return 429 Too Many Requests │
│ ├── Require upgrade to continue │
│ └── Example: "API limit reached. Upgrade to continue." │
│ │
│ DEGRADED SERVICE │
│ ├── Reduce service quality instead of blocking │
│ ├── Slower response times │
│ ├── Reduced features │
│ └── Example: Lower priority queue for API requests │
│ │
└────────────────────────────────────────────────────────────┘
Quota Checking Pattern:
┌────────────────────────────────────────────────────────────┐
│ public record QuotaCheckResult( │
│ bool IsAllowed, │
│ long CurrentUsage, │
│ long Limit, │
│ QuotaStatus Status, │
│ string? Message); │
│ │
│ public async Task<QuotaCheckResult> CheckQuotaAsync( │
│ string customerId, │
│ string quotaType, │
│ int requestedAmount = 1) │
│ { │
│ var quota = await GetQuotaAsync(customerId, quotaType); │
│ var usage = await GetUsageAsync(customerId, quotaType); │
│ │
│ var newUsage = usage.Current + requestedAmount; │
│ var percentUsed = (newUsage * 100) / quota.Limit; │
│ │
│ if (newUsage > quota.Limit) │
│ { │
│ return new(false, usage.Current, quota.Limit, │
│ QuotaStatus.Exceeded, │
│ $"Quota exceeded. Limit: {quota.Limit}"); │
│ } │
│ │
│ if (percentUsed >= 90) │
│ { │
│ return new(true, newUsage, quota.Limit, │
│ QuotaStatus.Warning, │
│ $"Approaching limit: {percentUsed}% used"); │
│ } │
│ │
│ return new(true, newUsage, quota.Limit, │
│ QuotaStatus.Ok, null); │
│ } │
└────────────────────────────────────────────────────────────┘
Increment Usage Pattern:
┌────────────────────────────────────────────────────────────┐
│ // High-performance: Async increment with eventual sync │
│ │
│ 1. Request comes in │
│ │ │
│ 2. Check quota (from cache) │
│ │ │
│ 3. Allow request (optimistic) │
│ │ │
│ 4. Increment local counter │
│ │ │
│ 5. Async: Batch sync to database │
│ - Every N requests, or │
│ - Every M seconds │
│ │
│ Trade-off: │
│ - Fast: No DB write per request │
│ - Risk: Slight over-quota before sync │
│ - Mitigation: Conservative thresholds (95% hard limit) │
└────────────────────────────────────────────────────────────┘
Upgrade Trigger Points:
┌────────────────────────────────────────────────────────────┐
│ Trigger │ Action │
│ ──────────────────────────┼─────────────────────────────── │
│ 80% quota used │ In-app warning banner │
│ 100% quota reached │ Block + upgrade modal │
│ Feature attempted (gated) │ "Upgrade for X" dialog │
│ Limit reached (projects) │ "Upgrade for more projects" │
│ High-tier feature preview │ "Available on Pro" overlay │
└────────────────────────────────────────────────────────────┘
UX Best Practices:
┌────────────────────────────────────────────────────────────┐
│ ✓ Show value, not just restriction │
│ "Unlock analytics to understand your customers" │
│ NOT "This feature is not available" │
│ │
│ ✓ Provide clear path forward │
│ "Upgrade to Pro for $29/month" │
│ NOT "Contact sales" │
│ │
│ ✓ Be transparent about limits │
│ Progress bars showing usage │
│ Clear limit displays in settings │
│ │
│ ✓ Offer alternatives │
│ "Delete old projects" OR "Upgrade for unlimited" │
└────────────────────────────────────────────────────────────┘
Entitlement Platforms:
┌────────────────────────────────────────────────────────────┐
│ Service │ Strengths │ Best For │
│ ──────────────┼──────────────────────────┼──────────────── │
│ LaunchDarkly │ Feature flags + basic │ Flag-heavy apps │
│ │ targeting │ │
│ ──────────────┼──────────────────────────┼──────────────── │
│ Stigg │ Full entitlements + │ SaaS billing │
│ │ metering │ │
│ ──────────────┼──────────────────────────┼──────────────── │
│ Schematic │ Entitlements-first │ Enterprise SaaS │
│ ──────────────┼──────────────────────────┼──────────────── │
│ Custom │ Full control │ Complex needs │
└────────────────────────────────────────────────────────────┘
LaunchDarkly with Entitlements:
┌────────────────────────────────────────────────────────────┐
│ // Combine feature flags with entitlements │
│ │
│ public async Task<bool> IsFeatureEnabled( │
│ string customerId, string featureKey) │
│ { │
│ // Check feature flag (is it released?) │
│ var flagEnabled = await _launchDarkly │
│ .BoolVariation(featureKey, user, false); │
│ │
│ if (!flagEnabled) return false; │
│ │
│ // Check entitlement (can this customer use it?) │
│ var hasEntitlement = await _entitlementService │
│ .HasFeatureAsync(customerId, featureKey); │
│ │
│ return hasEntitlement; │
│ } │
└────────────────────────────────────────────────────────────┘
Cache Architecture:
┌────────────────────────────────────────────────────────────┐
│ │
│ Request → Check Cache → Cache Hit? → Return │
│ │ │
│ └──→ Cache Miss → Load from DB → Cache │
│ │
│ Cache Configuration: │
│ ├── Key: entitlements:{customer_id} │
│ ├── TTL: 5 minutes (balance freshness vs load) │
│ ├── Invalidation: On plan change, purchase, override │
│ └── Type: Distributed (Redis) for multi-instance │
│ │
│ Invalidation Triggers: │
│ ├── Subscription upgraded/downgraded │
│ ├── Add-on purchased │
│ ├── Trial started/ended │
│ ├── Custom override applied │
│ └── Billing period changed │
│ │
└────────────────────────────────────────────────────────────┘
Critical Test Cases:
┌────────────────────────────────────────────────────────────┐
│ Feature Access: │
│ ✓ User on Free cannot access Pro feature │
│ ✓ User on Pro can access Pro feature │
│ ✓ Downgrade removes feature access │
│ ✓ Upgrade grants feature access │
│ ✓ Trial grants temporary access │
│ ✓ Expired trial removes access │
│ │
│ Quota Enforcement: │
│ ✓ Usage below limit allowed │
│ ✓ Usage at limit shows warning │
│ ✓ Usage over limit blocked (hard limit) │
│ ✓ Usage over limit logged (soft limit) │
│ ✓ Quota reset at billing cycle │
│ ✓ Upgrade increases quota │
│ │
│ Edge Cases: │
│ ✓ Concurrent requests near limit │
│ ✓ Plan change mid-billing cycle │
│ ✓ Multiple overrides (most permissive wins?) │
│ ✓ Expired override reverts to plan │
└────────────────────────────────────────────────────────────┘
Entitlements Best Practices:
┌────────────────────────────────────────────────────────────┐
│ 1. Separation of Concerns │
│ - Feature flags: Release management │
│ - Entitlements: Access control │
│ - Don't mix them │
│ │
│ 2. Fail Open or Closed? │
│ - Critical features: Fail closed (deny on error) │
│ - Nice-to-have: Fail open (allow on error) │
│ - Always log failures for investigation │
│ │
│ 3. Graceful Degradation │
│ - Show what they can't access (with upgrade CTA) │
│ - Don't hide features entirely │
│ - Preview mode for gated features │
│ │
│ 4. Transparency │
│ - Clear usage dashboards │
│ - Proactive limit warnings │
│ - Self-serve upgrade paths │
│ │
│ 5. Performance │
│ - Cache aggressively, invalidate precisely │
│ - Batch usage updates │
│ - Check entitlements once per request │
└────────────────────────────────────────────────────────────┘
subscription-models - Pricing tier designusage-metering - Event-driven usage trackingbilling-integration - Stripe entitlements syncLast Updated: 2025-12-26
Use when working with Payload CMS projects (payload.config.ts, collections, fields, hooks, access control, Payload API). Use when debugging validation errors, security issues, relationship queries, transactions, or hook behavior.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.