Access & gating
Most CMS content types share the same Visibility and Teaser fields. These control who sees full content vs a gated preview.
Visibility options
Set on articles, frameworks, resources, podcasts, learning paths, and assessments.
| CMS label | Database value | Who gets full access |
|---|---|---|
| Public | FREE |
Everyone — no account required |
| Free member | SUBSCRIBER |
Any signed-in member |
| Premium | PREMIUM |
Premium plan or individual learning path purchase |
Note: The admin form shows three options. Enterprise (
ENTERPRISE) exists on user plans but is not selectable in the CMS visibility dropdown — assign Enterprise manually on user records at/admin/users.
Plan hierarchy
Plans are ranked for access checks:
FREE (0) < SUBSCRIBER (1) < PREMIUM (2) < ENTERPRISE (3)
A user's plan must meet or exceed the content's visibility level. Logic lives in src/lib/resource-access.ts (canAccess).
Teaser field
When content is gated, visitors see a teaser instead of the full body:
- Set explicitly in the Teaser textarea, or
- Falls back to excerpt / summary / description (varies by content type)
Write teasers that explain value without giving away premium content.
What gated users see
| Visitor state | Free member content | Premium content |
|---|---|---|
| Not signed in | Gate panel → "Create free account" → /signup |
Gate panel → "Sign in" → /login |
| Signed in, free plan | Full access | Gate panel → "Upgrade to Premium" → /pricing |
| Premium plan | Full access | Full access |
Gate copy is generated by gateReason, gateHeadline, and gateCTA in src/lib/resource-access.ts.
Content types with gating
| Type | Visibility field | Teaser fallback |
|---|---|---|
| Articles | Yes | Excerpt |
| Frameworks | Yes | Summary |
| Resources | Yes | Description |
| Podcasts | Yes | Description |
| Learning paths | Yes | Description |
| Assessments | Yes | Description |
Downloads
Resources use the same visibility via /api/dl/[id]:
- Allowed → redirect to file URL
- Blocked → redirect to signup, login, or
/pricing(same rules as content gates)
Learning path exceptions
Path access uses visibility plus individual purchase:
- User's plan covers the path visibility → access
- Or user bought the path (when price is set) → access regardless of plan
See Learning paths.
Setting member plans manually
Admins can override a user's plan at /admin/users:
| Plan | Use case |
|---|---|
| Free | Default registered member |
| Subscriber | Newsletter-tier access |
| Premium | Full premium content |
| Enterprise | Highest tier (manual grants) |
Stripe webhooks automatically set Premium when a subscription is active.
Editorial checklist
Before setting Premium visibility:
- Stripe is configured — see Commerce setup
-
/pricingpage loads and checkout works in test mode - Teaser text is compelling and accurate
- Test as anonymous, free member, and premium user
Visibility badges
Listing cards show pills for non-public content ("Member content", "Premium content"). Public content has no badge.
Member plan badges appear on /account.