Skip to content

add-enterprise-feature

Access: /template add-enterprise-feature or /t add-enterprise-feature

Creates advanced enterprise-grade features for your MakerKit application, including SSO, audit logs, advanced permissions, and compliance tools.

What It Does

The add-enterprise-feature command helps you create:

  • Single Sign-On (SSO) with SAML/OAuth
  • Advanced audit logging and compliance
  • Role-based access control (RBAC)
  • Data export and retention policies
  • API rate limiting and quotas
  • Multi-region deployment support
  • Advanced security features

Usage

bash
/template add-enterprise-feature "Description"
# or
/t add-enterprise-feature "Description"

When prompted, specify:

  • Feature type (SSO, audit logs, RBAC, etc.)
  • Compliance requirements (SOC2, GDPR, HIPAA)
  • Security level needed
  • Integration requirements

Prerequisites

  • A MakerKit project with teams functionality
  • Understanding of enterprise requirements
  • Commercial MakerKit license from MakerKit

What Gets Created

1. Single Sign-On (SSO)

SAML 2.0 implementation:

typescript
// lib/sso/saml-provider.ts
import { SAML } from '@node-saml/node-saml';
import { createHash } from 'crypto';

export class SAMLProvider {
  private saml: SAML;
  
  constructor(config: SAMLConfig) {
    this.saml = new SAML({
      callbackUrl: `${process.env.NEXT_PUBLIC_APP_URL}/api/auth/saml/callback`,
      entryPoint: config.entryPoint,
      issuer: config.issuer,
      cert: config.certificate,
      privateKey: process.env.SAML_PRIVATE_KEY,
      identifierFormat: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
      signatureAlgorithm: 'sha256',
      digestAlgorithm: 'sha256',
    });
  }
  
  async generateLoginUrl(accountId: string): Promise<string> {
    const request = await this.saml.createLoginRequestAsync(
      accountId,
      { additionalParams: { accountId } }
    );
    
    return request;
  }
  
  async validateResponse(samlResponse: string): Promise<SSOUser> {
    const profile = await this.saml.validatePostResponseAsync(samlResponse);
    
    if (!profile) {
      throw new Error('Invalid SAML response');
    }
    
    return {
      id: profile.nameID,
      email: profile.email || profile.mail,
      firstName: profile.givenName,
      lastName: profile.sn,
      attributes: profile.attributes,
    };
  }
}

// SSO configuration table
create table public.sso_configurations (
  id uuid default gen_random_uuid() primary key,
  account_id uuid not null references public.accounts(id) on delete cascade,
  provider text not null check (provider in ('saml', 'oidc')),
  enabled boolean default false,
  metadata jsonb not null,
  created_at timestamptz default now(),
  updated_at timestamptz default now(),
  unique(account_id, provider)
);

-- SSO domains for auto-detection
create table public.sso_domains (
  id uuid default gen_random_uuid() primary key,
  account_id uuid not null references public.accounts(id) on delete cascade,
  domain text not null unique,
  verified boolean default false,
  verification_token text,
  created_at timestamptz default now()
);

2. Advanced Audit Logging

Comprehensive audit trail:

typescript
// lib/audit/audit-logger.ts
export interface AuditEvent {
  actor: {
    id: string;
    type: 'user' | 'system' | 'api';
    email?: string;
    ip?: string;
    userAgent?: string;
  };
  action: string;
  resource: {
    type: string;
    id: string;
    name?: string;
  };
  changes?: {
    before: any;
    after: any;
  };
  metadata?: Record<string, any>;
  timestamp: Date;
}

export class AuditLogger {
  private queue: AuditEvent[] = [];
  private flushInterval: NodeJS.Timer;
  
  constructor() {
    // Batch write events every 5 seconds
    this.flushInterval = setInterval(() => this.flush(), 5000);
  }
  
  async log(event: AuditEvent) {
    // Add context
    const enrichedEvent = {
      ...event,
      id: generateId(),
      timestamp: new Date(),
      environment: process.env.NODE_ENV,
      version: process.env.APP_VERSION,
    };
    
    this.queue.push(enrichedEvent);
    
    // Immediate flush for critical events
    if (this.isCriticalEvent(event)) {
      await this.flush();
    }
  }
  
  private async flush() {
    if (this.queue.length === 0) return;
    
    const events = [...this.queue];
    this.queue = [];
    
    try {
      await this.writeToDatabase(events);
      await this.writeToSIEM(events);
    } catch (error) {
      // Re-queue failed events
      this.queue.unshift(...events);
      console.error('Audit log flush failed:', error);
    }
  }
  
  private async writeToDatabase(events: AuditEvent[]) {
    const { error } = await supabase
      .from('audit_logs')
      .insert(events.map(event => ({
        actor_id: event.actor.id,
        actor_type: event.actor.type,
        actor_email: event.actor.email,
        action: event.action,
        resource_type: event.resource.type,
        resource_id: event.resource.id,
        resource_name: event.resource.name,
        changes: event.changes,
        metadata: event.metadata,
        ip_address: event.actor.ip,
        user_agent: event.actor.userAgent,
        timestamp: event.timestamp,
      })));
    
    if (error) throw error;
  }
  
  private async writeToSIEM(events: AuditEvent[]) {
    // Send to external SIEM system
    if (process.env.SIEM_ENDPOINT) {
      await fetch(process.env.SIEM_ENDPOINT, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.SIEM_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ events }),
      });
    }
  }
}

// Audit log viewer component
export function AuditLogViewer({ accountId }: { accountId: string }) {
  const { data: logs, isLoading } = useAuditLogs(accountId);
  
  return (
    <div className="space-y-4">
      <div className="flex justify-between items-center">
        <h2 className="text-xl font-semibold">Audit Log</h2>
        <Button onClick={exportAuditLogs}>
          Export CSV
        </Button>
      </div>
      
      <DataTable
        columns={auditLogColumns}
        data={logs || []}
        loading={isLoading}
        searchKey="action"
        filters={[
          {
            column: 'actor_type',
            title: 'Actor Type',
            options: ['user', 'system', 'api'],
          },
          {
            column: 'resource_type',
            title: 'Resource',
            options: ['user', 'team', 'project', 'billing'],
          },
        ]}
      />
    </div>
  );
}

3. Role-Based Access Control

Granular permissions system:

typescript
// lib/rbac/permissions.ts
export const PERMISSIONS = {
  // User management
  'users:read': 'View users',
  'users:write': 'Create and edit users',
  'users:delete': 'Delete users',
  'users:impersonate': 'Impersonate users',
  
  // Team management
  'teams:read': 'View team details',
  'teams:write': 'Edit team settings',
  'teams:delete': 'Delete team',
  'teams:manage_members': 'Add/remove team members',
  'teams:manage_roles': 'Manage team roles',
  
  // Billing
  'billing:read': 'View billing information',
  'billing:write': 'Update payment methods',
  'billing:manage_subscription': 'Change subscription plans',
  
  // Security
  'security:manage_sso': 'Configure SSO',
  'security:manage_2fa': 'Enforce 2FA policies',
  'security:view_audit_logs': 'View audit logs',
  'security:manage_api_keys': 'Create/revoke API keys',
  
  // Data
  'data:export': 'Export data',
  'data:delete': 'Delete data',
  'data:retention': 'Manage data retention',
} as const;

// Custom roles
export interface Role {
  id: string;
  name: string;
  description: string;
  permissions: string[];
  isSystem: boolean;
}

// Database schema
create table public.custom_roles (
  id uuid default gen_random_uuid() primary key,
  account_id uuid not null references public.accounts(id) on delete cascade,
  name text not null,
  description text,
  permissions text[] not null default '{}',
  is_system boolean default false,
  created_at timestamptz default now(),
  updated_at timestamptz default now(),
  unique(account_id, name)
);

create table public.user_custom_roles (
  user_id uuid not null references auth.users(id) on delete cascade,
  account_id uuid not null references public.accounts(id) on delete cascade,
  role_id uuid not null references public.custom_roles(id) on delete cascade,
  granted_by uuid references auth.users(id),
  granted_at timestamptz default now(),
  primary key (user_id, account_id, role_id)
);

// Permission checking
export async function checkPermission(
  userId: string,
  accountId: string,
  permission: keyof typeof PERMISSIONS
): Promise<boolean> {
  // Check system roles first
  const systemRole = await getUserSystemRole(userId, accountId);
  if (systemRole === 'owner') return true;
  
  // Check custom roles
  const { data: customRoles } = await supabase
    .from('user_custom_roles')
    .select('role:custom_roles(permissions)')
    .eq('user_id', userId)
    .eq('account_id', accountId);
  
  const allPermissions = customRoles?.flatMap(r => r.role.permissions) || [];
  return allPermissions.includes(permission);
}

// Permission guard component
export function RequirePermission({
  permission,
  fallback = <AccessDenied />,
  children,
}: {
  permission: keyof typeof PERMISSIONS;
  fallback?: React.ReactNode;
  children: React.ReactNode;
}) {
  const { user } = useUser();
  const { account } = useAccount();
  const { data: hasPermission } = usePermission(permission);
  
  if (!hasPermission) {
    return <>{fallback}</>;
  }
  
  return <>{children}</>;
}

4. Data Export & Compliance

GDPR and compliance tools:

typescript
// lib/compliance/data-export.ts
export class DataExporter {
  async exportUserData(userId: string): Promise<ExportBundle> {
    const bundle: ExportBundle = {
      metadata: {
        userId,
        exportDate: new Date(),
        version: '1.0',
      },
      data: {},
    };
    
    // Export from all tables
    const tables = [
      'users',
      'accounts_account_members',
      'projects',
      'documents',
      'audit_logs',
      'subscriptions',
    ];
    
    for (const table of tables) {
      bundle.data[table] = await this.exportTableData(table, userId);
    }
    
    // Export from external services
    bundle.data.stripe = await this.exportStripeData(userId);
    bundle.data.emails = await this.exportEmailData(userId);
    
    // Generate signed archive
    const archive = await this.createSecureArchive(bundle);
    
    // Log export event
    await auditLogger.log({
      actor: { id: userId, type: 'user' },
      action: 'data.exported',
      resource: { type: 'user', id: userId },
      metadata: { tables: Object.keys(bundle.data) },
    });
    
    return archive;
  }
  
  private async createSecureArchive(bundle: ExportBundle): Promise<Buffer> {
    const json = JSON.stringify(bundle, null, 2);
    const encrypted = await encrypt(json, process.env.EXPORT_ENCRYPTION_KEY!);
    
    const zip = new AdmZip();
    zip.addFile('data.json.enc', Buffer.from(encrypted));
    zip.addFile('README.txt', Buffer.from(
      'This is your personal data export.\n' +
      'The data.json.enc file is encrypted.\n' +
      'Contact support for decryption assistance.'
    ));
    
    return zip.toBuffer();
  }
}

// Data retention policies
export async function applyRetentionPolicies() {
  const policies = await getRetentionPolicies();
  
  for (const policy of policies) {
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - policy.retentionDays);
    
    if (policy.action === 'delete') {
      await supabase
        .from(policy.table)
        .delete()
        .lt('created_at', cutoffDate.toISOString());
    } else if (policy.action === 'anonymize') {
      await anonymizeOldData(policy.table, cutoffDate);
    }
  }
}

5. API Rate Limiting

Enterprise API management:

typescript
// lib/api/rate-limiter.ts
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';

// Configure rate limits by plan
const RATE_LIMITS = {
  free: { requests: 100, window: '1h' },
  pro: { requests: 1000, window: '1h' },
  enterprise: { requests: 10000, window: '1h' },
  custom: { requests: -1, window: '1h' }, // Unlimited
};

export function createRateLimiter(tier: keyof typeof RATE_LIMITS) {
  const limit = RATE_LIMITS[tier];
  
  if (limit.requests === -1) {
    return { limit: async () => ({ success: true }) };
  }
  
  return new Ratelimit({
    redis: Redis.fromEnv(),
    limiter: Ratelimit.slidingWindow(limit.requests, limit.window),
    analytics: true,
  });
}

// API middleware
export async function rateLimitMiddleware(
  request: NextRequest,
  accountId: string
) {
  const account = await getAccount(accountId);
  const rateLimiter = createRateLimiter(account.plan);
  
  const identifier = `${accountId}:${request.ip}`;
  const { success, limit, reset, remaining } = await rateLimiter.limit(
    identifier
  );
  
  // Add rate limit headers
  const response = NextResponse.next();
  response.headers.set('X-RateLimit-Limit', limit.toString());
  response.headers.set('X-RateLimit-Remaining', remaining.toString());
  response.headers.set('X-RateLimit-Reset', new Date(reset).toISOString());
  
  if (!success) {
    return new NextResponse('Rate limit exceeded', {
      status: 429,
      headers: response.headers,
    });
  }
  
  return response;
}

// Usage analytics
export async function getAPIUsageAnalytics(accountId: string) {
  const analytics = await redis.get(`analytics:${accountId}`);
  
  return {
    totalRequests: analytics?.totalRequests || 0,
    requestsByEndpoint: analytics?.endpoints || {},
    requestsByDay: analytics?.daily || {},
    averageLatency: analytics?.avgLatency || 0,
    errorRate: analytics?.errorRate || 0,
  };
}

6. Multi-Region Support

Deploy across regions:

typescript
// lib/infrastructure/multi-region.ts
export const REGIONS = {
  'us-east-1': { name: 'US East', endpoint: 'https://us-east.api.app.com' },
  'eu-west-1': { name: 'EU West', endpoint: 'https://eu-west.api.app.com' },
  'ap-southeast-1': { name: 'Asia Pacific', endpoint: 'https://ap.api.app.com' },
};

// Data residency configuration
create table public.data_residency (
  account_id uuid primary key references public.accounts(id) on delete cascade,
  primary_region text not null,
  allowed_regions text[] not null default '{}',
  data_processing_agreement boolean default false,
  created_at timestamptz default now()
);

// Region-aware database client
export function getRegionalClient(accountId: string) {
  const residency = await getDataResidency(accountId);
  const region = residency?.primary_region || 'us-east-1';
  
  return createClient(
    process.env[`SUPABASE_URL_${region.toUpperCase()}`],
    process.env.SUPABASE_SERVICE_ROLE_KEY,
    {
      global: {
        headers: {
          'x-region': region,
        },
      },
    }
  );
}

7. Advanced Security Features

Enterprise security controls:

typescript
// lib/security/advanced-features.ts

// IP Allowlisting
export async function checkIPAllowlist(
  accountId: string,
  ipAddress: string
): Promise<boolean> {
  const { data: allowlist } = await supabase
    .from('ip_allowlists')
    .select('cidr_blocks')
    .eq('account_id', accountId)
    .eq('enabled', true);
  
  if (!allowlist || allowlist.length === 0) {
    return true; // No restrictions
  }
  
  return allowlist.some(entry => 
    isIPInCIDR(ipAddress, entry.cidr_blocks)
  );
}

// Session management
export async function enforceSessionPolicies(
  userId: string,
  accountId: string
) {
  const policies = await getSecurityPolicies(accountId);
  
  if (policies.maxConcurrentSessions) {
    const sessions = await getActiveSessions(userId);
    
    if (sessions.length >= policies.maxConcurrentSessions) {
      // Terminate oldest session
      await terminateSession(sessions[0].id);
    }
  }
  
  if (policies.sessionTimeout) {
    // Set session expiry
    await setSessionExpiry(userId, policies.sessionTimeout);
  }
}

// Anomaly detection
export async function detectAnomalies(event: SecurityEvent) {
  const anomalies = [];
  
  // Unusual login location
  const lastLocation = await getLastLoginLocation(event.userId);
  if (lastLocation && getDistance(lastLocation, event.location) > 1000) {
    anomalies.push({
      type: 'unusual_location',
      severity: 'medium',
      description: 'Login from unusual location',
    });
  }
  
  // Unusual time
  const usualHours = await getUsualActiveHours(event.userId);
  if (!isWithinHours(event.timestamp, usualHours)) {
    anomalies.push({
      type: 'unusual_time',
      severity: 'low',
      description: 'Activity outside normal hours',
    });
  }
  
  // Rapid API calls
  const recentCalls = await getRecentAPICalls(event.userId, '5m');
  if (recentCalls > 100) {
    anomalies.push({
      type: 'rapid_api_calls',
      severity: 'high',
      description: 'Abnormally high API usage',
    });
  }
  
  if (anomalies.length > 0) {
    await notifySecurityTeam(event, anomalies);
  }
  
  return anomalies;
}

8. Enterprise Dashboard

Executive metrics and insights:

typescript
// app/enterprise/dashboard/page.tsx
export default function EnterpriseDashboard() {
  const metrics = useEnterpriseMetrics();
  
  return (
    <div className="space-y-6">
      <div className="grid grid-cols-4 gap-4">
        <MetricCard
          title="Total Users"
          value={metrics.totalUsers}
          change={metrics.userGrowth}
          icon={<Users />}
        />
        <MetricCard
          title="Active Teams"
          value={metrics.activeTeams}
          change={metrics.teamGrowth}
          icon={<Building />}
        />
        <MetricCard
          title="API Usage"
          value={`${metrics.apiUsage}M`}
          change={metrics.apiGrowth}
          icon={<Activity />}
        />
        <MetricCard
          title="Uptime"
          value="99.99%"
          change={0.01}
          icon={<Shield />}
        />
      </div>
      
      <div className="grid grid-cols-2 gap-6">
        <ComplianceStatus />
        <SecurityOverview />
      </div>
      
      <div className="grid grid-cols-3 gap-6">
        <UsageByRegion />
        <TopAPIEndpoints />
        <AuditActivity />
      </div>
    </div>
  );
}

Compliance Certifications

Support for various standards:

  • SOC 2 Type II: Audit logging, access controls
  • GDPR: Data export, deletion, consent management
  • HIPAA: Encryption, access logs, BAA support
  • ISO 27001: Security controls, risk management
  • PCI DSS: Payment data isolation, encryption

License Requirement

Important: This command requires a commercial MakerKit license from https://makerkit.dev?atp=MqaGgc MakerKit is a premium SaaS starter kit and requires proper licensing for commercial use.

Built with ❤️ for the AI Coding community, by Praney Behl