# Ads Analytics Service Architecture / Kiến Trúc Dịch Vụ Phân Tích Quảng Cáo

## Tổng Quan / Overview

```mermaid
graph TB
    subgraph "Data Sources"
        SERV[ads-serving-service]
        TRACK[ads-tracking-service]
        MGR[ads-manager-service]
    end
    
    subgraph "ads-analytics-service"
        API[API Layer]
        INGEST[Ingestion Workers]
        AGG[Aggregation Engine]
        STORE[(ClickHouse/TimescaleDB)]
    end
    
    subgraph "Output"
        DASH[Dashboard API]
        REPORT[Report Generator]
        EXPORT[Export Service]
    end
    
    SERV -->|Impressions/Clicks| INGEST
    TRACK -->|Conversions| INGEST
    MGR -->|Campaign Metadata| API
    
    INGEST --> STORE
    STORE --> AGG
    AGG --> DASH
    AGG --> REPORT
    REPORT --> EXPORT
```

## Domain Aggregates

### MetricsAggregate
- **CampaignMetrics** (Root): Impressions, Clicks, CTR, Spend
- **AdSetMetrics**: Per-targeting performance
- **AdMetrics**: Per-creative performance

### ReportAggregate
- **Report** (Root): Custom/scheduled reports
- **ReportSchedule**: Daily, Weekly, Monthly
- **ReportExport**: CSV, Excel, PDF formats

### InsightAggregate
- **AudienceInsight**: Demographics of reached users
- **PerformanceInsight**: Optimization recommendations

## Metrics Calculation

| Metric | Formula | Description |
|--------|---------|-------------|
| **CTR** | Clicks / Impressions | Click-through rate |
| **CPC** | Spend / Clicks | Cost per click |
| **CPM** | (Spend / Impressions) × 1000 | Cost per mille |
| **CPA** | Spend / Conversions | Cost per acquisition |
| **ROAS** | Revenue / Spend | Return on ad spend |
| **Frequency** | Impressions / Reach | Avg views per user |

## Data Flow

```
┌─────────────────────────────────────────────────────────────────┐
│                     DATA PIPELINE                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Raw Events        Aggregation         Query                    │
│  (RabbitMQ)        (Background)        (API)                    │
│                                                                  │
│  Impression ──┐                                                  │
│               │    ┌──────────────┐    ┌──────────────┐         │
│  Click ───────┼───►│  Hourly      │───►│  Campaign    │         │
│               │    │  Rollup      │    │  Dashboard   │         │
│  Conversion ──┘    └──────────────┘    └──────────────┘         │
│                           │                                      │
│                           ▼                                      │
│                    ┌──────────────┐    ┌──────────────┐         │
│                    │  Daily       │───►│  Reports     │         │
│                    │  Summary     │    │  Export      │         │
│                    └──────────────┘    └──────────────┘         │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

## Database Schema (ClickHouse)

```sql
-- Raw events (high write throughput)
CREATE TABLE ad_events (
    event_id UUID,
    event_type Enum8('impression' = 1, 'click' = 2, 'conversion' = 3),
    ad_id UUID,
    campaign_id UUID,
    advertiser_id UUID,
    user_id String,
    cost Decimal(18, 6),
    event_time DateTime
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(event_time)
ORDER BY (campaign_id, event_time);

-- Hourly aggregates (fast queries)
CREATE MATERIALIZED VIEW campaign_metrics_hourly
ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(hour)
ORDER BY (campaign_id, hour)
AS SELECT
    campaign_id,
    toStartOfHour(event_time) AS hour,
    countIf(event_type = 'impression') AS impressions,
    countIf(event_type = 'click') AS clicks,
    countIf(event_type = 'conversion') AS conversions,
    sumIf(cost, event_type IN ('impression', 'click')) AS spend
FROM ad_events
GROUP BY campaign_id, hour;
```

## API Endpoints

### Metrics
| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/api/v1/ads-analytics/campaigns/{id}/metrics` | Campaign metrics |
| `GET` | `/api/v1/ads-analytics/campaigns/{id}/breakdown` | Breakdown by dimension |

### Reports
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/v1/ads-analytics/reports` | Create custom report |
| `POST` | `/api/v1/ads-analytics/reports/schedule` | Schedule report |
| `GET` | `/api/v1/ads-analytics/reports/{id}/export` | Export report |

## Query Patterns

```csharp
/// <summary>
/// EN: Get campaign metrics with breakdown.
/// VI: Lấy metrics chiến dịch với breakdown.
/// </summary>
public async Task<CampaignMetricsDto> GetMetricsAsync(
    Guid campaignId,
    DateRange dateRange,
    BreakdownDimension? breakdown = null)
{
    var query = _clickHouse.Query<MetricRow>(@"
        SELECT 
            campaign_id,
            sum(impressions) as impressions,
            sum(clicks) as clicks,
            sum(spend) as spend
        FROM campaign_metrics_hourly
        WHERE campaign_id = @campaignId
          AND hour BETWEEN @start AND @end
        GROUP BY campaign_id
    ");
    
    return await query.ExecuteAsync();
}
```

## Integration

| Service | Integration Type | Purpose |
|---------|-----------------|---------|
| **ads-serving-service** | RabbitMQ Consumer | Impression/Click events |
| **ads-tracking-service** | RabbitMQ Consumer | Conversion events |
| **ads-manager-service** | HTTP Client | Campaign metadata |
