# Data Aggregation Services

This directory contains services responsible for maintaining data consistency across related Firestore collections. These aggregation services are typically used by Cloud Functions that react to document changes (create/update/delete operations).

## Purpose

When a document is created, updated, or deleted in one collection, related documents in other collections often need to be updated to maintain data consistency and support efficient querying. For example:

- When a practitioner is updated, their information needs to be updated in associated clinics
- When a procedure is added, summaries need to be added to both practitioner and clinic documents
- When a clinic is deleted, related calendar events need to be canceled

Rather than embedding this logic in the main service classes, these aggregation services keep the concerns separate and can be independently triggered by Cloud Functions.

## Design Pattern

Each aggregation service:

1. Handles a specific domain entity (clinic, practitioner, procedure, etc.)
2. Contains methods organized by event type (creation, update, deletion)
3. Focuses solely on updating related collections
4. Uses transactions where appropriate to ensure consistency

## Available Aggregation Services

- `ClinicAggregationService`: Handles clinic-related aggregations
- `PractitionerAggregationService`: Handles practitioner-related aggregations
- `ProcedureAggregationService`: Handles procedure-related aggregations
- `PatientAggregationService`: Handles patient-related aggregations

## Implementation Notes

- These services are for admin/internal use only
- They operate with admin Firestore privileges
- They are designed for use by Cloud Functions, not directly by client applications
- They include detailed logging for monitoring and debugging

## Example Usage

In a Cloud Function:

```typescript
exports.onPractitionerUpdate = functions.firestore
  .document('practitioners/{practitionerId}')
  .onUpdate(async (change, context) => {
    const beforeData = change.before.data();
    const afterData = change.after.data();
    const practitionerId = context.params.practitionerId;

    // Only run aggregation if specific fields changed
    if (beforeData.basicInfo.firstName !== afterData.basicInfo.firstName ||
        beforeData.basicInfo.lastName !== afterData.basicInfo.lastName ||
        beforeData.basicInfo.profileImageUrl !== afterData.basicInfo.profileImageUrl) {

      const aggregationService = new PractitionerAggregationService();

      // Build doctorInfo object from updated data
      const doctorInfo = {
        id: practitionerId,
        name: `${afterData.basicInfo.firstName} ${afterData.basicInfo.lastName}`,
        photo: afterData.basicInfo.profileImageUrl || '',
        // other fields...
      };

      // Update practitioner info in all related clinics
      await aggregationService.updatePractitionerInfoInClinics(
        afterData.clinics,
        doctorInfo
      );

      // Update practitioner info in all related procedures
      await aggregationService.updatePractitionerInfoInProcedures(
        afterData.procedures,
        doctorInfo
      );
    }
  });
</rewritten_file>
```
