Skip to content

Platform Administrator Guide

Overview

This guide covers the Platform Console -- the internal operations dashboard at /platform/* where Cadenora staff manage tenants, users, support sessions, and infrastructure health. The Platform Console operates on the control plane, which is physically separated from the data plane where tenant business data lives.

This separation is enforced at every layer of the stack: URL routing, middleware, database transactions, and storage. A platform admin cannot see individual client records, document content, or tenant business data without explicitly entering a support session.

Audience: Platform Administrators, Support Engineers, Security Team


Table of Contents

  1. Getting Started
  2. Tenant Management
  3. User Management
  4. Support Sessions
  5. Impersonation
  6. System Monitoring
  7. Security and Compliance
  8. Configuration
  9. Operational Procedures
  10. Troubleshooting

1. Getting Started

1.1 Platform Roles

Three platform-tier roles exist, each scoped to specific operational responsibilities:

RoleCodeDescriptionMFA Required
Platform AdminPLATFORM_ADMINFull platform operator: tenant provisioning, global config, user management, system diagnostics, support sessionsYes (AAL2)
Platform SupportPLATFORM_SUPPORTSupport operator: view tenant health and status, create support sessions, run diagnosticsYes (AAL2)
Platform SecurityPLATFORM_SECURITYSecurity operator: audit review, access reviews, security policy enforcementYes (AAL2)

All platform roles require MFA. You cannot access the Platform Console without an active AAL2 session.

1.2 Logging In

Platform admins authenticate via CadenoraAuth, the in-process identity system (bcrypt + Redis + Prisma). The login flow:

  1. Navigate to https://app.cadenora.com/auth/login.
  2. Enter your platform admin email and password.
  3. Complete TOTP verification (MFA).
  4. The system creates a session with actorType: PLATFORM and redirects you to /platform/dashboard.

Your session cookie (cadenora_sid) contains a minimal JWT for Edge validation. The full session, including your role, groups, and actor type, is stored in Redis.

Legacy routes: If you navigate to /admin/*, the middleware automatically redirects to /platform/* via a 301 redirect. This is part of the route consolidation completed in v8.2.

1.3 Platform Dashboard Overview

The dashboard at /platform/dashboard is your landing page. It provides:

  • Active Tenants count -- Total organizations with ACTIVE status.
  • Total Users count -- Users across all tenants (aggregate integer, no individual records).
  • Active Support Sessions count -- Currently active support connections.
  • Recent Tenants -- Last 5 tenants created, showing name, status, and creation date.
  • Recent Support Sessions -- Last 5 support sessions with tenant name, reason, and timestamps.
  • Quick Actions -- Links to Manage Tenants, Support Sessions, and View All Users.

1.4 Platform Console Navigation

PageRoutePurpose
Dashboard/platform/dashboardSystem health and tenant overview
Tenant List/platform/tenantsView and manage all tenants
New Tenant/platform/tenants/newProvision a new tenant workspace
Tenant Detail/platform/tenants/{id}Configuration and status of a specific tenant
Platform Users/platform/usersManage platform-level user accounts
Support Dashboard/platform/supportSupport sessions and impersonation tools
System Status/platform/systemInfrastructure health and service status
Redirect Analytics/platform/analytics/redirectsAnalytics for legacy route redirects

2. Tenant Management

2.1 Tenant List

Navigate to /platform/tenants to see all tenants. The list displays:

ColumnSourceDescription
Nametenant.nameClickable link to tenant detail
Subdomaintenant.subdomainThe tenant's URL slug (e.g., acme-corp)
Statustenant.statusDRAFT, ACTIVATING, ACTIVE, SUSPENDED
Industryconfiguration.industryTemplateThe industry template selected at onboarding
Admin Emailtenant.adminEmailThe provisioning admin's email
Users_count.usersInternal staff count (integer)
Projects_count.projectsContainer count (integer)
Client Orgs_count.clientOrganizationsClient organization count (integer)
Client Members_count.clientMembersClient member count (integer)
Invites_count.invitesInvitation count (integer)
Createdtenant.createdAtTenant creation timestamp

All client-related columns are aggregate counts only. Individual client records (names, emails, organization details) are never displayed to platform admins. This follows the control plane / data plane separation model.

2.2 Tenant Detail

Click a tenant name to access the detail page at /platform/tenants/{id}. This page provides nine stat cards in a grid layout:

CardData
StatusBadge: ACTIVE, DRAFT, SUSPENDED
UsersInternal staff count with max users limit
ProjectsContainer count
DocumentsDocument count
Client OrgsClient organization count (integer only)
Client MembersClient member count (integer only)
InvitationsInvitation count (integer only)
Storage UsedstorageUsedGb / storageQuotaGb
CreatedCreation and activation timestamps

Additional sections on the detail page:

  • Tenant Settings -- Tier, Admin Email, MFA policy, password policy, session timeout, onboarding email delay.
  • Industry Configuration -- Template (immutable after onboarding), current theme, terminology labels.
  • Internal Users (last 10) -- Staff names, emails, and roles. Only users with FIRM_ADMIN or PROJECT_MANAGER roles; INVESTOR role users are excluded from this view.
  • Recent Projects (last 10) -- Project names, statuses, and creation dates. Metadata only, no content or financials.
  • Activity Log (last 20) -- Audit log entries showing action, resource type, and timestamp. No content or PII details.
  • Danger Zone -- Delete tenant button (requires confirmation and audit justification).

2.3 Provisioning a New Tenant

Navigate to /platform/tenants/new or click "Create New Tenant" from the tenant list.

Step 1: Basic Information

FieldRequiredValidation
Organization NameYes2-80 characters
SubdomainYes3-63 characters, lowercase alphanumeric and hyphens only
Admin EmailYesValid email format
DescriptionNoMax 500 characters

The subdomain is auto-generated from the organization name. The system checks subdomain availability in real time via GET /api/platform/tenants/check-subdomain.

Step 2: Industry Template Selection

Select one of the five industry templates. Each template pre-configures:

TemplateContainer TermClient TermPortal NameDefault Theme
Financial ServicesProjectInvestorInvestor PortalExecutive
Real Estate DevelopmentDevelopmentInvestorInvestor PortalEmber
Property ManagementPropertyResidentResident PortalHorizon
Legal ServicesMatterClientClient PortalCorporate
General / OtherProjectClientClient PortalMinimal

You can clear the selection to let the tenant choose during onboarding instead.

Step 3: Submit

Clicking "Create Tenant" triggers the following backend flow:

  1. POST /api/platform/tenants creates a Tenant record in DRAFT status.
  2. The system redirects to the new tenant's detail page.
  3. From the detail page, click "Activate" to trigger the Temporal ProvisionTenantWorkflow.

Provisioning Workflow (Temporal):

The ProvisionTenantWorkflow executes the following activities in sequence:

  1. ValidateTenant -- Checks subdomain uniqueness and email validity.
  2. CreateTenantRecord -- Creates Tenant + TenantConfiguration with the selected industry template.
  3. ApplyTemplate -- Creates default document categories for the industry.
  4. CreateAdminUser -- Creates the User record with bcrypt-hashed password and AuthIdentity (provider: local) via CadenoraAuth.
  5. CreateAuditLog -- Logs the provisioning event.
  6. SendWelcomeEmail -- Sends a setup-password token email to the admin.

Tenant status transitions: DRAFT -> ACTIVATING -> ACTIVE.

If any step fails, the saga compensation mechanism rolls back partial state. The workflow uses WorkflowIDReusePolicy: RejectDuplicate to prevent double-click activation.

2.4 Tenant Status Lifecycle

StatusMeaningActions Available
DRAFTTenant created but not activatedActivate, Edit, Delete
ACTIVATINGProvisioning workflow in progressView status (polling)
ACTIVEFully operationalView details, Suspend, Enter support session
SUSPENDEDTemporarily disabledReactivate, View details

2.5 Activating a Tenant

From the tenant detail page, click "Activate Tenant". This transitions the tenant from DRAFT to ACTIVATING and starts the Temporal provisioning workflow.

The activation button calls POST /api/platform/tenants/{tenantId}/activate. While the workflow is running, the tenant detail page polls for status updates. Login routes detect PROVISIONING_IN_PROGRESS status and return a 503 with a user-friendly message if someone tries to log in before provisioning completes.

2.6 Suspending a Tenant

From the tenant detail page, click "Suspend Tenant" (available when status is ACTIVE). This calls POST /api/platform/tenants/{tenantId}/suspend.

When suspended:

  • Users cannot log in to the tenant workspace.
  • Existing sessions are revoked.
  • Data is preserved (not deleted).
  • Support sessions can still be created for investigation.

2.7 Tenant Configuration

The tenant detail page shows the industry configuration section:

  • Industry Template -- Set at onboarding, immutable afterward. Determines default categories, terminology, and theme.
  • Theme -- Can be changed by the tenant's Firm Admin at Settings > Branding, or overridden by a Platform Admin via PATCH /api/platform/tenants/{tenantId}/configuration.
  • Terminology -- The 14 dynamic label fields (9 raw + 5 computed). Customizable by the tenant. The platform view shows the current terminology values.

3. User Management

3.1 Platform Users Page

Navigate to /platform/users to see all users with platform roles. This page lists PLATFORM_ADMIN, PLATFORM_SUPPORT, and PLATFORM_SECURITY users.

3.2 Cross-Tenant User Visibility

Platform admins can view a tenant's internal staff (users with FIRM_ADMIN or PROJECT_MANAGER roles) via the tenant detail page. This is limited to the last 10 staff members, showing only name, email, and role.

Platform admins cannot see individual investor/client users (INVESTOR role) from the platform interface. Client user data is end-customer PII belonging to the tenant firm. To see individual client records, you must enter a support session.

3.3 What Platform Admins See vs. Do Not See

Visible to platform admins:

DataSourceRisk Level
Tenant metadata (name, subdomain, status)Tenant modelNone
Industry configurationTenantConfiguration modelNone
Admin email (provisioning contact)Tenant modelNone
Aggregate counts (users, projects, docs, clients)_count integersNone
Internal staff names and emails (last 10)User model (staff roles only)Low
Project metadata (name, status, date)Project model (last 10)Low
Audit log metadata (action, type, timestamp)AuditLog model (last 20)Low

Not visible to platform admins (requires support session):

DataReason
Individual client names and emailsEnd-customer PII; PIPEDA/GDPR exposure
Client organization detailsTenant business relationship data
Document content or previewsTenant business data (data plane)
Client-document grantsReveals client engagement patterns
Investor profilesSensitive financial PII
Invitation details (individual emails)PII exposure

3.4 User Provisioning by Platform Admin

Platform admins can provision users for any tenant using the Tenant Provisioning approach:

  1. Navigate to /platform/tenants.
  2. Select the target tenant.
  3. The provisioning workflow creates the admin user automatically.

For additional users within a tenant, you must either:

  • Enter a support session (SUPPORT_ADMIN mode) and use the tenant's user management interface.
  • Have the tenant's Firm Admin invite users themselves.

3.5 Password Reset Assistance

If a user cannot log in and the tenant's Firm Admin is unavailable:

  1. Enter a SUPPORT_ADMIN session for the tenant (see Section 4).
  2. Navigate to the tenant's user management at /t/{slug}/users.
  3. Locate the user and trigger a password reset email.
  4. The system sends a setup-password token to the user's email.
  5. End the support session when finished.

4. Support Sessions

4.1 What Support Sessions Are

Support sessions are time-boxed, audit-logged access grants that allow platform operators to access a specific tenant's data. They are the controlled escalation mechanism that bridges the control plane / data plane boundary.

Without a support session, platform admins see only aggregate counts and metadata. With a support session, you operate within the tenant's workspace with either read-only or delegated admin access.

4.2 Support Session Modes

ModeEffective RoleCan Read DataCan Modify DataTypical Use
READ_ONLYSUPPORT_READONLYYesNo (blocked by requireWriteAccess())Investigating issues, viewing tenant configuration
DELEGATED_ADMINSUPPORT_ADMINYesYes (all admin-level mutations)Fixing data issues, performing actions on behalf of tenant

4.3 Creating a Support Session

Navigate to /platform/support and click "New Support Session". The dialog requires:

FieldRequiredValidation
TenantYesSelect from active tenants (UUID)
ModeYesREAD_ONLY or DELEGATED_ADMIN
ReasonOptional (recommended)Max 1000 characters; reference a support ticket
TTL (Hours)Optional1-4 hours; defaults to 2 hours

Security requirements:

  • You must have PLATFORM_ADMIN or PLATFORM_SUPPORT role.
  • TOTP step-up verification is required (fresh MFA within the last 5 minutes).
  • All creation requests are audit-logged with your identity, IP address, user agent, mode, reason, and TTL.

What happens on creation:

  1. POST /api/platform/support/sessions validates your identity and step-up status.
  2. A SupportSession record is created with a SHA-256 hashed session token.
  3. Your Redis session is updated with supportContext (tenant ID, slug, mode, expiry).
  4. An audit log entry is created: SUPPORT_SESSION_CREATED.
  5. You are redirected to /t/{slug}/ -- the tenant's workspace, now accessible with your support role.

Visual indicator: The UI should display a banner or badge indicating you are in support mode, showing the tenant name, mode, and remaining time.

4.4 Operating Within a Support Session

Once inside a support session:

  • READ_ONLY mode: You can browse the tenant workspace, view documents, users, projects, audit logs, and settings. Any attempt to create, update, or delete data returns a 403 error. The requireWriteAccess(context) guard blocks all mutations.
  • DELEGATED_ADMIN mode: You have full admin access within the tenant. You can manage users, upload documents, change settings, and perform any action a FIRM_ADMIN could.

Audit trail during support sessions: Every action you take is logged with dual-identity attribution:

  • actorId -- Your platform admin user ID.
  • supportSessionId -- The support session ID.
  • auditorUserId -- Your platform admin user ID (for cross-reference).

4.5 Support Session Time Limits

SettingValue
Default TTL2 hours
Minimum TTL1 hour
Maximum TTL4 hours
Auto-expirySession automatically becomes invalid after expiresAt

When a session expires, the middleware detects the expired supportContext and redirects you back to the Platform Console. Your access to the tenant workspace is immediately revoked.

4.6 Ending a Support Session

You can end a support session before its natural expiry:

  1. Navigate to /platform/support.
  2. Find the active session in the list.
  3. Click "End Session" (or use the session banner's end button).
  4. DELETE /api/platform/support/sessions/{sessionId} is called.
  5. The session record is updated with revokedAt and revokeReason.
  6. An audit log entry is created: SUPPORT_SESSION_ENDED.
  7. Your Redis session is cleared of the supportContext.

4.7 Support Dashboard

The Support Dashboard at /platform/support shows:

  • Active Sessions -- Count of currently active (not revoked, not expired) sessions.
  • Total Sessions -- Count of all sessions (last 50).
  • Revoked Sessions -- Count of manually ended sessions.
  • Session Table -- Columns: Support User, Tenant, Mode, Status (Active/Expired/Revoked), Created, Expires, Reason.

4.8 Namespace Enforcement

The middleware at src/middleware.ts enforces that platform admins cannot access /t/{slug}/* or /i/{slug}/* routes without an active support session. If you try to navigate to a tenant workspace URL without a valid supportContext:

  • You are redirected to /platform with an error message (tenant_access_required).
  • The attempted access is logged.

5. Impersonation

5.1 When to Use Impersonation

Impersonation sessions are a deeper access level than support sessions. Use impersonation when you need to:

  • Reproduce a user-specific bug -- see the workspace exactly as a specific user sees it.
  • Debug permission issues -- verify what a particular user can and cannot access.
  • Perform actions on behalf of a user -- when the user cannot do so themselves (e.g., accessibility issues, emergency).

Impersonation is more invasive than a support session because you inherit the target user's specific permissions rather than operating as a generic admin.

5.2 Who Can Impersonate

RoleCan ImpersonateConditions
PLATFORM_ADMINYesTOTP step-up required; must have active support session or tenant context
FIRM_ADMINYesOnly within their own tenant; TOTP step-up required
PLATFORM_SUPPORTYesOnly when an active support session exists for the target tenant

5.3 Creating an Impersonation Session

Prerequisites:

  1. You need an active support session for the target tenant (if you are a platform operator), or you need to be a FIRM_ADMIN within the tenant.
  2. You need fresh TOTP step-up verification (within 5 minutes).

API call:

POST /api/platform/impersonations

Required fields:

FieldRequiredDescription
targetUserIdYesUUID of the user to impersonate
tenantIdYesUUID of the tenant (must match your support session context)
reasonYesJustification for the impersonation (mandatory, cannot be empty)

What happens:

  1. The system validates your role, step-up status, and that the target user exists within the specified tenant.
  2. An ImpersonationSession record is created with a SHA-256 hashed session token.
  3. Your Redis session is updated with impersonationContext (target user info, expiry).
  4. An audit log entry is created: IMPERSONATION_STARTED with dual-identity logging (your ID as auditorUserId, the impersonated user's ID as actorId).

5.4 Impersonation Session Model

FieldDescription
idSession UUID
tenantIdThe tenant being accessed
adminUserIdYour platform admin user ID
impersonatedUserIdThe user you are impersonating
sessionTokenHashSHA-256 hash (never stored in plaintext)
reasonRequired justification text
ipAddressYour IP at session creation
userAgentYour browser at session creation
expiresAtFixed at 1 hour from creation
actionsPerformedCounter of actions taken during the session

5.5 Audit Implications

Every action performed during an impersonation session creates an audit log entry with:

  • actorId -- The impersonated user's ID (the user whose permissions you are using).
  • onBehalfOfId -- The impersonated user's ID.
  • auditorUserId -- Your platform admin user ID (the person actually performing the action).
  • impersonationSessionId -- The session ID for traceability.
  • supportSessionId -- The parent support session ID (if applicable).

This dual-identity logging ensures that audit reviewers can distinguish between actions taken by the actual user and actions taken by a platform operator on their behalf.

5.6 Ending an Impersonation Session

To exit impersonation:

  1. Call POST /api/platform/impersonations/exit.
  2. The ImpersonationSession record is updated with endedAt.
  3. Your Redis session is cleared of the impersonationContext.
  4. You return to the support session context (or platform context if no support session was active).

Impersonation sessions automatically expire after 1 hour.


6. System Monitoring

6.1 System Status Page

Navigate to /platform/system to see real-time health monitoring for all core services. The page displays a card for each service with:

  • Status indicator -- Green (healthy), yellow (degraded), red (unhealthy).
  • Latency -- Response time in milliseconds (for services that responded).
  • Last Check -- Timestamp of the most recent health probe.
  • Overall Status -- "All systems operational" or count of services experiencing issues.

6.2 Monitored Services

The health endpoint at GET /api/platform/health checks five core services:

ServiceHealth Check MethodWhat It Probes
PostgreSQLSELECT 1 queryDatabase connectivity and query latency
RedisHTTP probe to Redis endpointSession store and cache availability
SeaweedFSHTTP probe to S3 endpointDocument storage availability
QuickwitGET /api/v1/clusterFull-text search engine availability
TemporalSDK health check (gRPC)Workflow orchestration availability

All health checks run in parallel with a timeout guard (defined in TIMEOUTS.HEALTH_CHECK_MS).

6.3 Gatus Integration

Cadenora includes a Gatus service (gatus) for continuous health monitoring and alerting. Gatus provides:

  • Status page -- Publicly accessible uptime dashboard.
  • SMTP alerts -- Email notifications when services go down or recover.
  • Historical data -- Uptime history and incident tracking.

Gatus runs as a Docker service alongside the application stack.

6.4 Temporal UI

The Temporal UI (accessible via the temporal-ui service) provides detailed monitoring of workflow execution:

  • Workflow list -- All running and completed workflows with status.
  • Workflow detail -- Step-by-step execution history for each workflow.
  • Pending tasks -- Tasks waiting for worker pickup.
  • Activity history -- Detailed logs for each activity execution.

This is particularly useful for debugging provisioning failures, document processing issues, and invitation delivery problems.

6.5 Key Metrics to Monitor

MetricWhere to CheckAlert Threshold
Service health/platform/systemAny service unhealthy
Active support sessions/platform/supportUnusual number of concurrent sessions
Failed provisioning jobsTemporal UIAny workflow in FAILED state
Storage usage per tenantTenant detail pageApproaching storageQuotaGb
Pending invitationsTenant detail (invitation count)Growing count may indicate delivery issues
AI provider healthTenant AI settingsProvider connection failures or timeouts
AI rate limit exhaustionTenant AI settingsUsers frequently hitting rate limits
AI monthly spendTenant AI settingsApproaching or exceeding monthly budget

Note: AI features are configured per tenant. Each tenant can use the platform default provider or bring their own API key. Platform admins should be aware of AI cost tracking, especially for tenants using the platform default provider, as their usage contributes to the platform's aggregate AI spend.

6.6 Console Workspace

The Console is an internal operations dashboard deployed alongside the main Cadenora application. It provides operational visibility and management tools for the Cadenora platform team.

Architecture:

  • The Console is a separate pnpm workspace member within the Cadenora monorepo -- same git repository, independent build and deploy cycle.
  • It has zero cross-dependencies with the main application. Console packages do not import from the main app's src/ directory, and vice versa.

Components:

ComponentPackageFrameworkPort
Console Web@cadenora/console-webNext.js 14, React 18, TailwindCSS 3, Tanstack Query 53100 (dev)
Console API@cadenora/console-apiHono 4, Prisma 6 (10 models), ioredis 54000

Deployment:

  • Deployed to k3s in the cadenora-console namespace (separate from the main cadenora namespace).
  • Console Dockerfiles build from the monorepo root (required for turbo prune).
  • Build and deploy via console/scripts/deploy.sh deploy.

Documentation:

  • Developer guide: console/docs/DEVELOPER_GUIDE.md
  • User guide: console/docs/USER_GUIDE.md
  • Architecture: console/CADENORA_CONSOLE_ARCHITECTURE_V1.1.md

Dual Prisma isolation:

The Console API generates its Prisma client to src/generated/prisma (not @prisma/client). This prevents overwriting the main application's Prisma client types.


7. Security and Compliance

7.1 Five-Layer Defense Model

As a platform admin, you should understand the five layers that protect tenant data:

LayerComponentWhat It Does
0Plane Separation/platform/* vs /t/{slug}/* vs /i/{slug}/* -- physically separate URL namespaces
1URL + Session + ContextMiddleware extracts scope from URL, validates JWT session, loads tenant config
2ApplicationrequireApiAuth(), requireWriteAccess(), Zod validation, request.clone() before auth
3Database (RLS)PostgreSQL RLS via set_config('app.tenant_id'), composite PKs enforce tenant isolation
4StorageSeaweedFS keys prefixed with v1/{tenantId}/, server validates key structure
5SearchQuickwit tenant_id field with mandatory filter on all queries

7.2 Audit Log Access

Audit logs are accessible at two levels:

Platform level (aggregate):

  • Tenant detail page shows the last 20 audit log entries for a specific tenant (action, resource type, timestamp only -- no content details).

Tenant level (full detail, requires support session):

  • Enter a support session for the tenant.
  • Navigate to /t/{slug}/audit-logs.
  • Filter by date range, action type, user, or resource.
  • Export as CSV for regulatory inspection.

7.3 Cross-Tenant Event Review

The audit log model includes a tenantId field on every entry. For cross-tenant event review:

  1. Support session audit events include both tenantId and supportSessionId, making it possible to trace all actions performed during a specific support session across the audit log.
  2. Impersonation session events include impersonationSessionId and auditorUserId for the same purpose.
  3. Platform-level events (tenant creation, activation, suspension) are logged with the platform admin's identity.

7.4 Compliance Reporting

Cadenora supports two major Canadian regulatory frameworks:

NI 31-103 (Canadian Securities):

  • 7-year document retention minimum, enforced technically.
  • 1-year post-project-closure extension.
  • Legal hold overrides (documents preserved indefinitely until hold removed).
  • Retention enforcement via RetentionEnforcementWorkflow (Temporal).

PIPEDA (Privacy):

  • Mandatory MFA for admin roles (based on 23andMe precedent, PIPEDA Findings #2025-001).
  • Aggregate-only visibility for platform admins (data minimization).
  • Time-boxed support sessions with audit trails (justified access).
  • Data access, correction, and deletion request handling (30-day response window).

7.5 Security Alerts

Monitor for:

  • Unusual support session patterns -- Multiple concurrent sessions, sessions created outside business hours, sessions with unusual tenant targets.
  • Failed step-up attempts -- Multiple failed TOTP verifications may indicate compromised credentials.
  • Provisioning failures -- Failed workflows may indicate infrastructure issues or configuration drift.
  • Unhealthy services -- Any service on the System Status page showing degraded or unhealthy.

7.6 Token Security

All security-sensitive tokens use proper cryptographic handling:

Token TypeAlgorithmStorage
Support session tokensSHA-256 hashOnly hash stored in sessionTokenHash column
Impersonation session tokensSHA-256 hashOnly hash stored in sessionTokenHash column
Invitation tokensSHA-256 hashOnly hash stored; cleartext sent once via email
Share tokensAES-256-GCM encryptionEncrypted blob with configurable expiry
Session cookiesJWT (HS256)Minimal claims; full session in Redis

8. Configuration

8.1 Platform-Level Settings

Platform-level settings are managed via environment variables and the deployment configuration. These are not editable via the Platform Console UI:

SettingEnvironment VariableDescription
App URLNEXT_PUBLIC_APP_URLBase URL for the application
Session secretSESSION_SECRETJWT signing secret for session cookies
JWT secretJWT_SECRETJWT signing key for edge middleware
Auth secretAUTH_SECRETAuthentication secret for CadenoraAuth
Storage endpointSTORAGE_ENDPOINTInternal SeaweedFS endpoint
Public storage endpointSTORAGE_PUBLIC_ENDPOINTPublic-facing presigned URL endpoint
Quickwit endpointQUICKWIT_ENDPOINTFull-text search engine endpoint
Temporal addressTEMPORAL_ADDRESSWorkflow orchestration server
Redis URLREDIS_URLSession store and cache

8.2 Per-Tenant Configuration

Tenant configuration is managed via the TenantConfiguration model and can be viewed (but rarely modified) from the platform:

  • Industry Template -- Set at onboarding, immutable. Determines default categories, terminology, and theme.
  • Theme -- Can be changed by the tenant via Settings > Branding. Platform admins can override via API.
  • Terminology -- 14 dynamic label fields. Customizable by the tenant.
  • MFA Policy (mfaRequired) -- Whether MFA is required for all users in the tenant.
  • Password Policy (passwordExpireDays) -- Password expiration period.
  • Session Timeout (sessionTimeoutMinutes) -- Idle session timeout.
  • Storage Quota (storageQuotaGb) -- Maximum storage allocation.

To modify tenant configuration from the platform:

PATCH /api/platform/tenants/{tenantId}/configuration
Content-Type: application/json

{
  "themeId": "EXECUTIVE",
  "terminology": { ... }
}
  • Max Users (maxUsers) -- Maximum number of users for the tenant.
  • Onboarding Email Delay (onboardingEmailDelayHours) -- Delay before sending onboarding emails.

8.3 Default Templates

The five industry templates are defined in src/lib/config/industry-templates.ts. Each template specifies:

  • Default terminology (9 raw fields).
  • Default theme.
  • Default document categories (6 per template, plus the system "Uncategorized" category).

These templates are code-level constants, not runtime configuration. Modifying them requires a code change and redeployment.

8.4 Email Configuration

Email delivery is handled via SMTP (configured in environment variables) and orchestrated through Temporal workflows:

  • Invitation emails -- Triggered by SendInviteWorkflow.
  • Welcome emails -- Triggered during ProvisionTenantWorkflow.
  • Reminder emails -- Triggered by RecipientReminderWorkflow.
  • Password reset emails -- Triggered by the auth flow.

Email templates use the tenant's terminology variables for industry-appropriate language.

Email delivery is orchestrated through Temporal workflows. If emails fail, check the workflow status in Temporal UI for error details and retry information.


9. Operational Procedures

9.1 Onboarding a New Tenant

Complete procedure:

  1. Gather information from the client: organization name, desired subdomain, admin email, industry.
  2. Navigate to /platform/tenants/new.
  3. Fill in the organization name, subdomain, and admin email.
  4. Select the appropriate industry template (or leave blank for the tenant to choose during onboarding).
  5. Click "Create Tenant".
  6. From the tenant detail page, click "Activate Tenant".
  7. Monitor the provisioning workflow status (should complete within 30-60 seconds).
  8. Verify the admin received the setup-password email.
  9. Confirm the tenant admin can log in at https://{subdomain}.cadenora.com/auth/login.
  10. Record the onboarding in your operational log.

If provisioning fails:

  • Check Temporal UI for the failed workflow and its error details.
  • Common causes: subdomain already taken (race condition), database connectivity issue, email delivery failure.
  • The saga compensation should have rolled back partial state. Verify by checking the tenant detail page.
  • If cleanup is incomplete, contact the engineering team.

9.2 Resetting a User's Password

When the tenant admin is available:

  • Direct them to the user management page in their workspace (/t/{slug}/users).
  • They can trigger a password reset email from there.

When the tenant admin is unavailable:

  1. Create a SUPPORT_ADMIN session for the tenant.
  2. Navigate to /t/{slug}/users.
  3. Find the user.
  4. Trigger a password reset (sends a setup-password token email).
  5. End the support session.
  6. Log the action in your support ticket.

9.3 Investigating a Reported Issue

Standard investigation workflow:

  1. Create a READ_ONLY support session for the affected tenant.
  2. Navigate to the relevant area (e.g., document detail, project settings, user list).
  3. Check the audit log at /t/{slug}/audit-logs for relevant events.
  4. If you need to make changes, end the READ_ONLY session and create a DELEGATED_ADMIN session.
  5. Make the necessary changes (all changes are audit-logged).
  6. End the support session.
  7. Document findings and actions in the support ticket.

9.4 Handling Data Access Requests (PIPEDA)

When a user submits a data access request:

  1. Verify the requestor's identity through an independent channel (phone, video).
  2. Create a READ_ONLY support session for the tenant.
  3. Locate the user's data: profile, audit logs, documents uploaded by the user, project memberships.
  4. Generate a data export (if the tenant has this capability enabled).
  5. Deliver the export via a secure channel (encrypted download link, 7-day expiry).
  6. Log the request fulfillment in the audit trail.
  7. Respond within 30 days (PIPEDA requirement).

9.5 Handling Data Deletion Requests

  1. Verify the requestor's identity.
  2. Check for NI 31-103 retention obligations -- documents within the 7-year retention period cannot be deleted.
  3. Check for active legal holds -- held documents cannot be deleted by anyone.
  4. If deletion is blocked by regulatory retention, inform the user and offer anonymization instead.
  5. If deletion is permitted, proceed through the tenant's user management interface (requires SUPPORT_ADMIN session).
  6. Audit logs are retained but anonymized (user identity replaced with "Deleted User [uuid]").
  7. Respond within 30 days (PIPEDA requirement).

9.6 Emergency: Suspending a Compromised Tenant

If you suspect a tenant account is compromised:

  1. Navigate to the tenant detail page.
  2. Click "Suspend Tenant" -- this immediately blocks all logins.
  3. Create a READ_ONLY support session (suspension does not prevent support access).
  4. Review the audit log for suspicious activity.
  5. Check recent login events for unfamiliar IP addresses or user agents.
  6. If individual users are compromised, disable their accounts and revoke all sessions.
  7. Coordinate with the tenant admin (via a verified channel) before reactivating.
  8. Document the incident per the incident response procedure.

10. Troubleshooting

10.1 Cannot Access Platform Console

Symptom: Navigating to /platform/* redirects to /unauthorized.

Diagnosis:

  • Verify your user account has actorType: PLATFORM in the session.
  • Verify your role is one of PLATFORM_ADMIN, PLATFORM_SUPPORT, or PLATFORM_SECURITY.
  • Check that you authenticated via CadenoraAuth with the correct platform admin email.

Solution:

  • If your session is stale, log out and log back in.
  • If your role was recently assigned, the session may not reflect it yet. Log out, clear cookies, and log in again.
  • Check Redis connectivity and SESSION_SECRET / AUTH_SECRET env vars.

10.2 Support Session Creation Fails

Symptom: "Failed to create support session" error when clicking "New Support Session".

Diagnosis:

  • Check that TOTP step-up is working (your MFA code must be valid and recent).
  • Verify the target tenant exists and has a valid status.
  • Check the browser console for API response details.

Solution:

  • If step-up fails, verify your device clock is synchronized (TOTP is time-sensitive, +/- 30 seconds).
  • If the tenant ID is invalid, refresh the tenant list.
  • If the API returns 500, check application logs for database connectivity issues.

10.3 Tenant Provisioning Stuck in ACTIVATING

Symptom: Tenant stays in ACTIVATING status indefinitely.

Diagnosis:

  • Check Temporal UI for the ProvisionTenantWorkflow execution status.
  • Look for failed activities in the workflow history.
  • Common failure points: database connectivity issue (CreateAdminUser), email delivery failure (SendWelcomeEmail).

Solution:

  • Check database and Redis connectivity; the workflow should retry automatically on transient failures.
  • If a specific activity failed permanently, check the activity error message in Temporal UI.
  • If saga compensation ran, the tenant may have been rolled back to DRAFT. You can re-attempt activation.
  • If the state is inconsistent (partially provisioned), contact engineering for manual cleanup.

10.4 Service Shows Unhealthy on System Status

Symptom: One or more services show red "unhealthy" status.

Diagnosis by service:

ServiceCheckCommon Cause
PostgreSQLDatabase container running, connections availableContainer restart, disk full, connection pool exhausted
RedisRedis container running, memory availableOOM kill, container restart
SeaweedFSS3 endpoint responsiveContainer restart, disk full
QuickwitCluster API responsiveIndex corruption, container restart
TemporalSDK health check responsiveServer restart, worker disconnected

General solution:

  1. Check Docker container status: verify the service container is running.
  2. Check container logs for error messages.
  3. If a container crashed, check if it auto-restarted (Docker restart policy).
  4. For persistent issues, check disk space and memory on the host.

10.5 User Reports "Account Locked"

Symptom: User sees "Account locked due to too many failed login attempts."

Details:

  • Default lockout threshold: 5 failed attempts within 15 minutes.
  • Auto-unlock after 30 minutes.

Solution:

  1. If the user can wait, the account auto-unlocks after 30 minutes.
  2. For immediate unlock, enter a SUPPORT_ADMIN session for the tenant and unlock via user management.
  3. If repeated lockouts occur, investigate for potential brute-force attacks -- check audit logs for suspicious IP addresses.

10.6 Invitation Email Not Delivered

Symptom: Tenant admin reports that invitation emails are not being received.

Diagnosis:

  1. Check the Temporal SendInviteWorkflow status for the specific invitation.
  2. Verify SMTP configuration is correct in the environment.
  3. Check email delivery logs (if available).
  4. Ask the recipient to check spam/junk folders.

Solution:

  • If the workflow failed, check the error in Temporal UI and retry.
  • If SMTP is down, fix the configuration and the workflow should retry.
  • If the email was delivered but filtered, ask the recipient to whitelist @cadenora.com.
  • As a workaround, the tenant admin can resend the invitation (generates a fresh token and email).

10.7 Build or Deployment Issues

For general application issues:

bash
# Clear build cache and rebuild
rm -rf .next node_modules/.cache && pnpm install && pnpm build

# Fix rootless Docker health checks (Ubuntu 24.04+)
sudo ./scripts/fix-rootless-docker-healthcheck.sh

# Full environment reset (development only)
./scripts/manage-tunnel-env.sh stop && docker system prune -f && ./scripts/manage-tunnel-env.sh start

Remember: Never use docker compose directly on servers. Use ./scripts/deploy-demo.sh or ./scripts/deploy-from-registry.sh for deployments.


Appendix A: Platform API Reference

Authentication and Session

MethodEndpointPurpose
GET/api/platform/users/meGet current platform user info
GET/api/platform/healthSystem health check (all services)
GET/api/platform/diagnosticsSystem diagnostics
GET/api/platform/diagnostics/authAuthentication diagnostics

Tenant Management

MethodEndpointPurpose
GET/api/platform/tenantsList all tenants
POST/api/platform/tenantsCreate a new tenant (DRAFT)
GET/api/platform/tenants/{tenantId}Get tenant details
GET/api/platform/tenants/{tenantId}/statusGet tenant status
POST/api/platform/tenants/{tenantId}/activateActivate a DRAFT tenant
POST/api/platform/tenants/{tenantId}/suspendSuspend an ACTIVE tenant
PATCH/api/platform/tenants/{tenantId}/configurationUpdate tenant configuration
GET/api/platform/tenants/check-subdomainCheck subdomain availability
POST/api/platform/tenants/provisionProvision tenant (alias for activation workflow)
GET/api/platform/provisioning-jobs/{jobId}Get provisioning job status

User Management

MethodEndpointPurpose
GET/api/platform/usersList platform users
GET/api/platform/users/{id}Get user details

Support Sessions

MethodEndpointPurpose
POST/api/platform/support/sessionsCreate a support session
GET/api/platform/support/sessions/activeGet active support sessions
DELETE/api/platform/support/sessions/{sessionId}End (revoke) a support session

Impersonation

MethodEndpointPurpose
POST/api/platform/impersonationsStart an impersonation session
GET/api/platform/impersonations/activeGet active impersonation sessions
POST/api/platform/impersonations/exitEnd an impersonation session
DELETE/api/platform/impersonations/{sessionId}End an impersonation session by ID

Invitations

MethodEndpointPurpose
GET/api/platform/invitationsList platform invitations
GET/api/platform/invitations/{id}Get invitation details
POST/api/platform/invitations/{id}/resendResend an invitation

Analytics

MethodEndpointPurpose
GET/api/platform/analytics/redirects/statsRedirect analytics statistics
GET/api/platform/analytics/redirects/trendsRedirect analytics trends
GET/api/platform/analytics/redirects/top-pathsTop redirected paths

Appendix B: Data Visibility Quick Reference

Principle: Platform admins operate on the control plane. They see tenant metadata and aggregate counts. They never see individual client records, document content, or end-customer PII without an explicit support session.

Always visible:

  • Tenant name, subdomain, status, industry template, theme, admin email
  • Aggregate counts (users, projects, documents, client orgs, client members, invites)
  • Internal staff list (last 10, FIRM_ADMIN and PROJECT_MANAGER roles only)
  • Storage metrics (used vs. quota)
  • Security posture (MFA policy, password policy, session timeout)

Never visible without support session:

  • Individual client names, emails, or organization details
  • Document content, previews, or file names
  • Client-document access grants
  • Investor profiles (accreditation, preferences)
  • Invitation recipient emails

Requires SUPPORT_ADMIN for modification:

  • Tenant user accounts (create, disable, role change, MFA reset)
  • Tenant documents (upload, delete, change visibility)
  • Tenant projects (create, edit, delete)
  • Tenant settings (branding, categories, policies)

DocumentPathPurpose
Architecture Specdocs/architecture/CADENORA_ARCHITECTURE_V8.6.mdCanonical system architecture
Product & System Designdocs/CADENORA_PRODUCT_AND_SYSTEM_DESIGN.mdProduct-level design reference
Platform Admin Visibilitydocs/developer/PLATFORM_ADMIN_VISIBILITY.mdControl plane / data plane separation details
User Management Guidedocs/admin/USER_MANAGEMENT.mdUser lifecycle management
Compliance Guidedocs/admin/COMPLIANCE.mdNI 31-103 and PIPEDA compliance
Admin Documentation Indexdocs/admin/README.mdAdmin documentation hub
Firm Admin Guidedocs/guides/firm-admin-guide.mdTenant-level admin operations
Deployment Guidedocs/operations/DEPLOYMENT.mdDeployment procedures
Upload Fix Documentationdocs/developer/UPLOAD_FIX_DOCUMENTATION.mdBody clone pattern for POST routes

This document was compiled from the live codebase, platform admin pages, API routes, and architecture documentation. Last updated March 5, 2026. For the canonical architecture specification, see docs/architecture/CADENORA_ARCHITECTURE_V8.6.md.

Cadenora Documentation