# Analytics Service Architecture

## Overview

The Analytics Service uses a **hybrid approach** combining **pre-computed analytics** (stored in Firestore) with **on-demand calculation** (fallback). This architecture optimizes for:

- **Performance**: Fast reads from pre-computed data
- **Cost**: Reduced Firestore reads and compute time
- **Flexibility**: Can still calculate on-demand when needed

## Architecture Components

### 1. Cloud Functions (Pre-computation)

**Location**: `Cloud/functions/src/analytics/computeAnalytics.ts`

**Schedule**: Runs every 12 hours via Cloud Scheduler

**What it does**:
- Queries all appointments for each clinic
- Computes analytics for multiple periods (daily, weekly, monthly, yearly, all_time)
- Stores computed analytics in Firestore subcollections

**Storage Structure**:
```
clinics/{clinicBranchId}/
  └── analytics/
      ├── dashboard/
      │   └── {period}/
      │       └── current
      ├── clinic/
      │   └── {period}/
      │       └── current
      ├── practitioners/
      │   └── {period}/
      │       └── {practitionerId}
      ├── procedures/
      │   └── {period}/
      │       └── {procedureId}
      ├── time_efficiency/
      │   └── {period}/
      │       └── current
      ├── revenue/
      │   └── {period}/
      │       └── current
      ├── cancellations/
      │   └── {period}/
      │       └── clinic
      └── no_shows/
          └── {period}/
              └── clinic
```

### 2. Analytics Service (Client-side)

**Location**: `Api/src/services/analytics/analytics.service.ts`

**Behavior**:
1. **First**: Tries to read from stored analytics
2. **Checks**: If data is fresh (within maxCacheAgeHours, default 12 hours)
3. **Falls back**: Calculates on-demand if:
   - No stored data exists
   - Data is stale (older than maxCacheAgeHours)
   - `useCache: false` is specified

### 3. Storage Types

**Location**: `Api/src/types/analytics/stored-analytics.types.ts`

Defines types for stored analytics documents, including metadata about when and how they were computed.

## Data Flow

### Pre-computation Flow (Cloud Function)

```
Cloud Scheduler (every 12 hours)
  ↓
computeAnalyticsForAllClinics()
  ↓
For each clinic:
  ├── Compute dashboard analytics
  ├── Compute clinic analytics
  ├── Compute practitioner analytics (for each practitioner)
  ├── Compute procedure analytics (for each procedure)
  ├── Compute time efficiency metrics
  ├── Compute revenue metrics
  ├── Compute cancellation metrics
  └── Compute no-show metrics
  ↓
Store in Firestore subcollections
```

### Client Read Flow

```
Client requests analytics
  ↓
AnalyticsService.getDashboardData()
  ↓
Check stored analytics?
  ├── Yes → Read from Firestore
  │   ├── Fresh? → Return cached data ✅
  │   └── Stale? → Calculate on-demand
  └── No → Calculate on-demand
```

## Benefits

### Performance
- **Fast reads**: Single document read vs. querying hundreds/thousands of appointments
- **Reduced latency**: Pre-computed data returns instantly
- **Scalable**: Works efficiently even with large datasets

### Cost Optimization
- **Fewer reads**: 1 read vs. potentially hundreds/thousands
- **Reduced compute**: Calculations run server-side, not on every client request
- **Predictable costs**: Fixed cost per clinic per period

### Flexibility
- **On-demand fallback**: Can still calculate when needed
- **Custom date ranges**: Can override cached data for specific queries
- **Real-time option**: Can disable caching for live data

## Usage Examples

### Using Pre-computed Analytics (Default)

```typescript
// Automatically uses cached data if available and fresh
const dashboard = await analyticsService.getDashboardData(
  { clinicBranchId: 'clinic-123' },
  { start: new Date('2024-01-01'), end: new Date('2024-12-31') }
);
```

### Forcing On-demand Calculation

```typescript
// Bypass cache and calculate on-demand
const dashboard = await analyticsService.getDashboardData(
  { clinicBranchId: 'clinic-123' },
  { start: new Date('2024-01-01'), end: new Date('2024-12-31') },
  { useCache: false }
);
```

### Custom Cache Age

```typescript
// Use cache if data is less than 6 hours old (instead of default 12)
const dashboard = await analyticsService.getDashboardData(
  { clinicBranchId: 'clinic-123' },
  { start: new Date('2024-01-01'), end: new Date('2024-12-31') },
  { maxCacheAgeHours: 6 }
);
```

## Configuration

### Cloud Function Schedule

Edit `Cloud/functions/src/analytics/computeAnalytics.ts`:

```typescript
schedule: "every 12 hours" // Change to "every 6 hours", "every 24 hours", etc.
```

### Default Cache Age

Edit `Api/src/services/analytics/utils/stored-analytics.utils.ts`:

```typescript
maxCacheAgeHours = 12 // Change default cache age
```

## Monitoring

### Cloud Function Logs

Check Cloud Function logs for:
- Computation success/failure
- Processing time per clinic
- Errors during computation

### Firestore Usage

Monitor Firestore reads:
- Pre-computed reads: 1 per analytics request
- On-demand reads: Variable (depends on appointment count)

## Future Enhancements

1. **Incremental Updates**: Only recompute changed periods
2. **Real-time Triggers**: Update analytics when appointments change
3. **Aggregated Views**: Pre-compute common dashboard views
4. **Historical Snapshots**: Keep historical analytics for trend analysis
5. **Multi-clinic Aggregation**: Aggregate analytics across clinic groups

