Skip to main content

AdminHQ (Core) Complete Schema Documentation

Overview

The AdminHQ Core module provides the foundational infrastructure for the Tellus EHS platform, including multi-tenant company management, user authentication, role-based access control (RBAC), subscription management, and onboarding workflows.

Table Naming Convention

All tables follow a consistent naming convention:

  • core_config_* : Configuration tables (system-wide, read-mostly, seeded in migrations)
  • core_data_* : Data tables (tenant-specific, frequently written, user-generated)
  • core_junction_* : Junction tables (many-to-many relationships, association tables)
  • core_module_* : Module-specific tables

Key Design Principles

  • Multi-Tenancy: Complete data isolation via company_id foreign keys
  • RBAC: Hierarchical role-based access control with system templates and company customization
  • Subscription Model: Versioned plans with entitlements and company-level overrides
  • Module System: Industry-specific module availability with feature capabilities
  • Audit Trails: Complete logging of authentication and configuration changes

Architecture Overview

Multi-Tenant Architecture

┌─────────────────────────────────────────────────────────────────────────────┐
│ PLATFORM CONFIGURATION │
│ (System-wide, seeded in migrations) │
├─────────────────────────────────────────────────────────────────────────────┤
│ Plans & Entitlements │ Modules & Features │ System Roles │
│ ├─ core_config_plans │ ├─ core_config_modules│ ├─ core_config_system_ │
│ ├─ core_config_plan_ │ ├─ core_config_module_│ │ roles │
│ │ versions │ │ features │ └─ core_config_ │
│ ├─ core_config_plan_ │ └─ core_config_ │ permissions │
│ │ entitlements │ feature_ │ │
│ └─ core_config_ │ capabilities │ │
│ entitlement_defs │ │ │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│ COMPANY (TENANT) │
│ (Isolated per company_id) │
├─────────────────────────────────────────────────────────────────────────────┤
│ core_data_companies │
│ │ │
│ ├─► Sites (core_data_sites) │
│ │ └─► Locations (core_data_site_locations) │
│ │ │
│ ├─► Subscriptions (core_data_company_subscriptions) │
│ │ └─► Plan Version (core_config_plan_versions) │
│ │ │
│ ├─► Enabled Modules (core_junction_company_enabled_modules) │
│ │ │
│ ├─► Company Roles (core_data_company_roles) │
│ │ └─► Role Permissions (core_junction_company_role_permissions) │
│ │ │
│ ├─► User Memberships (core_junction_company_user_memberships) │
│ │ └─► User Roles (core_junction_company_user_roles) │
│ │ │
│ ├─► Invites (core_data_invites) │
│ │ │
│ └─► Onboarding Checklist (core_data_onboarding_checklist) │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│ USERS │
│ (Can belong to multiple companies) │
├─────────────────────────────────────────────────────────────────────────────┤
│ core_data_users │
│ │ │
│ ├─► Login Audit (core_data_user_login_audit) │
│ ├─► Sessions (core_data_user_sessions) │
│ └─► Company Memberships (core_junction_company_user_memberships) │
│ └─► Company Roles (core_junction_company_user_roles) │
└─────────────────────────────────────────────────────────────────────────────┘

RBAC Architecture

┌──────────────────────────────────────────────────────────────────────────┐
│ SYSTEM ROLE TEMPLATES │
│ (Platform-wide, seeded data) │
├──────────────────────────────────────────────────────────────────────────┤
│ SystemRole (ADMIN, MANAGER, COORDINATOR, EMPLOYEE, CONSULTANT) │
│ │ │
│ └─► SystemRolePermissions ──► Permissions │
│ (module:feature:action) │
└──────────────────────────────────────────────────────────────────────────┘

▼ (template for)
┌──────────────────────────────────────────────────────────────────────────┐
│ COMPANY-SPECIFIC ROLES │
│ (Customizable per company) │
├──────────────────────────────────────────────────────────────────────────┤
│ CompanyRole (can rename, add/remove permissions) │
│ │ │
│ ├─► base_system_role_id (optional template reference) │
│ │ │
│ └─► CompanyRolePermissions ──► Permissions │
│ │
│ Example: Company renames "MANAGER" to "Site Supervisor" │
│ and adds custom permissions │
└──────────────────────────────────────────────────────────────────────────┘

▼ (assigned to)
┌──────────────────────────────────────────────────────────────────────────┐
│ USER ROLE ASSIGNMENTS │
│ (Per user, per company, optional site scope) │
├──────────────────────────────────────────────────────────────────────────┤
│ CompanyUserRole │
│ │ │
│ ├─► company_id │
│ ├─► user_id │
│ ├─► company_role_id │
│ └─► site_id (optional - for site-scoped roles) │
│ │
│ Example: User is "Site Supervisor" only at "Downtown Warehouse" │
└──────────────────────────────────────────────────────────────────────────┘

Part 1: User & Authentication System

Table 1: core_data_users

Purpose: User identity and authentication management.

Key Features:

  • Supabase authentication integration
  • Multi-company user support
  • Last company tracking for UX improvement
  • Active/inactive status management

Important Columns:

ColumnTypeConstraintsDescription
user_idUUIDPKPrimary identifier
supabase_uidUUIDUNIQUESupabase authentication ID
emailString(255)UNIQUE, indexedUser email address
full_nameString(255)User's full name
phone_numberString(50)Contact phone
avatar_urlString(500)User profile picture URL
is_activeBooleandefault=trueActive status flag
last_company_idUUIDFKLast company user accessed
created_atTimestampAccount creation time
updated_atTimestampLast update time

Indexes:

  • B-tree index on email
  • Unique constraint on supabase_uid

Relationships:

  • One-to-many: login_audits → UserLoginAudit
  • One-to-many: sessions → UserSession
  • One-to-many: company_memberships → CompanyUserMembership
  • Many-to-one: last_company → Company

Use Cases:

  • User account creation and management
  • Supabase authentication integration
  • Multi-company user support (consultants)
  • Last company tracking for quick access

Table 2: core_data_user_login_audit

Purpose: Audit trail for authentication events.

Key Features:

  • Complete login history
  • IP address and device tracking
  • Geographic metadata via JSONB
  • Authentication method tracking

Important Columns:

ColumnTypeConstraintsDescription
audit_idUUIDPKLog entry identifier
user_idUUIDFK, indexedUser who logged in
login_atDateTimeindexedTimestamp of login
ip_addressINETClient IP address
user_agentTextBrowser/device information
device_typeString(50)Device classification
methodString(50)Auth method: password, otp, magic_link, sso
statusString(20)success, failed, blocked
geo_metadataJSONBGeographic information

geo_metadata Structure:

{
"country": "US",
"city": "San Francisco",
"region": "California",
"timezone": "America/Los_Angeles"
}

Indexes:

  • Composite index on (user_id, login_at DESC)

Relationships:

  • Many-to-one: user → User

Use Cases:

  • Security audit trails
  • Login failure detection and blocking
  • Geographic access patterns
  • Multi-device tracking

Table 3: core_data_user_sessions

Purpose: Active session management.

Key Features:

  • JWT/session token storage
  • Expiration handling
  • Company context per session
  • Activity tracking

Important Columns:

ColumnTypeConstraintsDescription
session_idUUIDPKSession identifier
user_idUUIDFK, indexedUser who owns session
company_idUUIDFKCompany context for session
tokenString(500)UNIQUEJWT or session token
expires_atDateTimeToken expiration time
created_atTimestampSession creation time
last_activity_atTimestampLast activity timestamp

Indexes:

  • B-tree index on user_id
  • Unique index on token

Relationships:

  • Many-to-one: user → User
  • Many-to-one: company → Company

Use Cases:

  • Session tracking and validation
  • Multi-session management per user
  • Token expiration handling
  • Activity monitoring

Part 2: Company & Organizational Structure

Table 4: core_config_company_types

Purpose: Industry-specific company classifications with module configuration rules.

Key Features:

  • Industry classification during onboarding
  • Determines available modules per industry
  • Industry-specific default configurations
  • Regulatory compliance filtering

Important Columns:

ColumnTypeConstraintsDescription
company_type_idUUIDPKPrimary identifier
codeString(50)UNIQUEIndustry code
nameString(100)Display name
descriptionTextDetailed description
created_atTimestampCreation time

Seed Data Examples:

CodeNameDescription
MANUFACTURERManufacturingManufacturing facilities
AUTO_SHOPAuto Repair ShopAutomotive repair services
PEST_CONTROLPest ControlPest management services
EHS_TRAINEREHS TrainerEnvironmental Health & Safety trainers
SCHOOL_DISTRICTSchool DistrictK-12 educational facilities
HEALTHCAREHealthcareHospitals and clinics
CONSTRUCTIONConstructionConstruction companies

Relationships:

  • One-to-many: companies → Company
  • One-to-many: module_rules → CompanyTypeModuleRule
  • One-to-many: screen_rules → CompanyTypeScreenRule

Use Cases:

  • Industry classification during onboarding
  • Determine available modules per industry
  • Industry-specific default configurations
  • Regulatory compliance filtering

Table 5: core_data_companies

Purpose: Master company record and tenant isolation.

Key Features:

  • Primary tenant isolation boundary
  • Complete company profile
  • Onboarding status tracking
  • Regulatory identifiers (EIN, EPA ID)

Important Columns:

ColumnTypeConstraintsDescription
company_idUUIDPKPrimary identifier
company_type_idUUIDFK, indexedIndustry type
legal_nameString(255)Official registered name
display_nameString(255)UNIQUEUser-facing company name
address_line1String(255)Street address line 1
address_line2String(255)Street address line 2
cityString(100)City
state_provinceString(100)State/Province
postal_codeString(20)Postal/ZIP code
countryString(100)default='USA'Country
phone_numberString(50)Contact phone
emailString(255)Contact email
websiteString(255)Company website
business_sizeString(50)Number of employees
einString(20)Employer Identification Number
epa_idString(50)EPA facility identifier
license_numberString(100)Business license
onboarding_statusString(20)default='pending'pending, in_progress, completed
created_atTimestampCreation time

Indexes:

  • B-tree index on company_type_id
  • Unique constraint on display_name

Relationships:

  • Many-to-one: company_type → CompanyType
  • One-to-many: sites → CompanySite
  • One-to-many: user_memberships → CompanyUserMembership
  • One-to-many: subscriptions → CompanySubscription
  • One-to-many: invites → Invite
  • One-to-many: onboarding_checklists → OnboardingChecklist
  • One-to-many: roles → CompanyRole
  • One-to-many: enabled_modules → CompanyEnabledModule

Use Cases:

  • Tenant isolation and multi-tenancy
  • Company profile management
  • Onboarding workflow tracking
  • Industry-specific configuration

Table 6: core_data_sites

Purpose: Company sites/facilities.

Key Features:

  • Multi-site company support
  • Site-level configuration
  • Site manager assignment
  • Geographic inventory tracking

Important Columns:

ColumnTypeConstraintsDescription
site_idUUIDPKPrimary identifier
company_idUUIDFK, indexedParent company
codeString(50)Site identifier code
nameString(255)Display name
descriptionTextSite details
address_line1String(255)Street address line 1
address_line2String(255)Street address line 2
cityString(100)City
state_provinceString(100)State/Province
postal_codeString(20)Postal/ZIP code
countryString(100)default='USA'Country
timezoneString(50)Site timezone
site_manager_nameString(255)Primary contact name
site_manager_contactString(255)Contact information
is_activeBooleandefault=trueActive flag
created_atTimestampCreation time
updated_atTimestampLast update time

Indexes:

  • B-tree index on company_id
  • Unique constraint on (company_id, code)

Relationships:

  • Many-to-one: company → Company
  • One-to-many: locations → SiteLocation

Use Cases:

  • Multi-site company management
  • Geographic inventory tracking
  • Site-specific role scoping
  • Regulatory compliance per location

Table 7: core_data_site_locations

Purpose: Specific locations within a site (buildings, warehouses, departments).

Key Features:

  • Granular location tracking
  • Hazard classification
  • Geographic coordinates
  • Ventilation status for chemical storage

Important Columns:

ColumnTypeConstraintsDescription
location_idUUIDPKPrimary identifier
site_idUUIDFK, indexedParent site
nameString(255)Location name
location_typeString(50)warehouse, office, manufacturing, storage
hazard_typeString(100)Hazard classification
ventilation_statusString(50)Ventilation level
address_line1String(255)Street address line 1
address_line2String(255)Street address line 2
cityString(100)City
state_provinceString(100)State/Province
postal_codeString(20)Postal/ZIP code
countryString(100)default='USA'Country
latitudeFloatGeographic latitude
longitudeFloatGeographic longitude
created_atTimestampCreation time

Indexes:

  • B-tree index on site_id

Relationships:

  • Many-to-one: site → CompanySite

Use Cases:

  • Granular inventory tracking by location
  • Hazard-specific storage rules
  • Geographic mapping
  • Environmental health & safety tracking

Part 3: Role-Based Access Control (RBAC)

Table 8: core_config_system_roles

Purpose: System-wide role templates that can be used or customized by companies.

Key Features:

  • Platform-wide role definitions
  • Template for company-specific roles
  • Permission bundling
  • Industry-standard role definitions

Important Columns:

ColumnTypeConstraintsDescription
system_role_idUUIDPKPrimary identifier
codeString(50)UNIQUERole code
display_nameString(100)Display name
descriptionTextRole description
created_atTimestampCreation time

Seed Data:

CodeDisplay NameDescription
ADMINAdministratorFull system access
MANAGERManagerSite/department management
PROGRAM_COORDINATORProgram CoordinatorEHS program coordination (OSHA Step 1)
EMPLOYEEEmployeeBasic access
CONSULTANTEHS ConsultantMulti-company access
VIEWERViewerRead-only access

Relationships:

  • One-to-many: permissions → SystemRolePermission
  • One-to-many: company_roles → CompanyRole (as base template)

Use Cases:

  • Define standard roles across platform
  • Template for company-specific role creation
  • Permission bundling
  • Industry-standard role definitions

Table 9: core_config_permissions

Purpose: Atomic permissions tied to specific features and capabilities.

Key Features:

  • Fine-grained access control
  • Hierarchical permission codes (module:feature:action)
  • Feature-specific permissions
  • Capability-level restrictions

Important Columns:

ColumnTypeConstraintsDescription
permission_idUUIDPKPrimary identifier
codeString(100)UNIQUEPermission code (hierarchical)
nameString(255)Display name
descriptionTextWhat this permission allows
module_idUUIDFK, indexedAssociated module
feature_idUUIDFKAssociated feature
capability_idUUIDFKAssociated capability
created_atTimestampCreation time

Permission Code Examples:

CodeDescription
adminhq:company:readRead company details
adminhq:company:writeModify company details
adminhq:users:inviteSend user invitations
chemiq:sds:uploadUpload SDS documents
chemiq:sds:deleteDelete SDS documents
chemiq:inventory:writeModify inventory

Relationships:

  • Many-to-one: module → Module
  • Many-to-one: feature → ModuleFeature
  • Many-to-one: capability → FeatureCapability
  • One-to-many: system_role_permissions → SystemRolePermission
  • One-to-many: company_role_permissions → CompanyRolePermission

Use Cases:

  • Fine-grained access control
  • Feature-specific permissions
  • Module capability restrictions
  • Audit trail of who can do what

Table 10: core_junction_system_role_permissions

Purpose: Many-to-many relationship between system roles and permissions.

Important Columns:

ColumnTypeConstraintsDescription
system_role_idUUIDPK, FKSystem role identifier
permission_idUUIDPK, FKPermission identifier
created_atTimestampAssignment time

Relationships:

  • Many-to-one: system_role → SystemRole
  • Many-to-one: permission → Permission

Use Cases:

  • Define permissions for system role templates
  • Audit default role capabilities
  • Role-to-permission mapping

Table 11: core_data_company_roles

Purpose: Company-specific roles that can be based on system templates but are customizable.

Key Features:

  • Customizable per company
  • Based on system role templates (optional)
  • Company-specific naming
  • Active/inactive status

Important Columns:

ColumnTypeConstraintsDescription
company_role_idUUIDPKPrimary identifier
company_idUUIDFK, indexedCompany that owns this role
base_system_role_idUUIDFKSystem role template (can be NULL)
role_codeString(50)Internal code (unique within company)
display_nameString(100)Customizable display name
descriptionTextRole description
is_system_defaultBooleandefault=falseAuto-created from system role
is_activeBooleandefault=trueActive status
created_atTimestampCreation time
updated_atTimestampLast update time

Indexes:

  • B-tree index on company_id
  • Unique constraint on (company_id, role_code)

Relationships:

  • Many-to-one: company → Company
  • Many-to-one: base_system_role → SystemRole
  • One-to-many: permissions → CompanyRolePermission
  • One-to-many: user_roles → CompanyUserRole

Use Cases:

  • Customize roles per company (rename "Manager" to "Site Supervisor")
  • Create company-specific custom roles
  • Role-based access control at company level
  • Flexible permission assignment

Table 12: core_junction_company_role_permissions

Purpose: Many-to-many relationship between company roles and permissions.

Important Columns:

ColumnTypeConstraintsDescription
company_role_idUUIDPK, FKCompany role identifier
permission_idUUIDPK, FKPermission identifier
created_atTimestampAssignment time

Relationships:

  • Many-to-one: company_role → CompanyRole
  • Many-to-one: permission → Permission

Use Cases:

  • Assign permissions to company-specific roles
  • Override system role permissions
  • Audit trail of role-permission assignments

Part 4: User Membership & Role Assignment

Table 13: core_junction_company_user_memberships

Purpose: User membership in companies (multi-company support).

Key Features:

  • Multi-company user support
  • Membership status tracking
  • Invite tracking
  • Join date recording

Important Columns:

ColumnTypeConstraintsDescription
company_idUUIDPK, FKCompany identifier
user_idUUIDPK, FK, indexedUser identifier
statusString(20)default='active'active, inactive, invited, suspended
invited_byUUIDFKUser who sent invite
joined_atTimestampdefault=nowWhen user joined

Indexes:

  • Composite primary key on (company_id, user_id)
  • B-tree index on user_id

Relationships:

  • Many-to-one: company → Company
  • Many-to-one: user → User
  • Many-to-one: invited_by_user → User
  • One-to-many: roles → CompanyUserRole

Use Cases:

  • Multi-company user support (consultants)
  • Invite tracking
  • User status management
  • Company-wide membership queries

Table 14: core_junction_company_user_roles

Purpose: User role assignments within companies.

Key Features:

  • Site-scoped role assignments
  • Multiple roles per user
  • Assignment audit trail
  • Flexible role management

Important Columns:

ColumnTypeConstraintsDescription
company_idUUIDPK, FKCompany identifier
user_idUUIDPK, FKUser identifier
company_role_idUUIDPK, FKAssigned role
site_idUUIDFKOptional site scope for this role
assigned_atTimestampdefault=nowAssignment timestamp
assigned_byUUIDFKUser who made assignment

Indexes:

  • B-tree index on user_id
  • B-tree index on company_id

Relationships:

  • Many-to-one: company_role → CompanyRole
  • Many-to-one: site → CompanySite
  • Many-to-one: user → User
  • Many-to-one: assigned_by_user → User

Use Cases:

  • Site-scoped role assignment (user is manager only at Site A)
  • Multi-role users (user has Admin role and Coordinator role)
  • Role audit trails
  • Permission resolution at query time

Part 5: Subscription & Entitlements

Table 15: core_config_plans

Purpose: Plan tiers defining feature sets and pricing.

Key Features:

  • Pricing tier definitions
  • Feature bundling
  • Version support
  • Upgrade/downgrade logic

Important Columns:

ColumnTypeConstraintsDescription
plan_idUUIDPKPrimary identifier
codeString(50)UNIQUEPlan code
nameString(100)Display name
descriptionTextPlan description
created_atTimestampCreation time

Seed Data:

CodeNameDescription
STARTERStarterBasic features for small teams
STANDARDStandardFull features for growing businesses
PROProfessionalAdvanced features with AI capabilities

Relationships:

  • One-to-many: versions → PlanVersion

Use Cases:

  • Define pricing tiers
  • Feature bundling
  • Versioning for plan changes
  • Upgrade/downgrade logic

Table 16: core_config_plan_versions

Purpose: Versioned plan configurations with effective dates.

Key Features:

  • Plan versioning for backward compatibility
  • Effective date management
  • Active/inactive status
  • Historical plan tracking

Important Columns:

ColumnTypeConstraintsDescription
plan_version_idUUIDPKPrimary identifier
plan_idUUIDFKPlan identifier
versionIntegerVersion number
is_activeBooleandefault=trueActive status
effective_fromDateWhen version becomes effective
effective_toDateWhen version expires
created_atTimestampCreation time

Indexes:

  • Unique constraint on (plan_id, version)

Relationships:

  • Many-to-one: plan → Plan
  • One-to-many: subscriptions → CompanySubscription
  • One-to-many: entitlements → PlanEntitlement
  • One-to-many: default_limits → PlanDefaultLimit

Use Cases:

  • Plan versioning for backward compatibility
  • Effective date management
  • Support for plan changes without migration
  • Historical plan tracking

Table 17: core_data_company_subscriptions

Purpose: Company subscription to specific plan versions.

Key Features:

  • Subscription tracking
  • Trial period management
  • Stripe integration
  • Status management

Important Columns:

ColumnTypeConstraintsDescription
subscription_idUUIDPKPrimary identifier
company_idUUIDFK, indexedCompany identifier
plan_version_idUUIDFKSubscribed plan version
started_atDateTimeSubscription start date
ends_atDateTimeSubscription end date (NULL = ongoing)
trial_ends_atDateTimeTrial period end
statusString(20)default='active'active, trial, past_due, canceled
stripe_subscription_idString(100)Stripe payment subscription ID
created_atTimestampCreation time

Indexes:

  • B-tree index on company_id
  • Unique constraint on (company_id, status) where status='active'

Relationships:

  • Many-to-one: company → Company
  • Many-to-one: plan_version → PlanVersion

Use Cases:

  • Track active subscriptions
  • Trial period management
  • Subscription status
  • Payment integration (Stripe)

Table 18: core_config_plan_default_limits

Purpose: Default usage limits per plan tier.

Key Features:

  • Plan quota definitions
  • Multiple limit types
  • Unit of measure support
  • Tier-based restrictions

Important Columns:

ColumnTypeConstraintsDescription
plan_limit_idUUIDPKPrimary identifier
plan_version_idUUIDFKPlan version
limit_codeString(50)Limit identifier
limit_valueBigIntegerLimit value (NULL = unlimited)
unitString(20)Unit of measure
descriptionTextLimit description
created_atTimestampCreation time

Limit Code Examples:

CodeUnitDescription
MAX_SITEScountMaximum number of sites
MAX_USERScountMaximum number of users
MAX_SDS_UPLOADSper_monthSDS uploads per month
MAX_STORAGEGBStorage quota

Indexes:

  • B-tree index on plan_version_id
  • Unique constraint on (plan_version_id, limit_code)

Relationships:

  • Many-to-one: plan_version → PlanVersion

Use Cases:

  • Define plan quotas
  • Rate limiting
  • Resource allocation
  • Upsell/downgrade logic

Table 19: core_config_entitlement_definitions

Purpose: Master catalog of all controllable features and limits.

Key Features:

  • Feature flag definitions
  • Limit/quota definitions
  • Type differentiation (FEATURE vs LIMIT)
  • Centralized entitlement catalog

Important Columns:

ColumnTypeConstraintsDescription
entitlement_idUUIDPKPrimary identifier
codeString(100)UNIQUEEntitlement code
nameString(255)Display name
typeString(20)FEATURE (boolean) or LIMIT (numeric)
unitString(20)Unit of measure (count, per_month, GB)
descriptionTextWhat this entitlement controls
created_atTimestampCreation time

Entitlement Examples:

CodeTypeDescription
sds_ai_parsingFEATUREAI-powered SDS parsing
sds_web_searchFEATUREWeb search for SDS documents
max_sds_documentsLIMITMaximum SDS documents
max_inventory_itemsLIMITMaximum inventory items

Indexes:

  • B-tree index on type

Relationships:

  • One-to-many: plan_entitlements → PlanEntitlement
  • One-to-many: company_overrides → CompanyEntitlementOverride

Use Cases:

  • Define all controllable features
  • Feature flags management
  • Quota/limit definitions
  • Entitlement catalog

Table 20: core_config_plan_entitlements

Purpose: Default entitlements included in each plan tier.

Key Features:

  • Plan feature sets
  • Tier-specific capabilities
  • Selectable entitlements for onboarding
  • Module association

Important Columns:

ColumnTypeConstraintsDescription
plan_entitlement_idUUIDPKPrimary identifier
plan_version_idUUIDFKPlan version
entitlement_idUUIDFKEntitlement definition
feature_enabledBooleanFor type='FEATURE', is it enabled?
limit_valueBigIntegerFor type='LIMIT', what is the quota?
is_selectableBooleandefault=trueCan user toggle in onboarding?
module_idUUIDFKAssociated module
feature_levelTextnullableFeature level descriptor (e.g. tier detail)
created_atTimestampCreation time

Indexes:

  • B-tree index on plan_version_id
  • Unique constraint on (plan_version_id, entitlement_id)

Relationships:

  • Many-to-one: plan_version → PlanVersion
  • Many-to-one: entitlement → EntitlementDefinition
  • Many-to-one: module → Module

Use Cases:

  • Define plan feature sets
  • Tier-specific feature control
  • Onboarding module selection
  • Feature visibility

Table 21: core_data_company_entitlement_overrides

Purpose: Per-company exceptions to plan entitlements (custom contracts, upgrades).

Key Features:

  • Custom enterprise contracts
  • Sales concessions
  • Feature upgrades
  • Override tracking with reasons

Important Columns:

ColumnTypeConstraintsDescription
override_idUUIDPKPrimary identifier
company_idUUIDFKCompany getting override
entitlement_idUUIDFKEntitlement being overridden
feature_enabledBooleanOverride for FEATURE type
limit_valueBigIntegerOverride for LIMIT type
reasonTextWhy override exists
created_atTimestampCreation time

Indexes:

  • B-tree index on company_id
  • Unique constraint on (company_id, entitlement_id)

Relationships:

  • Many-to-one: company → Company
  • Many-to-one: entitlement → EntitlementDefinition

Use Cases:

  • Custom enterprise contracts
  • Sales concessions
  • Feature upgrades
  • Upsell tracking

Part 6: Modules, Features & Capabilities

Table 22: core_config_modules

Purpose: Core platform modules (ADMINHQ, CHEMIQ, SAFEPATH, etc.).

Key Features:

  • Module definitions
  • Category classification (REQUIRED, USER_OPTION, UNDERLYING)
  • Parent-child relationships
  • Visibility control

Important Columns:

ColumnTypeConstraintsDescription
module_idUUIDPKPrimary identifier
codeString(50)UNIQUEModule code
nameString(100)Display name
descriptionTextModule description
categoryString(20)REQUIRED, USER_OPTION, UNDERLYING
parent_module_idUUIDFKParent module (for nesting)
is_visibleBooleandefault=trueWhether to show in UI
created_atTimestampCreation time

Category Definitions:

CategoryDescription
REQUIREDAlways enabled, cannot be disabled
USER_OPTIONSelectable by user during onboarding
UNDERLYINGSystem modules, hidden from UI

Module Examples:

CodeNameCategory
ADMINHQAdmin HQREQUIRED
CHEMIQChemIQUSER_OPTION
SAFEPATHSafePathUSER_OPTION
INCIDENTIQIncidentIQUSER_OPTION
INSIGHTSInsightsUNDERLYING

Indexes:

  • B-tree index on category
  • B-tree index on parent_module_id
  • CHECK constraint: UNDERLYING modules must have is_visible=false

Relationships:

  • One-to-many: screens → ModuleScreen
  • One-to-many: company_type_rules → CompanyTypeModuleRule
  • Self-referencing: parent_module
  • One-to-many: enabled_companies → CompanyEnabledModule
  • One-to-many: features → ModuleFeature

Use Cases:

  • Define platform modules
  • Industry-specific feature availability
  • Parent-child module relationships
  • Visibility control

Table 23: core_config_module_features

Purpose: Features within modules.

Key Features:

  • Feature definitions per module
  • Display ordering
  • Active/inactive status
  • Capability grouping

Important Columns:

ColumnTypeConstraintsDescription
feature_idUUIDPKPrimary identifier
module_idUUIDFKParent module
codeString(50)Feature code
nameString(100)Display name
descriptionTextFeature description
display_orderIntegerOrder for UI display
is_activeBooleandefault=trueActive flag
created_atTimestampCreation time

Feature Examples (ChemIQ):

CodeNameDescription
SDS_BINDERSDS BinderSDS document management
INVENTORYChemical InventoryInventory tracking
BARCODE_SCANBarcode ScanningBarcode-based lookup
EPA_LABELSEPA LabelsFIFRA pesticide labels

Indexes:

  • B-tree index on module_id
  • Unique constraint on (module_id, code)

Relationships:

  • Many-to-one: module → Module
  • One-to-many: capabilities → FeatureCapability

Use Cases:

  • Define module features
  • Feature availability per tier
  • Capability grouping

Table 24: core_config_feature_capabilities

Purpose: Tier-specific capabilities for each feature.

Key Features:

  • Tier differentiation (STARTER, STANDARD, PRO)
  • Capability-level detail
  • Optional permission binding
  • Feature comparison across tiers

Important Columns:

ColumnTypeConstraintsDescription
capability_idUUIDPKPrimary identifier
feature_idUUIDFKParent feature
capability_codeString(100)Capability identifier
tierString(20)STARTER, STANDARD, or PRO
descriptionTextWhat this capability includes
requires_permissionString(100)Optional permission code
created_atTimestampCreation time

Capability Examples:

FeatureTierCapabilityDescription
SDS_BINDERSTARTERmanual_uploadManual SDS upload
SDS_BINDERSTANDARDweb_searchWeb search for SDS
SDS_BINDERPROai_parsingAI-powered SDS parsing

Indexes:

  • B-tree index on feature_id
  • B-tree index on tier
  • Unique constraint on (feature_id, capability_code, tier)

Relationships:

  • Many-to-one: feature → ModuleFeature

Use Cases:

  • Define tier-specific capabilities
  • Feature comparison across tiers
  • Permission binding to capabilities

Table 25: core_junction_company_type_module_rules

Purpose: Define module availability per company type/industry.

Key Features:

  • Industry-specific module availability
  • Availability levels (REQUIRED, DEFAULT_ON, OPTIONAL, HIDDEN)
  • Reason tracking
  • Regulatory compliance

Important Columns:

ColumnTypeConstraintsDescription
rule_idUUIDPKPrimary identifier
company_type_idUUIDFKCompany type
module_idUUIDFKModule
availabilityString(20)REQUIRED, DEFAULT_ON, OPTIONAL, HIDDEN
reasonTextWhy module is available/hidden
created_atTimestampCreation time

Availability Definitions:

AvailabilityDescription
REQUIREDAlways enabled, cannot disable
DEFAULT_ONEnabled by default, can disable
OPTIONALNot enabled by default, can enable
HIDDENNot available for this industry

Indexes:

  • B-tree index on company_type_id
  • B-tree index on module_id
  • Unique constraint on (company_type_id, module_id)

Relationships:

  • Many-to-one: company_type → CompanyType
  • Many-to-one: module → Module

Use Cases:

  • Industry-specific module availability
  • Regulatory requirement enforcement
  • Default module selection for onboarding

Table 26: core_junction_company_enabled_modules

Purpose: Track which modules are enabled for each company.

Key Features:

  • Module enablement tracking
  • User vs. system enablement distinction
  • Enablement timestamp
  • Audit trail

Important Columns:

ColumnTypeConstraintsDescription
company_idUUIDPK, FKCompany identifier
module_idUUIDPK, FKModule identifier
enabled_byUUIDFKUser who enabled (NULL for system)
enabled_atTimestampdefault=nowWhen enabled

Indexes:

  • B-tree index on company_id

Relationships:

  • Many-to-one: company → Company
  • Many-to-one: module → Module
  • Many-to-one: enabled_by_user → User

Use Cases:

  • Track enabled modules per company
  • Distinguish user-selected vs. system-attached modules
  • Audit trail of module activation
  • Feature availability checking

Part 7: Invitations & Onboarding

Table 27: core_data_invites

Purpose: User invitation tracking.

Key Features:

  • Unique invite tokens
  • Expiration handling
  • Status tracking
  • Role pre-assignment

Important Columns:

ColumnTypeConstraintsDescription
invite_idUUIDPKPrimary identifier
company_idUUIDFK, indexedCompany sending invite
emailString(255)Invited email address
company_role_idUUIDFKRole to assign upon acceptance
role_templateUUIDFKSystem role template for invite
site_idUUIDFKOptional site scope
invite_tokenString(100)UNIQUE, indexedUnique token for invite link
expires_atDateTimeExpiration timestamp
accepted_atDateTimeWhen user accepted
invited_byUUIDFKUser who sent invite
statusString(20)default='pending'pending, accepted, expired, revoked
invite_metadataJSONBAdditional user data
created_atTimestampCreation time

invite_metadata Structure:

{
"full_name": "John Doe",
"department": "Safety",
"custom_message": "Welcome to the team!"
}

Indexes:

  • B-tree index on company_id
  • Unique index on invite_token where status='pending'

Relationships:

  • Many-to-one: company → Company
  • Many-to-one: company_role → CompanyRole
  • Many-to-one: role_template → SystemRole
  • Many-to-one: site → CompanySite
  • Many-to-one: invited_by_user → User

Use Cases:

  • User invitations
  • Temporary access tokens
  • Invite status tracking
  • Role pre-assignment

Table 28: core_data_onboarding_checklist

Purpose: Track onboarding progress for companies.

Key Features:

  • Step-by-step progress tracking
  • Status per step (pending, in_progress, done, skipped)
  • Metadata storage per step
  • Completion verification

Important Columns:

ColumnTypeConstraintsDescription
company_idUUIDPK, FKCompany identifier
step_codeString(50)PKStep identifier
statusString(20)default='pending'pending, in_progress, done, skipped
meta_jsonJSONBStep-specific metadata
updated_atTimestamponupdateLast update time

Unified Onboarding Steps:

Step CodeTitleRequiredOrder
industryIndustry & Company TypeYes1
modulesModules & PlanYes2
detailsCompany DetailsYes3
coordinatorProgram CoordinatorYes4
rolesRoles & PermissionsNo5
sitesSitesYes6
locationsLocationsNo7
teamTeam MembersNo8
finalizeReview & CompleteYes9

Relationships:

  • Many-to-one: company → Company

Use Cases:

  • Track onboarding progress
  • Multi-step workflow management
  • Skip logic for optional steps
  • Onboarding completion verification

Table 29: core_data_audit_logs

Purpose: Audit trail for all entity changes across the platform.

Key Features:

  • Complete change history for any entity
  • Tracks old and new values
  • User and company context
  • Action type categorization

Important Columns:

ColumnTypeConstraintsDescription
audit_idUUIDPKPrimary identifier
company_idUUIDFK, indexedCompany context
user_idUUIDFKUser who made the change
target_tableTextTable that was modified
target_idUUIDID of the modified record
actionTextcreate, update, delete
changed_fieldsJSONBFields that were changed
old_valuesJSONBPrevious values
new_valuesJSONBNew values
occurred_atTimestampWhen change occurred

Indexes:

  • B-tree index on company_id
  • B-tree index on occurred_at

Relationships:

  • Many-to-one: company → Company
  • Many-to-one: user → User

Use Cases:

  • Compliance audit trails
  • Track all entity changes
  • Debug data issues
  • Generate change reports for regulators

Complete Table Summary

Total Core Module Tables: 29

Configuration Tables (System-wide, seeded in migrations): 10

  1. core_config_company_types
  2. core_config_system_roles
  3. core_config_permissions
  4. core_config_modules
  5. core_config_module_features
  6. core_config_feature_capabilities
  7. core_config_plans
  8. core_config_plan_versions
  9. core_config_plan_default_limits
  10. core_config_entitlement_definitions
  11. core_config_plan_entitlements

Data Tables (Tenant-specific, user-generated): 12 12. core_data_users 13. core_data_user_login_audit 14. core_data_user_sessions 15. core_data_companies 16. core_data_sites 17. core_data_site_locations 18. core_data_company_roles 19. core_data_company_subscriptions 20. core_data_company_entitlement_overrides 21. core_data_invites 22. core_data_onboarding_checklist 23. core_data_audit_logs

Junction Tables (Many-to-many relationships): 6 24. core_junction_system_role_permissions 25. core_junction_company_role_permissions 26. core_junction_company_user_memberships 27. core_junction_company_user_roles 28. core_junction_company_enabled_modules 29. core_junction_company_type_module_rules


Key Relationships Summary

Company
├── company_type (CompanyType)
├── subscriptions (CompanySubscription)
│ └── plan_version (PlanVersion)
│ └── plan (Plan)
├── sites (CompanySite)
│ └── locations (SiteLocation)
├── user_memberships (CompanyUserMembership)
│ └── roles (CompanyUserRole)
│ └── company_role (CompanyRole)
├── roles (CompanyRole)
│ ├── base_system_role (SystemRole)
│ └── permissions (CompanyRolePermission)
│ └── permission (Permission)
├── enabled_modules (CompanyEnabledModule)
│ └── module (Module)
├── invites (Invite)
├── onboarding_checklists (OnboardingChecklist)
└── entitlement_overrides (CompanyEntitlementOverride)
└── entitlement (EntitlementDefinition)

User
├── login_audits (UserLoginAudit)
├── sessions (UserSession)
├── company_memberships (CompanyUserMembership)
│ └── company (Company)
└── company_roles (CompanyUserRole)
└── company_role (CompanyRole)

Module
├── screens (ModuleScreen)
├── features (ModuleFeature)
│ └── capabilities (FeatureCapability)
├── company_type_rules (CompanyTypeModuleRule)
└── enabled_companies (CompanyEnabledModule)

Plan
├── versions (PlanVersion)
│ ├── subscriptions (CompanySubscription)
│ ├── entitlements (PlanEntitlement)
│ │ └── entitlement (EntitlementDefinition)
│ └── default_limits (PlanDefaultLimit)

SystemRole
├── permissions (SystemRolePermission)
│ └── permission (Permission)
└── company_roles (CompanyRole) [as base_system_role]

SQLAlchemy Models

Location: tellus-ehs-hazcom-service/app/db/models/

User Models (user.py)

  1. User - Main user model
  2. UserLoginAudit - Login audit trail
  3. UserSession - Active sessions

Company Models (company.py)

  1. CompanyType - Industry classification
  2. Company - Main company model
  3. CompanySite - Company sites
  4. SiteLocation - Site locations

Role Models (role.py)

  1. SystemRole - System role templates
  2. Permission - Atomic permissions
  3. SystemRolePermission - System role-permission mapping
  4. CompanyRole - Company-specific roles
  5. CompanyRolePermission - Company role-permission mapping

Membership Models (membership.py)

  1. CompanyUserMembership - User-company membership
  2. CompanyUserRole - User role assignments

Plan Models (plan.py)

  1. Plan - Plan definitions
  2. PlanVersion - Plan versions
  3. CompanySubscription - Company subscriptions
  4. PlanDefaultLimit - Plan limits

Module Models (module.py)

  1. Module - Module definitions
  2. ModuleScreen - Module screens
  3. CompanyTypeModuleRule - Industry module rules
  4. CompanyTypeScreenRule - Industry screen rules
  5. CompanyEnabledModule - Company module enablements
  6. ModuleFeature - Module features
  7. FeatureCapability - Feature capabilities

Entitlement Models (entitlement.py)

  1. EntitlementDefinition - Entitlement catalog
  2. PlanEntitlement - Plan entitlements
  3. CompanyEntitlementOverride - Company overrides

Other Models

  1. Invite (invite.py) - User invitations
  2. OnboardingChecklist (onboarding.py) - Onboarding progress

Example Queries

Get user's permissions for a company

SELECT DISTINCT p.code, p.name
FROM core_config_permissions p
JOIN core_junction_company_role_permissions crp ON p.permission_id = crp.permission_id
JOIN core_data_company_roles cr ON crp.company_role_id = cr.company_role_id
JOIN core_junction_company_user_roles cur ON cr.company_role_id = cur.company_role_id
WHERE cur.company_id = :company_id
AND cur.user_id = :user_id;

Get company's enabled modules with features

SELECT m.code, m.name, mf.code AS feature_code, mf.name AS feature_name
FROM core_config_modules m
JOIN core_junction_company_enabled_modules cem ON m.module_id = cem.module_id
LEFT JOIN core_config_module_features mf ON m.module_id = mf.module_id
WHERE cem.company_id = :company_id
AND m.is_visible = true
ORDER BY m.code, mf.display_order;

Get company's subscription with plan details

SELECT c.display_name, p.code AS plan_code, pv.version,
cs.status, cs.trial_ends_at
FROM core_data_companies c
JOIN core_data_company_subscriptions cs ON c.company_id = cs.company_id
JOIN core_config_plan_versions pv ON cs.plan_version_id = pv.plan_version_id
JOIN core_config_plans p ON pv.plan_id = p.plan_id
WHERE c.company_id = :company_id
AND cs.status IN ('active', 'trial');

Get onboarding progress

SELECT step_code, status, updated_at
FROM core_data_onboarding_checklist
WHERE company_id = :company_id
ORDER BY
CASE step_code
WHEN 'industry' THEN 1
WHEN 'modules' THEN 2
WHEN 'details' THEN 3
WHEN 'coordinator' THEN 4
WHEN 'roles' THEN 5
WHEN 'sites' THEN 6
WHEN 'locations' THEN 7
WHEN 'team' THEN 8
WHEN 'finalize' THEN 9
END;

Check if user has specific permission

SELECT EXISTS (
SELECT 1
FROM core_junction_company_user_roles cur
JOIN core_junction_company_role_permissions crp
ON cur.company_role_id = crp.company_role_id
JOIN core_config_permissions p
ON crp.permission_id = p.permission_id
WHERE cur.company_id = :company_id
AND cur.user_id = :user_id
AND p.code = :permission_code
AND (cur.site_id IS NULL OR cur.site_id = :site_id)
) AS has_permission;

Performance Considerations

Indexes

  • Compound indexes on (company_id, user_id) for membership queries
  • Covering indexes on (company_id, status) for filtered queries
  • Foreign key indexes on all junction tables for join optimization
  • Unique constraints prevent duplicate assignments

Query Patterns

  • Fast company membership checks
  • Efficient role-permission lookups (cached in app layer)
  • Site-scoped role queries
  • Module availability per company type

Data Volume Expectations

TableExpected VolumeGrowth Pattern
core_data_usersHundreds of thousandsSlow, steady
core_data_companiesThousandsSlow growth
core_junction_company_user_membershipsMillionsModerate
core_data_user_login_auditTens of millionsHigh, time-partitioned
core_data_user_sessionsEphemeralCleaned after expiration

Caching Strategy

  • Configuration tables (core_config_*) cached at app startup
  • Permission lookups cached per user session
  • Module/feature availability cached per company

Security Considerations

Multi-Tenancy Isolation

  • All queries must include company_id filter
  • No cross-company data leakage
  • Site-scoped permissions for granular access

Authentication

  • Supabase integration for auth
  • JWT token validation
  • Session management with expiration

Audit Trails

  • Login audit for all authentication events
  • Role assignment tracking
  • Onboarding step changes

Data Protection

  • No PII in logs beyond user_id
  • Invite tokens expire after 7 days
  • Sessions expire after 12 hours (configurable)

Integration Points

Supabase

  • User authentication via supabase_uid
  • Token validation
  • Password reset flows

Stripe

  • Subscription management via stripe_subscription_id
  • Payment processing
  • Plan upgrades/downgrades

ChemIQ Module

  • Company isolation via company_id
  • Site/location scoping
  • Permission checks for SDS/inventory access

Background Services

  • Invite expiration cleanup
  • Session cleanup
  • Subscription renewal checks

Migration Files

Key Alembic migrations for AdminHQ Core:

  1. Initial Schema - Creates all core tables
  2. Add Onboarding Checklist - core_data_onboarding_checklist
  3. Add Module Features - core_config_module_features, core_config_feature_capabilities
  4. Add Entitlements - Entitlement system tables
  5. Add Company Roles - Company-specific role system

See tellus-ehs-hazcom-service/alembic/versions/ for complete migration history.


Summary

The AdminHQ Core schema provides the foundational infrastructure for the Tellus EHS platform:

  1. Multi-tenant isolation - Companies completely isolated via company_id
  2. Flexible RBAC - Customizable roles with granular permissions
  3. Feature management - Per-tier capability control via entitlements
  4. Guided onboarding - Step-by-step company setup with progress tracking
  5. Multi-company users - Consultants can access multiple companies
  6. Industry compliance - Industry-specific module rules and requirements
  7. Audit trails - Complete authentication and action logging
  8. Subscription management - Plan versioning with Stripe integration

This schema integrates seamlessly with the ChemIQ module and other future modules, providing a robust foundation for scalable multi-tenant SaaS operations.