feat: Implement user tier-based feature gating system (refs #8)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m35s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 27s
Deploy to Staging / Verify Staging (pull_request) Successful in 5s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 5s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m35s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 27s
Deploy to Staging / Verify Staging (pull_request) Successful in 5s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 5s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Add subscription tier system to gate features behind Free/Pro/Enterprise tiers. Backend: - Create feature-tiers.ts with FEATURE_TIERS config and utilities - Add /api/config/feature-tiers endpoint for frontend config fetch - Create requireTier middleware for route-level tier enforcement - Add subscriptionTier to request.userContext in auth plugin - Gate scanForMaintenance in documents controller (Pro+ required) - Add migration to reset scanForMaintenance for free users Frontend: - Create useTierAccess hook for tier checking - Create UpgradeRequiredDialog component (responsive) - Gate DocumentForm checkbox with lock icon for free users - Add SubscriptionTier type to profile.types.ts Documentation: - Add TIER-GATING.md with usage guide Tests: 30 passing (feature-tiers, tier-guard, controller) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import { logger } from '../logging/logger';
|
||||
import { UserProfileRepository } from '../../features/user-profile/data/user-profile.repository';
|
||||
import { pool } from '../config/database';
|
||||
import { auth0ManagementClient } from '../auth/auth0-management.client';
|
||||
import { SubscriptionTier } from '../../features/user-profile/domain/user-profile.types';
|
||||
|
||||
// Routes that don't require email verification
|
||||
const VERIFICATION_EXEMPT_ROUTES = [
|
||||
@@ -56,6 +57,7 @@ declare module 'fastify' {
|
||||
onboardingCompleted: boolean;
|
||||
isAdmin: boolean;
|
||||
adminRecord?: any;
|
||||
subscriptionTier: SubscriptionTier;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -129,6 +131,7 @@ const authPlugin: FastifyPluginAsync = async (fastify) => {
|
||||
let displayName: string | undefined;
|
||||
let emailVerified = false;
|
||||
let onboardingCompleted = false;
|
||||
let subscriptionTier: SubscriptionTier = 'free';
|
||||
|
||||
try {
|
||||
// If JWT doesn't have email, fetch from Auth0 Management API
|
||||
@@ -170,6 +173,7 @@ const authPlugin: FastifyPluginAsync = async (fastify) => {
|
||||
displayName = profile.displayName || undefined;
|
||||
emailVerified = profile.emailVerified;
|
||||
onboardingCompleted = profile.onboardingCompletedAt !== null;
|
||||
subscriptionTier = profile.subscriptionTier || 'free';
|
||||
|
||||
// Sync email verification status from Auth0 if needed
|
||||
if (!emailVerified) {
|
||||
@@ -208,6 +212,7 @@ const authPlugin: FastifyPluginAsync = async (fastify) => {
|
||||
emailVerified,
|
||||
onboardingCompleted,
|
||||
isAdmin: false, // Default to false; admin status checked by admin guard
|
||||
subscriptionTier,
|
||||
};
|
||||
|
||||
// Email verification guard - block unverified users from non-exempt routes
|
||||
|
||||
Reference in New Issue
Block a user