Portal
›
Database Architecture
1. Database Executive Summary
AIUsagePlatform employs a shared-schema multi-tenant architecture using SQL Server with Entity Framework Core. The database is designed for SaaS scale with tenant isolation enforced through OrganizationId propagation across all tenant-scoped entities.
✅ Shared-Schema Model Single database, multi-tenant tables
✅ EF Core 8 Migrations, LINQ, strong typing
✅ OrganizationId Isolation Tenant boundary on all tables
⚠️ 10M+ Session Rows High-write table needs partitioning
SaaS Data Architecture Overview
SaaS Database Architecture Strategy
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ SHARED-SCHEMA MULTI-TENANT MODEL │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ SQL SERVER DATABASE │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ TENANT-SCOPED TABLES (OrganizationId FK required) │ │ │
│ │ │ ───────────────────────────────────────────────────────── │ │ │
│ │ │ │ │ │
│ │ │ Organizations ──► Users ──► Sessions ──► AIUsageLogs │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ ▼ ▼ ▼ │ │ │
│ │ │ └─────────► AuditLogs ──► ExportJobs ──► Analytics │ │ │
│ │ │ │ │ │
│ │ │ KEY RULE: EVERY query MUST include OrganizationId filter │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ GLOBAL TABLES (No OrganizationId - Shared definitions) │ │ │
│ │ │ ───────────────────────────────────────────────────────── │ │ │
│ │ │ │ │ │
│ │ │ • Plans (Subscription tiers) │ │ │
│ │ │ • SystemRoles (Admin, Manager, User definitions) │ │ │
│ │ │ • ApplicationCatalog (Known AI applications) │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ TENANT ISOLATION STRATEGY: │
│ ───────────────────────── │
│ │
│ Organization A (org-a-123) Organization B (org-b-456) │
│ ┌────────────────────────┐ ┌────────────────────────┐ │
│ │ WHERE OrganizationId = │ │ WHERE OrganizationId = │ │
│ │ 'org-a-123' │ │ 'org-b-456' │ │
│ │ │ │ │ │
│ │ Users: Alice, Bob │ │ Users: Carol, Dave │ │
│ │ Sessions: 1,245 │ │ Sessions: 892 │ │
│ │ AI Usage: 45h │ │ AI Usage: 23h │ │
│ │ │ │ │ │
│ │ NEVER sees Org B data │ │ NEVER sees Org A data │ │
│ └────────────────────────┘ └────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
2. Core Entity Relationship Analysis
Entity Relationship Hierarchy
Complete Entity Relationship Map
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ ENTITY RELATIONSHIP HIERARCHY │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ORGANIZATION (Root Entity) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ PK: Id, Name, ApiKey, PlanType, Status, CreatedAt ││
│ │ FK: PlanId ──► Plans ││
│ │ TENANT SCOPE: Global table (no org filter needed for lookup) ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ │ 1:N │
│ ▼ │
│ USERS │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ PK: Id, Email, Name, PasswordHash, Role, Status ││
│ │ FK: OrganizationId (REQUIRED) ││
│ │ TENANT SCOPE: WHERE OrganizationId = @orgId ││
│ │ RELATIONSHIPS: ││
│ │ • 1:N ──► Sessions ││
│ │ • 1:N ──► AuditLogs ││
│ │ • 1:N ──► ExportJobs ││
│ │ • M:N ──► Roles (via UserRoles junction) ││
│ │ • 1:N ──► Devices (optional) ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ │ 1:N │
│ ▼ │
│ SESSIONS (High-Volume Table) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ PK: Id, UserId, OrganizationId, StartTime, EndTime, Duration ││
│ │ FK: UserId, OrganizationId (both REQUIRED) ││
│ │ TENANT SCOPE: WHERE OrganizationId = @orgId ││
│ │ RELATIONSHIPS: ││
│ │ • 1:N ──► AIUsageLogs ││
│ │ • 1:N ──► ApplicationUsage ││
│ │ • 1:N ──► WebsiteUsage ││
│ │ • 1:N ──► ProductivityIntervals ││
│ │ • N:1 ──► Devices (optional) ││
│ │ VOLUME: 10M+ rows, fastest growing ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ │ 1:N │
│ ▼ │
│ AI_USAGE_LOGS (High-Volume Child Table) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ PK: Id, SessionId, OrganizationId, Application, Domain, Duration ││
│ │ FK: SessionId, OrganizationId (both REQUIRED) ││
│ │ TENANT SCOPE: WHERE OrganizationId = @orgId ││
│ │ RELATIONSHIPS: ││
│ │ • N:1 ──► Sessions ││
│ │ • Can aggregate to SessionDailySummary ││
│ │ VOLUME: 20M+ rows (2x sessions) ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ PARALLEL ENTITIES (Same hierarchy level): │
│ │
│ DEVICES │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ PK: Id, OrganizationId, UserId, Name, Type, AgentVersion, LastSeen ││
│ │ FK: OrganizationId, UserId (optional) ││
│ │ TENANT SCOPE: WHERE OrganizationId = @orgId ││
│ │ RELATIONSHIPS: 1:N ──► Sessions (optional) ││
│ │ ⚠️ ASSUMPTION: Device table structure inferred from dashboard usage ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ ROLES & PERMISSIONS (RBAC System) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ ROLES Table: ││
│ │ PK: Id, Name, OrganizationId (nullable for system roles), Level ││
│ │ FK: OrganizationId (null = system role, set = custom role) ││
│ │ ││
│ │ USERROLES Junction Table: ││
│ │ PK: (UserId, RoleId) composite ││
│ │ FK: UserId ──► Users, RoleId ──► Roles ││
│ │ TENANT SCOPE: Implicit via User.OrganizationId ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ AUDIT & REPORTING ENTITIES: │
│ │
│ AUDIT_LOGS │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ PK: Id, OrganizationId, UserId, Action, EntityType, Timestamp ││
│ │ FK: OrganizationId, UserId (optional) ││
│ │ TENANT SCOPE: WHERE OrganizationId = @orgId ││
│ │ VOLUME: 5M+ rows, compliance-critical ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ EXPORT_JOBS │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ PK: Id, OrganizationId, UserId, Status, Format, FileUrl, CreatedAt ││
│ │ FK: OrganizationId, UserId ││
│ │ TENANT SCOPE: WHERE OrganizationId = @orgId ││
│ │ RELATIONSHIPS: Triggered by Reporting queries ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ SESSION_DAILY_SUMMARY (Aggregation Table) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ PK: Id, OrganizationId, Date, TotalSessions, TotalDuration ││
│ │ FK: OrganizationId ││
│ │ TENANT SCOPE: WHERE OrganizationId = @orgId ││
│ │ PURPOSE: Pre-aggregated analytics for dashboard performance ││
│ │ UPDATED BY: Background job or trigger ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Entity Detail Specifications
Entity
Purpose
Primary Key
Foreign Keys
Tenant Scoped
Volume (Est)
Indexing Needs
Organizations
Tenant root
Id (Guid)
PlanId ──► Plans
❌ Global
1,000
PK, IX_Name, IX_ApiKey
Users
User accounts
Id (Guid)
OrganizationId (req)
✅ Yes
50,000
PK, IX_OrgId, IX_Email
Sessions
Session tracking
Id (Guid)
UserId, OrgId (req)
✅ Yes
10,000,000
PK, IX_OrgId_StartTime (MISSING)
AIUsageLogs
AI activity details
Id (Guid)
SessionId, OrgId (req)
✅ Yes
20,000,000
PK, IX_SessionId, IX_OrgId
">
AuditLogs
Compliance trail
Id (Guid)
OrgId, UserId (opt)
✅ Yes
5,000,000
PK, IX_OrgId_Timestamp (MISSING)
Devices
Device registry
Id (Guid)
OrgId, UserId (opt)
✅ Yes
100,000
PK, IX_OrgId, IX_LastSeen
Roles
RBAC definitions
Id (Guid)
OrgId (nullable)
✅ Optional
100
PK, IX_Name, IX_OrgId
ExportJobs
Export tracking
Id (Guid)
OrgId, UserId
✅ Yes
50,000
PK, IX_OrgId_Status
SessionDailySummary
Pre-aggregated stats
Id (Guid)
OrgId
✅ Yes
500,000
PK, IX_OrgId_Date (UNIQUE)
Plans
Subscription tiers
Id (Guid)
None
❌ Global
10
PK only
│ │
3. Agent Onboarding Data Flow
Onboarding Architecture Overview
The onboarding flow establishes the complete data chain from organization registration to active agent runtime. Understanding this flow is critical for troubleshooting, security, and scaling.
Complete Onboarding Sequence
Agent Onboarding Data Flow
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 1: ORGANIZATION SETUP │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Step 1: Organization Registration │
│ ───────────────────────────────────────────────────────────────────────── │
│ │
│ Actor: SuperAdmin or Self-Registration │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ INSERT INTO Organizations ││
│ │ (Id, Name, PlanId, ApiKey, Status, CreatedAt) ││
│ │ VALUES ││
│ │ (NEWID(), 'Acme Corp', 'plan-pro', NEWID(), 'Active', GETUTCDATE())││
│ │ ││
│ │ OUTPUT: OrganizationId = 'org-abc-123' (propagates to all child rows) ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ INSERT INTO Subscriptions ││
│ │ (Id, OrganizationId, PlanId, StartDate, EndDate, Status) ││
│ │ VALUES ││
│ │ (NEWID(), 'org-abc-123', 'plan-pro', GETDATE(), DATEADD(year,1,...),││
│ │ 'Active') ││
│ │ ││
│ │ TENANT ISOLATION: OrganizationId = 'org-abc-123' established ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 2: ADMIN USER CREATION │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Step 2: Admin User Registration │
│ ───────────────────────────────────────────────────────────────────────── │
│ │
│ Actor: Registration Form → AuthController │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ INSERT INTO Users ││
│ │ (Id, OrganizationId, Email, Name, PasswordHash, Role, Status) ││
│ │ VALUES ││
│ │ (NEWID(), 'org-abc-123', 'admin@acme.com', 'Admin User', ││
│ │ HASH('password'), 'Admin', 'Active') ││
│ │ ││
│ │ CRITICAL: OrganizationId FK links user to org (tenant isolation) ││
│ │ OUTPUT: UserId = 'usr-def-456' ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ INSERT INTO UserRoles (Junction Table) ││
│ │ SELECT NEWID(), 'usr-def-456', Id, GETUTCDATE() ││
│ │ FROM Roles WHERE Name = 'Admin' AND OrganizationId IS NULL ││
│ │ ││
│ │ RBAC: User now has Admin role (level 50) ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ JWT GENERATION (AuthController) ││
│ │ ───────────────────────────────────────────────────────────────────── ││
│ │ ││
│ │ Claims: ││
│ │ { ││
│ │ "sub": "usr-def-456", ← UserId for self-scoped queries ││
│ │ "org": "org-abc-123", ← CRITICAL: OrganizationId for tenant ││
│ │ "role": "Admin", ││
│ │ "email": "admin@acme.com" ││
│ │ } ││
│ │ ││
│ │ TOKEN USAGE: Every API call includes org claim for tenant isolation ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 3: DEVICE & AGENT SETUP │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Step 3: Device Registration │
│ ───────────────────────────────────────────────────────────────────────── │
│ │
│ Actor: Admin Portal → Device Installation │
│ ⚠️ ASSUMPTION: Device table exists (inferred from dashboard top-devices) │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ INSERT INTO Devices (⚠️ ASSUMED STRUCTURE) ││
│ │ (Id, OrganizationId, UserId, Name, Type, AgentVersion, LastSeen) ││
│ │ VALUES ││
│ │ (NEWID(), 'org-abc-123', 'usr-def-456', 'Alice-PC', 'Windows', ││
│ │ '1.2.3', GETUTCDATE()) ││
│ │ ││
│ │ OUTPUT: DeviceId = 'dev-ghi-789' ││
│ │ TENANT ISOLATION: OrganizationId = 'org-abc-123' ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ Step 4: Agent Installation & Authentication │
│ ───────────────────────────────────────────────────────────────────────── │
│ │
│ Actor: Agent Installer → Agent Onboarding API │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ AGENT INSTALLATION FLOW: ││
│ │ ││
│ │ 1. Agent installer prompts for credentials ││
│ │ 2. User enters: admin@acme.com / password ││
│ │ 3. Agent calls: POST /api/auth/login ││
│ │ 4. Receives JWT with org claim: "org-abc-123" ││
│ │ 5. Agent stores: OrgId + ApiKey locally (encrypted) ││
│ │ 6. Agent registers device: POST /api/devices/register ││
│ │ 7. Database: Devices row created with OrgId = 'org-abc-123' ││
│ │ ││
│ │ DEVICE LINKAGE: ││
│ │ Device.OrganizationId = 'org-abc-123' ││
│ │ Device.UserId = 'usr-def-456' (optional, can be null) ││
│ │ Device.ApiKey = Org.ApiKey (for future auth) ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 4: RUNTIME ACTIVATION │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Step 5: Agent Runtime Data Ingestion Begins │
│ ───────────────────────────────────────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ ONGOING: Session Creation ││
│ │ ───────────────────────────────────────────────────────────────────── ││
│ │ ││
│ │ TRIGGER: Agent detects user activity ││
│ │ ││
│ │ INSERT INTO Sessions ││
│ │ (Id, UserId, OrganizationId, DeviceId, StartTime, Status) ││
│ │ VALUES ││
│ │ (NEWID(), 'usr-def-456', 'org-abc-123', 'dev-ghi-789', ││
│ │ GETUTCDATE(), 'Active') ││
│ │ ││
│ │ CRITICAL: OrganizationId = 'org-abc-123' on EVERY session row ││
│ │ This enables tenant isolation for all child entities ││
│ │ OUTPUT: SessionId = 'ses-jkl-012' ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ ONGOING: AI Usage Detection ││
│ │ ───────────────────────────────────────────────────────────────────── ││
│ │ ││
│ │ TRIGGER: Agent detects AI application (ChatGPT, Copilot, etc.) ││
│ │ ││
│ │ INSERT INTO AIUsageLogs ││
│ │ (Id, SessionId, OrganizationId, Application, Domain, StartTime) ││
│ │ VALUES ││
│ │ (NEWID(), 'ses-jkl-012', 'org-abc-123', 'ChatGPT', ││
│ │ 'chat.openai.com', GETUTCDATE()) ││
│ │ ││
│ │ TENANT PROPAGATION: Session.OrganizationId ──► AIUsageLogs.OrgId ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ AGGREGATION: Dashboard Data ││
│ │ ───────────────────────────────────────────────────────────────────── ││
│ │ ││
│ │ BACKGROUND JOB (nightly): ││
│ │ UPDATE SessionDailySummary ││
│ │ SET TotalSessions = (SELECT COUNT(*) FROM Sessions ││
│ │ WHERE OrganizationId = 'org-abc-123' ││
│ │ AND CAST(StartTime AS DATE) = @date) ││
│ │ WHERE OrganizationId = 'org-abc-123' AND Date = @date ││
│ │ ││
│ │ DASHBOARD QUERY: ││
│ │ SELECT * FROM SessionDailySummary ││
│ │ WHERE OrganizationId = 'org-abc-123' ││
│ │ ORDER BY Date DESC ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Onboarding Data Flow Summary
Phase
Tables Modified
OrganizationId Propagation
Critical For
1. Organization Setup
Organizations, Subscriptions
Root entity created (OrgId = source)
Tenant identity
2. Admin Creation
Users, UserRoles
User.OrganizationId = Org.Id
Access control
3. Device Setup
Devices (⚠️ assumed)
Device.OrganizationId = Org.Id
Agent runtime
4. Runtime Activation
Sessions, AIUsageLogs
Session.OrgId ──► AIUsageLogs.OrgId
Data isolation
4. Agent Runtime Data Pipeline
Runtime Data Ingestion Architecture
The agent continuously streams activity data to the API. Understanding the data pipeline is critical for performance tuning, troubleshooting, and scaling.
Runtime Data Flow Architecture
Agent Runtime Data Pipeline
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ AGENT RUNTIME LAYER │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ AGENT (Desktop Application) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ MONITORING MODULES: ││
│ │ ───────────────────────────────────────────────────────────────────── ││
│ │ ││
│ │ 1. Activity Tracker ││
│ │ • Detects active window ││
│ │ • Tracks idle time ││
│ │ • Records application usage ││
│ │ ││
│ │ 2. AI Detection Engine ││
│ │ • Monitors browser URLs (ChatGPT, Claude, Copilot) ││
│ │ • Detects AI desktop apps ││
│ │ • Captures AI usage duration ││
│ │ ││
│ │ 3. Sync Engine ││
│ │ • Batches events locally │
│ │ • Uploads to API every 30 seconds │
│ │ • Handles offline buffering │
│ │ ││
│ │ AUTHENTICATION: ││
│ │ • Stores JWT (refresh periodically) │
│ │ • Includes OrgId in API calls │
│ │ • Device fingerprint for verification │
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ │ HTTP/HTTPS │
│ ▼ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ API INGESTION LAYER │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ AGENT API ENDPOINTS (⚠️ ASSUMED - Inferred from data flow) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ ││
│ │ POST /api/agent/session/start ││
│ │ Body: { deviceId, userId, startTime, organizationId } ││
│ │ Response: { sessionId } ││
│ │ Action: INSERT INTO Sessions ││
│ │ ││
│ │ POST /api/agent/activity ││
│ │ Body: { sessionId, application, windowTitle, timestamp } ││
│ │ Action: INSERT INTO ApplicationUsage (⚠️ assumed table) ││
│ │ ││
│ │ POST /api/agent/ai-usage ││
│ │ Body: { sessionId, aiApplication, domain, duration } ││
│ │ Action: INSERT INTO AIUsageLogs ││
│ │ TENANT CHECK: JWT org claim must match session.OrganizationId ││
│ │ ││
│ │ POST /api/agent/heartbeat ││
│ │ Body: { deviceId, timestamp, status } ││
│ │ Action: UPDATE Devices SET LastSeen = GETUTCDATE() ││
│ │ ││
│ │ POST /api/agent/session/end ││
│ │ Body: { sessionId, endTime, totalDuration, aiUsageTime } ││
│ │ Action: UPDATE Sessions SET EndTime = @endTime, Status = 'Completed' ││
│ │ ││
│ │ ⚠️ NOTE: These agent endpoints are INFERRED from data structures. ││
│ │ Actual endpoint names may differ. ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ DATABASE STORAGE LAYER │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ RAW DATA TABLES (High Write Volume) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ ││
│ │ Sessions (10M+ rows, growing) ││
│ │ ┌─────────────────────────────────────────────────────────────────┐ ││
│ │ │ PK: Id, UserId, OrganizationId, DeviceId, StartTime, EndTime │ ││
│ │ │ Status: 'Active' | 'Completed' | 'Idle' │ ││
│ │ │ │ ││
│ │ │ INDEX: IX_Sessions_OrgId_StartTime (⚠️ MISSING - HIGH PRIORITY)│ ││
│ │ │ │ ││
│ │ │ QUERY PATTERN: │ ││
│ │ │ SELECT * FROM Sessions │ ││
│ │ │ WHERE OrganizationId = @orgId │ ││
│ │ │ AND StartTime BETWEEN @from AND @to │ ││
│ │ └─────────────────────────────────────────────────────────────────┘ ││
│ │ ││
│ │ AIUsageLogs (20M+ rows, 2x sessions) ││
│ │ ┌─────────────────────────────────────────────────────────────────┐ ││
│ │ │ PK: Id, SessionId, OrganizationId, Application, Domain │ ││
│ │ │ Duration: AI usage time in seconds │ ││
│ │ │ │ ││
│ │ │ TENANT ISOLATION: │ ││
│ │ │ WHERE OrganizationId = @orgId ← ALWAYS required │ ││
│ │ └─────────────────────────────────────────────────────────────────┘ ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ AGGREGATION TABLES (Background Process) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ ││
│ │ SessionDailySummary (500K rows) ││
│ │ ┌─────────────────────────────────────────────────────────────────┐ ││
│ │ │ PK: Id, OrganizationId, Date │ ││
│ │ │ TotalSessions: COUNT from Sessions │ ││
│ │ │ TotalDuration: SUM(Duration) from Sessions │ ││
│ │ │ TotalAIUsage: SUM(AIUsageTime) from Sessions │ ││
│ │ │ │ ││
│ │ │ UPDATED BY: Nightly background job or SQL trigger │ ││
│ │ │ │ ││
│ │ │ DASHBOARD QUERY (Fast): │ ││
│ │ │ SELECT Date, TotalSessions, TotalAIUsage │ ││
│ │ │ FROM SessionDailySummary │ ││
│ │ │ WHERE OrganizationId = @orgId │ ││
│ │ │ ORDER BY Date DESC │ ││
│ │ └─────────────────────────────────────────────────────────────────┘ ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ DASHBOARD & REPORTING LAYER │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ADMIN DASHBOARD QUERY FLOW: │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ ││
│ │ 1. ORGANIZATION SCOPED (Fast - Pre-aggregated): ││
│ │ GET /api/admindashboard ││
│ │ → SELECT * FROM SessionDailySummary ││
│ │ WHERE OrganizationId = @orgId (from JWT) ││
│ │ → Returns: Daily totals for last 30 days ││
│ │ ││
│ │ 2. USER ANALYTICS (Slower - Raw data): ││
│ │ GET /api/analytics/user/{id} ││
│ │ → SELECT * FROM Sessions ││
│ │ WHERE OrganizationId = @orgId AND UserId = @userId ││
│ │ → JOIN AIUsageLogs ON SessionId ││
│ │ → ⚠️ Can be slow without IX_OrgId_StartTime ││
│ │ ││
│ │ 3. TOP USERS (Aggregated): ││
│ │ GET /api/admindashboard/top-users ││
│ │ → SELECT UserId, SUM(Duration) as TotalTime ││
│ │ FROM Sessions ││
│ │ WHERE OrganizationId = @orgId ││
│ │ GROUP BY UserId ││
│ │ ORDER BY TotalTime DESC ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────────────────┘
5. Analytics & Reporting Database Flow
Analytics Pipeline Architecture
Analytics flow from raw data ingestion to dashboard visualization and report generation.
Analytics Data Pipeline
Analytics & Reporting Database Dependencies
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ RAW DATA SOURCES (Real-time Write) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Agent ──► Sessions ──► AIUsageLogs ──► ApplicationUsage ──► WebsiteUsage │
│ (10M rows) (20M rows) (⚠️ assumed) (⚠️ assumed) │
│ │
│ Characteristics: │
│ • High write frequency (every 30 seconds per active device) │
│ • INSERT-heavy │
│ • OrganizationId required on every row │
│ • No UPDATE (immutable log pattern) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│
│ Background Aggregation
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ SUMMARY TABLES (Pre-aggregated) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ SessionDailySummary │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ ││
│ │ AGGREGATION LOGIC (Nightly Job): ││
│ │ ───────────────────────────────────────────────────────────────────── ││
│ │ ││
│ │ INSERT INTO SessionDailySummary ││
│ │ (Id, OrganizationId, Date, TotalSessions, TotalDuration, ││
│ │ TotalAIUsage, ActiveUsers) ││
│ │ SELECT ││
│ │ NEWID(), ││
│ │ OrganizationId, ││
│ │ CAST(StartTime AS DATE), ││
│ │ COUNT(*), ││
│ │ SUM(Duration), ││
│ │ SUM(AIUsageTime), ││
│ │ COUNT(DISTINCT UserId) ││
│ │ FROM Sessions ││
│ │ WHERE StartTime >= @yesterday AND StartTime < @today ││
│ │ GROUP BY OrganizationId, CAST(StartTime AS DATE) ││
│ │ ││
│ │ ⚠️ PERFORMANCE RISK: Without IX_Sessions_OrgId_StartTime, ││
│ │ this query scans millions of rows. ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ Benefits of Summary Tables: │
│ • Dashboard queries: O(30) rows vs O(1M) raw rows │
│ • Report generation: Seconds vs minutes │
│ • Cross-tenant analytics: Fast aggregation across orgs │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│
│ Query
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ DASHBOARD & REPORTING CONSUMERS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Dashboard ──► SessionDailySummary (Fast) │
│ │ │
│ ├── Top Users ──► Sessions (Slower) │
│ ├── AI Analytics ──► AIUsageLogs (Medium) │
│ └── Trends ──► TimeAggregationController (Pre-aggregated) │
│ │
│ Reports ──► ExportJobs ──► Background Processing │
│ │ │
│ ├── AI Usage Report ──► AIUsageLogs + Sessions │
│ ├── Organization Report ──► SessionDailySummary + Users │
│ └── Comprehensive Report ──► All tables JOINed │
│ │
│ ⚠️ REPORTING BOTTLENECK: Large date ranges hit raw tables │
│ Solution: Use SessionDailySummary for >30 day ranges │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Reporting Dependencies Table
Report Type
Primary Tables
Query Complexity
Performance Strategy
Risk At Scale
Daily Dashboard
SessionDailySummary
Simple SELECT
Pre-aggregated (30 rows)
✅ Low
Weekly Trends
SessionDailySummary
GROUP BY week
Pre-aggregated (7 rows)
✅ Low
Top Users
Sessions
GROUP BY UserId
Needs IX_OrgId_StartTime
⚠️ Medium
AI Domain Analysis
AIUsageLogs
JOIN Sessions
Index on OrgId + Domain
⚠️ Medium
Custom Date Range Export
Sessions + AIUsageLogs
Complex JOIN + date filter
Requires partitioning
🔴 High
Cross-tenant SuperAdmin Report
All tenant tables
Multiple aggregations
Read replica required
🔴 High
6. Tenant Isolation Database Review
Tenant Isolation Strategy
OrganizationId propagation ensures complete data separation between tenants in the shared-schema model.
OrganizationId Propagation Flow
OrganizationId Propagation & Tenant Isolation
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ ORGANIZATIONID PROPAGATION CHAIN │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ROOT: Organizations.Id = 'org-abc-123' │
│ │ │
│ ├──► Users.OrganizationId = 'org-abc-123' │
│ │ ├──► Sessions.OrganizationId = 'org-abc-123' │
│ │ │ ├──► AIUsageLogs.OrganizationId = 'org-abc-123' │
│ │ │ ├──► ApplicationUsage.OrganizationId = 'org-abc-123'│
│ │ │ └──► WebsiteUsage.OrganizationId = 'org-abc-123' │
│ │ │ │
│ │ ├──► AuditLogs.OrganizationId = 'org-abc-123' │
│ │ ├──► ExportJobs.OrganizationId = 'org-abc-123' │
│ │ └──► Devices.OrganizationId = 'org-abc-123' │
│ │ │
│ └──► SessionDailySummary.OrganizationId = 'org-abc-123' │
│ │
│ RULE: Every query MUST include: WHERE OrganizationId = @orgId │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ TENANT ISOLATION ENFORCEMENT LAYERS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ LAYER 1: JWT Claims (Trusted Source) │
│ ───────────────────────────────────────────────────────────────────────── │
│ JWT: { "org": "org-abc-123", "role": "Admin" } │
│ ↓ │
│ │
│ LAYER 2: Middleware Extraction │
│ ───────────────────────────────────────────────────────────────────────── │
│ MultiTenantIsolationMiddleware: │
│ • Extracts OrganizationId from JWT │
│ • Attaches to HttpContext │
│ • Validates organization exists & active │
│ ↓ │
│ │
│ LAYER 3: Controller Enforcement │
│ ───────────────────────────────────────────────────────────────────────── │
│ BaseApiController.GetCurrentOrganizationId(): │
│ • Returns OrganizationId from JWT claim │
│ • All controllers inherit this method │
│ ↓ │
│ │
│ LAYER 4: Repository Filtering │
│ ───────────────────────────────────────────────────────────────────────── │
│ Repository Pattern: │
│ _dbContext.Sessions │
│ .Where(s => s.OrganizationId == orgId) ← CRITICAL FILTER │
│ .Where(predicate) │
│ .ToListAsync(); │
│ ↓ │
│ │
│ LAYER 5: Database Query (Final Enforcement) │
│ ───────────────────────────────────────────────────────────────────────── │
│ Generated SQL: │
│ SELECT * FROM Sessions │
│ WHERE OrganizationId = 'org-abc-123' ← Database-level filter │
│ AND StartTime > @date │
│ │
│ DEFENSE IN DEPTH: 5 layers of OrganizationId enforcement │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Tables Requiring OrganizationId
Table
OrganizationId Required
FK Constraint
Index Present
Risk If Missing
Users
✅ REQUIRED
FK ──► Organizations
IX_Users_OrganizationId
🔴 Cross-tenant data leak
Sessions
✅ REQUIRED
FK ──► Organizations
⚠️ Basic only
🔴 Critical data leak
AIUsageLogs
✅ REQUIRED
FK ──► Organizations
IX_AIUsageLogs_OrgId
🔴 AI usage data leak
AuditLogs
✅ REQUIRED
FK ──► Organizations
⚠️ Missing timestamp index
🔴 Compliance violation
ExportJobs
✅ REQUIRED
FK ──► Organizations
IX_ExportJobs_OrgId
🔴 Data export leak
SessionDailySummary
✅ REQUIRED
FK ──► Organizations
⚠️ Missing composite
⚠️ Analytics leak
Plans
❌ NOT REQUIRED
None
PK only
✅ N/A (Global)
SystemRoles
❌ NOT REQUIRED
None
PK only
✅ N/A (Global)
7. Database Scaling Review
Scaling Strategy & Bottlenecks
Current state and future scaling recommendations for enterprise deployment.
High-Volume Table Analysis
Table
Current Volume
Growth Rate
Write Pattern
Query Pattern
Scaling Risk
Sessions
10M rows
+500K/month
High INSERT
Date range queries
🔴 Critical (no partitioning)
AIUsageLogs
20M rows
+1M/month
High INSERT
JOIN with Sessions
🔴 Critical (child of Sessions)
AuditLogs
5M rows
+200K/month
Medium INSERT
Timestamp queries
⚠️ Medium (compliance retention)
SessionDailySummary
500K rows
+1K/day
Batch INSERT
PK lookup
✅ Low (aggregation)
Users
50K rows
+2K/month
Low INSERT
Email lookup
✅ Low
Scaling Recommendations
Database Scaling Strategy
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ IMMEDIATE (0-3 months) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. ADD COMPOSITE INDEXES (Critical) │
│ ───────────────────────────────────────────────────────────────────── │
│ │
│ CREATE INDEX IX_Sessions_OrgId_StartTime │
│ ON Sessions (OrganizationId, StartTime) │
│ INCLUDE (Duration, AIUsageTime, UserId); │
│ │
│ Impact: 80% reduction in analytics query time │
│ Effort: 2 hours (online index creation) │
│ │
│ 2. ADD AUDIT LOG INDEX │
│ ───────────────────────────────────────────────────────────────────── │
│ │
│ CREATE INDEX IX_AuditLogs_OrgId_Timestamp │
│ ON AuditLogs (OrganizationId, Timestamp); │
│ │
│ Impact: Audit log queries < 100ms │
│ Effort: 1 hour │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ SHORT-TERM (3-6 months) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 3. TABLE PARTITIONING (High Volume Tables) │
│ ───────────────────────────────────────────────────────────────────── │
│ │
│ Sessions Table: │
│ • Partition by StartTime (monthly) │
│ • Current: 10M rows → Future: 100M+ rows │
│ • Query pruning: Only scan relevant partitions │
│ │
│ Implementation: │
│ CREATE PARTITION FUNCTION pfn_Sessions (DATETIME2) │
│ AS RANGE RIGHT FOR VALUES ('2026-01-01', '2026-02-01', ...); │
│ │
│ Impact: Maintains performance at 100M+ rows │
│ Effort: 2 days (requires maintenance window) │
│ │
│ 4. READ REPLICAS FOR ANALYTICS │
│ ───────────────────────────────────────────────────────────────────── │
│ │
│ • Configure SQL Server Always On read replica │
│ • Route dashboard/reporting queries to replica │
│ • Keep primary for writes (Sessions, AIUsageLogs) │
│ │
│ Impact: Offload 70% of read traffic from primary │
│ Effort: 3 days (infrastructure setup) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ LONG-TERM (6-12 months) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 5. REDIS CACHING LAYER │
│ ───────────────────────────────────────────────────────────────────── │
│ │
│ • Cache dashboard aggregates (SessionDailySummary) │
│ • Cache user lists for organization │
│ • TTL: 5 minutes for dashboard data │
│ │
│ 6. ANALYTICS WAREHOUSE (OLAP) │
│ ───────────────────────────────────────────────────────────────────── │
│ │
│ • ETL raw data to columnar store (Azure Synapse / Snowflake) │
│ • Complex analytics queries run on warehouse │
│ • Keep 90 days hot data in SQL Server │
│ • Archive older data to warehouse │
│ │
│ 7. DATA ARCHIVAL STRATEGY │
│ ───────────────────────────────────────────────────────────────────── │
│ │
│ Sessions: │
│ • > 2 years: Move to cold storage (Azure Blob) │
│ • > 5 years: Delete (compliance dependent) │
│ │
│ AuditLogs: │
│ • Keep 7 years (compliance requirement) │
│ • Partition by year for efficient queries │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
8. Database Security Review
Security Considerations
Data protection, compliance, and tenant isolation security analysis.
Security Risk Assessment
Risk Area
Current State
Risk Level
Mitigation
Password Storage
PasswordHash (BCrypt/Argon2 assumed)
✅ Low
Never store plaintext
JWT Secrets
RS256 signing (private key)
✅ Low
Secure key storage
API Keys
Organizations.ApiKey (plaintext?)
⚠️ Medium
Hash ApiKey in DB
Tenant Isolation
OrganizationId enforced in all queries
✅ Low
Middleware validation
Audit Trail
AuditLogs table exists
⚠️ Medium
Enable for all actions
SQL Injection
EF Core parameterized queries
✅ Low
Avoid raw SQL
Data Retention
No automated purge
🔴 High
Implement archival jobs
GDPR & Compliance Requirements
✅ Right to Access
Users can access their own data through API endpoints. Organization admins can export organization data via ExportJobs.
✅ Right to Rectification
User profile data can be updated via UsersManagementController. Organization settings editable by admins.
⚠️ Right to Erasure
Soft delete implemented. Hard delete requires manual process. Automated data purging not implemented.
✅ Data Portability
JSON/CSV export available via ExportJobsController. GDPR-compliant export format.
9. Future Enterprise Database Architecture
Future Architecture Recommendations
Strategic database improvements for enterprise scale and advanced analytics.
Event-Driven Analytics Architecture
Future Enterprise Database Architecture
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ CURRENT: Direct Write Architecture │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Agent ──► API ──► SQL Server (Sessions, AIUsageLogs) │
│ │ │
│ └──► Background Job ──► SessionDailySummary │
│ │
│ Limitations: │
│ • High write load on SQL Server │
│ • Analytics queries impact transactional performance │
│ • No real-time streaming │
│ • Scaling bottleneck at 100M+ rows │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
↓
│ Future Evolution
↓
┌─────────────────────────────────────────────────────────────────────────────┐
│ FUTURE: Event-Driven Analytics Architecture │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ AGENT LAYER │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ Agent ──► API Gateway ││
│ │ │ ││
│ │ ├──► [FAST PATH] ──► SQL Server (Hot Data 90 days) ││
│ │ │ ││
│ │ └──► [EVENT STREAM] ──► Redis Streams / Kafka ││
│ │ │ ││
│ └─────────────────────────────────────────┼───────────────────────────────┘│
│ │ │
│ ▼ │
│ EVENT PROCESSING LAYER │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ Stream Consumers: ││
│ │ ───────────────────────────────────────────────────────────────────── ││
│ │ ││
│ │ 1. Real-time Aggregator ──► Redis (Dashboard cache) ││
│ │ 2. Analytics Processor ──► ClickHouse / Druid (OLAP) ││
│ │ 3. Audit Archiver ──► Long-term storage (Blob) ││
│ │ 4. ML Feature Store ──► Feature extraction for ML ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ QUERY LAYER │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ ││
│ │ Dashboard Queries: ││
│ │ • Real-time: Redis cache (< 10ms) ││
│ │ • Historical: ClickHouse OLAP (< 100ms) ││
│ │ ││
│ │ Ad-hoc Analytics: ││
│ │ • ClickHouse SQL interface ││
│ │ • Columnar compression (10x storage efficiency) ││
│ │ ││
│ │ Audit & Compliance: ││
│ │ • Azure Blob / S3 (cheap long-term storage) ││
│ │ • 7-year retention ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ BENEFITS: │
│ • SQL Server write load reduced 80% │
│ • Analytics queries don't impact transactions │
│ • Real-time dashboard updates via Redis │
│ • OLAP queries 100x faster for large datasets │
│ • 10x storage cost reduction for historical data │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Technology Stack Recommendations
Component
Current
Future (6-12 months)
Justification
Primary Database
SQL Server
SQL Server + Read Replicas
Scale reads, keep writes
Cache Layer
None
Redis
Dashboard performance
Analytics Warehouse
SQL Server
ClickHouse / BigQuery
OLAP performance
Event Streaming
None
Redis Streams / Kafka
Real-time processing
Archival Storage
SQL Server
Azure Blob / S3
Cost reduction
Search
SQL LIKE
Elasticsearch
Full-text search