Feature paywall + access restriction

Two sibling sub-patterns: (a) **paywall** — what surfaces when a feature is gated by a paid tier the user hasn't subscribed to; (b) **permission restriction** — what surfaces when the user lacks the required role / scope. Modeled after MongoDB LeafyGreen FeatureWalls.

Pattern — Feature paywall / access restriction

*tatus* v0.1.0 — Draft. Koder Stack today is free-tier only, but the moment a tiered plan or per-tenant entitlement lands this spec is needed.

R1 — Hide vs disable vs paywall vs restriction

Situation Pattern
Feature exists, but user's tier excludes it *aywall*— show feature with upgrade overlay
Feature exists, but user's role lacks permission *estriction*— show feature with "request access" overlay
Feature doesn't exist for the user's deployment at all *ide*— feature absent from UI entirely
Feature transiently unavailable (server, network) *isable*— show as disabled with explanatory tooltip

The four are NOT interchangeable. Pick by the decision tree above.

R2 — Paywall anatomy

Overlay on top of the feature surface (semi-transparent backdrop + centered card):

  • Lock icon (sparkle-locked variant from icon set).
  • Heading: {Feature name} is part of {Plan name}.
  • Body: 1–2 sentences explaining the benefit.
  • Primary CTA: Upgrade plan → billing flow.
  • Secondary link: Learn more about plans.

Tone: informative, never pushy. Per specs/content/voice-and-tone.kmd marketing column.

R3 — Restriction anatomy

Overlay or pagelevel message (no semitransparent backdrop — the user should not perceive the feature as "almost reachable"):

  • Permission-denied icon (shield).
  • Heading: You don't have access to {feature name}.
  • Body: 1 sentence: Ask {admin role} for the {permission slug} permission.
  • Primary action: Request access (opens form / email composer with

    pre-filled context).

  • Secondary: Learn about permissions (link to product docs).

No upsell CTA. Per multitenancy: NEVER reveal crosstenant data even in the restriction message (cross-tenant access = 404, not 403, per specs/multi-tenancy/contract.kmd).

R4 — Accessibility

  • Modal overlay: focus trap (Tab cycles inside; Esc dismisses overlay returning user to safe surface).
  • Backdrop click on paywall: dismisses overlay (don't trap user).
  • Restriction: no Esc behavior since there's nothing to dismiss; user navigates away normally.
  • Live-region announce on appearance: "{Feature name} requires {Plan / Permission}".

R5 — Graceful keyboard nav

  • Tab order: heading → body → primary CTA → secondary link → close (if any).
  • Enter on primary CTA activates.
  • Esc on paywall: dismiss (returns to safe surface).
  • Esc on restriction: no-op (user uses their browser/system back).

R6 — Internationalization

All strings translatable per specs/i18n/contract.kmd. Keys paywall.{feature}.heading|body|primary|secondary and restriction.{feature}.heading|body|primary|secondary.

Plan and Permission names use their canonical localized form.

Não-escopo

  • Billing / entitlement engine (servicesfoundationbilling concern).
  • Permission model itself (servicesfoundationidentity concern).
  • A/B-tested upgrade copy (product concern).

Source: ../home/koder/dev/koder/meta/docs/stack/specs/patterns/feature-paywall.kmd