Implement a system to gate features and functions behind user tiers (Free, Pro, Enterprise). This provides the foundation for monetization and premium feature differentiation.
User Tiers
Tier
Description
free
Default tier, limited features
pro
Mid-tier, most features
enterprise
Full access to all features
Requirements
Database
Add tier column to users table if not present (enum: free, pro, enterprise, default: free)
exportconstFEATURE_TIERS={'document.scanMaintenanceSchedule':{minTier:'pro',name:'Scan for Maintenance Schedule',upgradePrompt:'Upgrade to Pro to automatically extract maintenance schedules from your manuals.'}}asconst;
// Route-level tier requirement by minimum tier
fastify.get('/premium-route',{preHandler:[fastify.requireTier({minTier:'pro'})],handler: controller.method});// Or by feature key (recommended)
fastify.post('/documents',{preHandler:[fastify.requireTier({featureKey:'document.scanMaintenanceSchedule'})],handler: controller.method});
403 Error Response
{"error":"TIER_REQUIRED","requiredTier":"pro","currentTier":"free","feature":"document.scanMaintenanceSchedule","featureName":"Scan for Maintenance Schedule","upgradePrompt":"Upgrade to Pro to..."}
-- Reset scanForMaintenance for free tier users
UPDATEdocumentsdSETscan_for_maintenance=falseFROMuser_profilesuWHEREd.user_id=u.auth0_subANDu.subscription_tier='free'ANDd.scan_for_maintenance=true;
Test Results
PASS documents.controller.tier.test.ts (8 tests)
- allows free user to create document without scanForMaintenance
- blocks free user from using scanForMaintenance=true
- allows pro user to use scanForMaintenance=true
- allows enterprise user to use scanForMaintenance=true
- defaults to free tier when userContext is missing
- allows free user to update document without scanForMaintenance
- blocks free user from setting scanForMaintenance=true on update
- allows pro user to set scanForMaintenance=true on update
Combined Test Summary (All Tier Tests)
Test Suites: 3 passed, 3 total
Tests: 30 passed, 30 total
- feature-tiers.test.ts: 14 tests
- tier-guard.plugin.test.ts: 8 tests
- documents.controller.tier.test.ts: 8 tests
Acceptance Criteria
Free users cannot set scanForMaintenance=true
Pro/Enterprise users can set scanForMaintenance=true
403 response matches structured error format
Data migration ready for deployment
Unit tests pass
Proceeding to M5: Frontend Tier Access Hook
## Milestone 4 Complete: Backend Documents Tier Validation
### Files Created
| File | Description |
|------|-------------|
| `backend/src/features/documents/migrations/003_reset_scan_for_maintenance_free_users.sql` | Data migration to reset scanForMaintenance for free users |
| `backend/src/features/documents/tests/unit/documents.controller.tier.test.ts` | Unit tests for tier validation (8 tests) |
### Files Modified
| File | Change |
|------|--------|
| `backend/src/features/documents/api/documents.controller.ts` | Added tier validation for scanForMaintenance on create/update |
### Implementation Summary
**Controller Tier Validation (lines 88-106, 134-153):**
```typescript
// Tier validation: scanForMaintenance requires Pro tier
const featureKey = 'document.scanMaintenanceSchedule';
if (request.body.scanForMaintenance && !canAccessFeature(userTier, featureKey)) {
const config = getFeatureConfig(featureKey);
return reply.code(403).send({
error: 'TIER_REQUIRED',
requiredTier: config?.minTier || 'pro',
currentTier: userTier,
feature: featureKey,
featureName: config?.name || null,
upgradePrompt: config?.upgradePrompt || '...',
});
}
```
**Data Migration:**
```sql
-- Reset scanForMaintenance for free tier users
UPDATE documents d
SET scan_for_maintenance = false
FROM user_profiles u
WHERE d.user_id = u.auth0_sub
AND u.subscription_tier = 'free'
AND d.scan_for_maintenance = true;
```
### Test Results
```
PASS documents.controller.tier.test.ts (8 tests)
- allows free user to create document without scanForMaintenance
- blocks free user from using scanForMaintenance=true
- allows pro user to use scanForMaintenance=true
- allows enterprise user to use scanForMaintenance=true
- defaults to free tier when userContext is missing
- allows free user to update document without scanForMaintenance
- blocks free user from setting scanForMaintenance=true on update
- allows pro user to set scanForMaintenance=true on update
```
### Combined Test Summary (All Tier Tests)
```
Test Suites: 3 passed, 3 total
Tests: 30 passed, 30 total
- feature-tiers.test.ts: 14 tests
- tier-guard.plugin.test.ts: 8 tests
- documents.controller.tier.test.ts: 8 tests
```
### Acceptance Criteria
- [x] Free users cannot set scanForMaintenance=true
- [x] Pro/Enterprise users can set scanForMaintenance=true
- [x] 403 response matches structured error format
- [x] Data migration ready for deployment
- [x] Unit tests pass
---
**Proceeding to M5: Frontend Tier Access Hook**
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Implement a system to gate features and functions behind user tiers (Free, Pro, Enterprise). This provides the foundation for monetization and premium feature differentiation.
User Tiers
freeproenterpriseRequirements
Database
tiercolumn touserstable if not present (enum:free,pro,enterprise, default:free)Backend - Feature Registry
backend/src/config/feature-tiers.ts- hardcoded feature-to-tier mappingdocument.scanMaintenanceSchedule)Example structure:
Backend - Tier Enforcement
canAccessFeature(userTier: Tier, featureKey: string): booleangetRequiredTier(featureKey: string): TiergetTierLevel(tier: Tier): number(for comparison: free=0, pro=1, enterprise=2)Frontend - Tier Context
/api/auth/me)useTierAccesshook:hasAccess(featureKey: string): booleancheckAccess(featureKey: string): { allowed: boolean; requiredTier?: Tier }Frontend - Upgrade Dialog
UpgradeRequiredDialogcomponentfeatureKey,open,onCloseAdmin UI Integration
Initial Feature Gate
Technical Notes
feature-tiers.tsuseTierAccesshookenterprise>pro>free(higher tiers inherit all lower tier features)Acceptance Criteria
Out of Scope (Future Issues)
Implementation Plan - User Tier-Based Feature Gating
Analysis Summary
Codebase Analysis Complete. Key findings:
subscription_tiercolumnuser_profilestable (migration 002)SubscriptionTiertypeAdminUsersPage.tsxdropdown worksscanForMaintenancecolumndocumentstable (migration 002)Files to Create (4):
backend/src/config/feature-tiers.tsbackend/src/core/plugins/tier-guard.plugin.tsfrontend/src/core/hooks/useTierAccess.tsfrontend/src/shared-minimal/components/UpgradeRequiredDialog.tsxFiles to Modify (4):
backend/src/core/plugins/auth.plugin.ts(add tier to userContext)backend/src/features/documents/domain/documents.service.ts(validate tier)frontend/src/features/documents/components/DocumentForm.tsx(gate checkbox)Milestone 1: Backend Feature Registry and Tier Service
Goal: Create centralized feature-to-tier configuration and utility functions.
Files:
backend/src/config/feature-tiers.tsImplementation:
Tests:
feature-tiers.spec.ts- Unit tests for tier comparison logicAcceptance:
Milestone 2: Backend Auth Context Extension
Goal: Add
subscriptionTierto request.userContext for route-level checks.Files:
backend/src/core/plugins/auth.plugin.tsChanges at line ~208:
Type augmentation update:
Acceptance:
Milestone 3: Backend Tier Enforcement Middleware
Goal: Create reusable middleware for route-level tier checks.
Files:
backend/src/core/plugins/tier-guard.plugin.tsbackend/src/app.tsImplementation Pattern (following admin-guard.plugin.ts):
Acceptance:
Milestone 4: Backend Documents Tier Validation
Goal: Gate
scanForMaintenancefeature at API level.Files:
backend/src/features/documents/domain/documents.service.tsbackend/src/features/documents/api/documents.controller.tsService validation:
Tests:
Acceptance:
Milestone 5: Frontend Tier Access Hook
Goal: Create React hook for checking feature access.
Files:
frontend/src/core/hooks/useTierAccess.tsfrontend/src/core/hooks/index.tsImplementation (following useAdminAccess pattern):
Acceptance:
Milestone 6: Frontend Upgrade Dialog Component
Goal: Create reusable upgrade prompt dialog.
Files:
frontend/src/shared-minimal/components/UpgradeRequiredDialog.tsxfrontend/src/shared-minimal/components/index.tsProps:
Implementation (mobile + desktop responsive):
Acceptance:
Milestone 7: Frontend Document Form Gating
Goal: Gate scanForMaintenance checkbox in document upload.
Files:
frontend/src/features/documents/components/DocumentForm.tsxImplementation:
Acceptance:
Milestone 8: Testing and Documentation
Goal: Comprehensive test coverage and documentation.
Tests:
feature-tiers.spec.tstier-guard.plugin.spec.tsdocuments.service.spec.tsuseTierAccess.spec.tsxUpgradeRequiredDialog.spec.tsxDocumentation Updates:
backend/src/config/README.md- Document feature-tiers configdocs/FEATURES.md- Document tier system architectureAcceptance:
Dependencies Between Milestones
Recommended Order: M1 -> M2 -> M3 -> M4 -> M5 -> M6 -> M7 -> M8
Risk Assessment
Out of Scope (per issue requirements)
Ready for review. Please provide feedback on this plan before implementation begins.
Plan Review Cycle Complete
Review Summary
Blocking Issues (Must Fix Before Implementation)
1. Incorrect File Paths (TW)
backend/src/config/feature-tiers.tsbackend/src/core/config/feature-tiers.tsbackend/src/config/README.mdbackend/src/core/config/README.md2. Missing Index Files (TW)
frontend/src/core/hooks/index.ts- does not existfrontend/src/shared-minimal/components/index.ts- does not existDecision needed: Create these index files or use direct imports?
3. TypeScript Interface Update Required (QR Code)
The
FastifyRequest.userContextinterface atauth.plugin.ts:49-60must be extended:4. ForbiddenError Class Does Not Exist (QR Code)
Plan references
throw new ForbiddenError({...})but no such class exists.Decision needed:
core/errors/ForbiddenError.tsShould Fix (Before Milestone Completion)
5. Guard Pattern Inconsistency (QR Code)
requireAdminuses direct decoration; plan showsrequireTieras factory function. Should be consistent.Recommendation: Follow
requireAdminpattern (direct decoration with parameter object).6. Config Drift Strategy (QR Completeness)
Plan mentions risk but mitigation is vague.
Decision needed:
/api/config/feature-tiersendpoint7. Data Migration Decision (QR Completeness)
Existing free users may have
scanForMaintenance=true.Decision needed: Grandfather existing data OR reset to false?
8. Missing Decision Log (QR Completeness)
Add section documenting:
Suggestions (Nice to Have)
__tests__/or alongside source)Action Items
Before Implementation Begins:
Ready to start M1 after decisions are made.
Decision Log
Decisions made on blocking issues:
backend/src/core/config/frontend/src/core/hooks/index.tsandfrontend/src/shared-minimal/components/index.tsrequireAdminandrequireTierare distinct/api/config/feature-tiersendpointscanForMaintenance=truetofalsefor free usersUpdated Plan Amendments
M1 Update - Add API endpoint:
backend/src/core/config/feature-tiers.tsGET /api/config/feature-tiersendpoint returning feature configM4 Update - Controller pattern:
M5 Update - Fetch from API:
New: Data Migration (add to M4):
All blocking issues resolved. Ready to begin implementation.
Milestone 1 Complete: Backend Feature Registry and Tier Service
Files Created
backend/src/core/config/feature-tiers.tsbackend/src/core/config/config.routes.tsbackend/src/core/config/tests/feature-tiers.test.tsFiles Modified
backend/src/app.tsAPI Endpoint
Exported Utilities
getTierLevel(tier)- Get numeric level (0/1/2)canAccessFeature(userTier, featureKey)- Check access permissiongetRequiredTier(featureKey)- Get minimum tier for featuregetFeatureConfig(featureKey)- Get full feature configgetAllFeatureConfigs()- Get all configs (for API)Test Results
Acceptance Criteria
Proceeding to M2: Backend Auth Context Extension
Milestone 2 Complete: Backend Auth Context Extension
Files Modified
backend/src/core/plugins/auth.plugin.tsChanges Made
Type Check
Acceptance Criteria
Proceeding to M3: Backend Tier Enforcement Middleware
Milestone 3 Complete: Backend Tier Enforcement Middleware
Files Created
backend/src/core/plugins/tier-guard.plugin.tsbackend/src/core/plugins/tests/tier-guard.plugin.test.tsFiles Modified
backend/src/app.tsUsage
403 Error Response
Test Results
Acceptance Criteria
Proceeding to M4: Backend Documents Tier Validation
Milestone 4 Complete: Backend Documents Tier Validation
Files Created
backend/src/features/documents/migrations/003_reset_scan_for_maintenance_free_users.sqlbackend/src/features/documents/tests/unit/documents.controller.tier.test.tsFiles Modified
backend/src/features/documents/api/documents.controller.tsImplementation Summary
Controller Tier Validation (lines 88-106, 134-153):
Data Migration:
Test Results
Combined Test Summary (All Tier Tests)
Acceptance Criteria
Proceeding to M5: Frontend Tier Access Hook
Milestone 5 Complete: Frontend Tier Access Hook
Files Created
frontend/src/core/hooks/useTierAccess.tsfrontend/src/core/hooks/index.tsFiles Modified
frontend/src/features/settings/types/profile.types.tsSubscriptionTiertype andsubscriptionTierfield toUserProfileHook API
Implementation Details
user-profilequery key with 5-minute stale time/api/config/feature-tierswith 30-minute stale timeallowed: truefor safetyType Check
Acceptance Criteria
Proceeding to M6: Frontend Upgrade Dialog Component
Milestone 6 Complete: Frontend Upgrade Dialog Component
Files Created
frontend/src/shared-minimal/components/UpgradeRequiredDialog.tsxfrontend/src/shared-minimal/components/index.tsComponent API
Features
Responsive Design:
< 600px)Tier Visualization:
Dynamic Content:
Actions:
Type Check
Acceptance Criteria
Proceeding to M7: Frontend Document Form Gating
Milestone 7 Complete: Frontend Document Form Gating
Files Modified
frontend/src/features/documents/components/DocumentForm.tsxImplementation Details
Imports added:
Hook usage:
UI Behavior:
Visual Comparison
Free User:
Pro/Enterprise User:
Type Check
Acceptance Criteria
Implementation Summary
All milestones for Issue #8 (User Tier-Based Feature Gating) have been completed:
Files Created (9)
backend/src/core/config/feature-tiers.tsbackend/src/core/config/config.routes.tsbackend/src/core/config/tests/feature-tiers.test.tsbackend/src/core/plugins/tier-guard.plugin.tsbackend/src/core/plugins/tests/tier-guard.plugin.test.tsbackend/src/features/documents/migrations/003_reset_scan_for_maintenance_free_users.sqlbackend/src/features/documents/tests/unit/documents.controller.tier.test.tsfrontend/src/core/hooks/useTierAccess.tsfrontend/src/core/hooks/index.tsfrontend/src/shared-minimal/components/UpgradeRequiredDialog.tsxfrontend/src/shared-minimal/components/index.tsFiles Modified (4)
backend/src/app.tsbackend/src/core/plugins/auth.plugin.tsbackend/src/features/documents/api/documents.controller.tsfrontend/src/features/documents/components/DocumentForm.tsxfrontend/src/features/settings/types/profile.types.tsTest Summary
Remaining for M8 (Testing and Documentation)
Ready for review and merge.
Milestone 8 Complete: Documentation
Files Created
docs/TIER-GATING.mdDocumentation Contents
Pull Request Created
PR #18: feat: Implement user tier-based feature gating system
Implementation Complete
All 8 milestones have been completed:
Ready for review and merge.