Organization Modules & Tier System
Organization Modules & Tier System
Overview
This feature implements a modular access control system for the CRM. Organizations can have different subscription tiers that determine which CRM modules they can access. Administrators can also customize module access on a per-organization basis.
Date Implemented
December 23, 2025
Subscription Tiers
| Tier | Default Modules | Description |
|---|---|---|
| Basic | Clients, Intake | Essential client management features |
| Standard | Clients, Intake, Resources, Referrals | Full CRM features with resource library |
| Premium | Clients, Intake, Resources, Referrals, Reports | Advanced features with analytics |
| Enterprise | Clients, Intake, Resources, Referrals, Reports | Full platform access with priority support |
Available Modules
| Module | Description | Route |
|---|---|---|
| Clients | Client and household management | /clients |
| Intake | Client intake forms and assessments | /intake |
| Resources | Resource library and program management | /resources |
| Referrals | Referral tracking and coordination | /referrals |
| Reports | Analytics and reporting dashboards | /access-crm/reports |
| Insights | Map-first analytics hub — resource coverage, demand, data quality (gated by Reports module) | /insights |
| Resource Navigator | Embedded Resource Navigator theme and messaging customization | /resource-navigator |
How It Works
1. Tier-Based Access (Default)
When an organization is created, it's assigned a tier. By default, the organization has access to all modules included in that tier.
2. Custom Module Overrides
Administrators can override the default modules for an organization by:
- Go to Admin Panel > Organizations
- Click "Modules" on any organization card
- Enable "Custom modules" checkbox
- Toggle individual modules on/off
- Save changes
3. Access Control Flow
### 4. Resource Navigator Module Activation
Resource Navigator customization is module-gated per organization:
1. Range Lab admin enables `chatbot` in **Admin Panel > Organizations > Modules**.
2. Org admins can then access `/resource-navigator`.
3. If disabled, org admins see a locked page; Range Lab admins can still access for setup/testing.
User Request → Middleware → Module Check → Page Access
↓
Profile Lookup
↓
Role Check
↓
If org-scoped user:
↓
Organization Module Check
↓
Allow/Deny Access
Database Schema
Organizations Table Updates
ALTER TABLE organizations
ADD COLUMN tier TEXT DEFAULT 'basic',
ADD COLUMN enabled_modules TEXT[] DEFAULT ARRAY[]::TEXT[];
-- Constraint for valid tiers
ALTER TABLE organizations
ADD CONSTRAINT organizations_tier_check
CHECK (tier IN ('basic', 'standard', 'premium', 'enterprise'));
Database Function
CREATE OR REPLACE FUNCTION has_module_access(
p_org_id UUID,
p_module_name TEXT
) RETURNS BOOLEAN
Key Files
Configuration
lib/modules.ts- Module and tier definitions, helper functions
Server Helpers
lib/supabase-server.ts- Server-side module access checks
API
app/api/user/modules/route.ts- Returns user's enabled modules
Components
app/components/ModuleContext.tsx- React context for module accessapp/components/CRMSidebar.tsx- Conditionally shows modules in navigation
Middleware
middleware.ts- Route-level module access protection
Admin Interface
app/(crm)/admin/components/OrganizationModulesModal.tsx- Module management UIapp/(crm)/admin/organizations/AdminOrganizationsClient.tsx- Organization list with tier badges
Access Control Bypass
The following users bypass module checks:
- Admin users (
role === 'admin') - System-wide staff (
role === 'staff' && !org_id)
Usage Examples
Check Module Access in Server Components
import { canAccessModule } from '@/lib/supabase-server'
export default async function ResourcesPage() {
const hasAccess = await canAccessModule('resources')
if (!hasAccess) {
redirect('/unauthorized?reason=module_not_enabled')
}
// ... render page
}
Check Module Access in Client Components
import { useModules } from '@/app/components/ModuleContext'
function MyComponent() {
const { hasModule, isLoading } = useModules()
if (isLoading) return <Loading />
if (!hasModule('resources')) {
return <UpgradePrompt />
}
return <ResourcesList />
}
Get Enabled Modules
import { getEnabledModules } from '@/lib/modules'
// Get modules for an organization
const modules = getEnabledModules(org.tier, org.enabled_modules)
// Returns: ['clients', 'intake', 'resources', 'referrals']
Migration Guide
To apply this feature to an existing database:
- Run the migration:
psql -U your_user -d your_database -f database/migrations/DATABASE_MIGRATION_ORGANIZATION_MODULES.sql
- Existing organizations will default to 'basic' tier
- Update organization tiers as needed through Admin Panel
Security Considerations
-
Defense in Depth: Module access is checked at multiple layers:
- Middleware (route-level)
- Page components (server-side)
- Navigation (client-side, UI only)
-
Server-Side Authority: The client-side ModuleContext is for UI purposes only. Actual access control is enforced server-side.
-
API Protection: API routes should also check module access for org-scoped users.
Future Enhancements
- Module usage analytics
- Module trial periods
- Automatic tier upgrades based on usage
- Module feature flags within modules
- Billing integration for tier changes
Use links in each imported doc to open its source.