Use when working with membership tiers, content access control, Stripe billing, paywall gates, or the member portal. Triggers on "tier", "paywall", "access control", "subscription", "checkout", "billing", "member portal".
How tiers, billing, and content gating work.
AGENTS.md, CLAUDE.md, docs/standards/agent-knowledge-protocol.md. Task-scoped: Stripe and tiers in CLAUDE.md; billing ops in docs/ops/member-billing-sop.md; env names in docs/ops/env-vars.md.
free < basic < premium
Never compare tier strings directly — always use helpers:
import { includesTier, compareTiers } from '@/lib/membership';
includesTier('premium', 'basic'); // true — premium includes basic
compareTiers('basic', 'premium'); // -1 — basic < premium
Access checking — use checkContentAccess():
import { checkContentAccess } from '@/lib/supabase/access';
const { hasAccess, user } = await checkContentAccess(content.access_tier);
Paywall rendering — show preview + gate:
{hasAccess ? (
<FullContent />
) : (
<PaywallGate
requiredTier={content.access_tier}
previewBody={content.body.slice(0, 300)}
isLoggedIn={!!user}
nextHref={`/articles/${content.slug}`}
/>
)}
| Flow | Route | Description |
|---|---|---|
| Membership checkout | /api/stripe/checkout | Creates Stripe Checkout session for basic/premium |
| Donation | /api/stripe/donate | One-time or recurring donation |
| Manage billing | /api/stripe/manage-billing | Redirects to Stripe Customer Portal |
| Webhook | /api/stripe/webhook | Handles subscription lifecycle events |
Config: src/lib/stripe/config.ts (client), src/lib/stripe/helpers.ts (session creation)
src/app/(auth)/portal/src/app/(auth)/portal/settings/ (tier upgrade, profile)src/components/portal/ (CheckoutButton, SubscriptionManager, TierBadge)Members table: email, tier (free|basic|premium), role (member|editor|admin), stripe_customer_id, stripe_subscription_id
Query: getMemberById() from src/lib/supabase/queries.ts