# VS-07: Risk Alerts — Vertical Slice Specification

**Domain:** Risk & Portfolio Management  
**Capability:** Monitor thresholds (concentration, VAR, volatility); trigger escalations  
**User Goal:** "I need automatic alerts when portfolio risk exceeds safe limits"

---

## Non-Goals

- Custom alert rules (simple threshold library only)
- SMS/Email delivery (platform abstraction, VS-09)
- Alert aggregation/deduplication (separate)
- AI-based anomaly detection (future)

---

## Requirements

### Functional

| Req ID | Description | RBAC | SLA | Evidence |
|--------|-------------|------|-----|----------|
| **ALERT-001** | Monitor thresholds: concentration >60%, VAR >20%, volatility >30% | System | Real-time | Trigger job after VS-05 metrics |
| **ALERT-002** | GET /api/portfolio/{id}/alerts | DataReader | <100ms | JSON array of active alerts |
| **ALERT-003** | Support threshold configuration (per portfolio) | PortfolioManager | N/A | UI form (VS-08 FE) |
| **ALERT-004** | Alert escalation: initial → warning → critical | System | <5min | Progressive notification |
| **ALERT-005** | Soft-delete completed alerts (preserved for audit) | System | N/A | WHERE removed_at IS NULL |

### Non-Functional

- **Accuracy:** Threshold breach detected within 5 minutes of metric update
- **Latency:** Alert query <100ms, trigger <5min
- **Noise:** False-positive rate <1%
- **Audit:** Full alert lifecycle tracked (created → escalated → resolved)

---

## State Transitions

```
Portfolio Risk Metrics (from VS-05)
  ↓ threshold evaluation
Threshold Breached?
  ├─ No → status=OK
  └─ Yes → create Alert(status=Initial)
    ↓ after 2 min (no resolution)
    Alert escalate to status=Warning
    ↓ after 3 min (still breached)
    Alert escalate to status=Critical
    ↓ user resolves
    Alert(status=Resolved, removed_at=now)
```

**Frequency:** Real-time (evaluated after each metric update)  
**Escalation:** Progressive (Initial → Warning → Critical over 5min)  
**Resolution:** Manual or automatic (threshold back to safe level)

---

## Data & API Contracts

### GET /api/portfolio/{portfolioId}/alerts

**Response (200 OK):**
```json
{
  "portfolioId": "550e8400-e29b-41d4-a716-446655440001",
  "activeAlerts": [
    {
      "alertId": "550e8400-e29b-41d4-a716-446655440008",
      "thresholdType": "concentration",
      "thresholdName": "Top-5 Holdings > 60%",
      "currentValue": 65.2,
      "threshold": 60,
      "severity": "Warning",
      "triggeredAt": "2026-08-05T10:30:00Z",
      "escalatedAt": "2026-08-05T10:35:00Z",
      "message": "Top 5 holdings now represent 65.2% of portfolio (threshold: 60%)"
    },
    {
      "alertId": "550e8400-e29b-41d4-a716-446655440009",
      "thresholdType": "volatility",
      "thresholdName": "Annualized Volatility > 30%",
      "currentValue": 31.5,
      "threshold": 30,
      "severity": "Initial",
      "triggeredAt": "2026-08-05T10:45:00Z",
      "escalatedAt": null,
      "message": "Portfolio volatility now 31.5% (threshold: 30%)"
    }
  ],
  "resolvedAlerts": [
    {
      "alertId": "550e8400-e29b-41d4-a716-446655440010",
      "thresholdType": "concentration",
      "status": "Resolved",
      "resolvedAt": "2026-08-05T10:50:00Z",
      "duration": 20
    }
  ]
}
```

### Events

**RiskAlertTriggered:**
```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440011",
  "eventType": "RiskAlertTriggered",
  "portfolioId": "550e8400-e29b-41d4-a716-446655440001",
  "alertId": "550e8400-e29b-41d4-a716-446655440008",
  "thresholdType": "concentration",
  "severity": "Warning",
  "currentValue": 65.2,
  "threshold": 60,
  "triggeredAt": "2026-08-05T10:30:00Z",
  "correlationId": "alert-2026-08-05-001"
}
```

**RiskAlertResolved:**
```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440012",
  "eventType": "RiskAlertResolved",
  "alertId": "550e8400-e29b-41d4-a716-446655440008",
  "resolvedAt": "2026-08-05T10:50:00Z",
  "durationMinutes": 20,
  "correlationId": "alert-2026-08-05-001"
}
```

---

## Threshold Library (Defaults)

| Type | Default Threshold | Severity Escalation |
|------|-------------------|---------------------|
| Concentration (top-5) | 60% | Initial (0min) → Warning (2min) → Critical (5min) |
| VAR-95 | 20% of portfolio | Initial (0min) → Warning (2min) → Critical (5min) |
| Volatility (annual) | 30% | Initial (0min) → Warning (3min) → Critical (7min) |
| Single position | 40% | Initial (0min) → Critical (5min) |

---

## RBAC & Authorization

| Operation | Role | Condition |
|-----------|------|-----------|
| VIEW alerts | DataReader | Own portfolio only |
| CONFIGURE thresholds | PortfolioManager | Own portfolio only |
| RESOLVE alert | PortfolioManager | Own portfolio + manual action |
| CREATE portfolio-level rules | RiskHead | Organization-wide override |

---

## Testing Strategy

1. **Unit:** Threshold evaluation (8 tests)
   - Concentration > threshold → alert triggered
   - VAR increase → alert escalated
   - Threshold back to safe → alert resolved

2. **Integration:** DB persistence (3 tests)
   - Insert alert
   - Escalate alert
   - Soft-delete resolved alert

3. **E2E:** API + escalation flow (3 tests)
   - Threshold breach → alert appears in API
   - Time-based escalation (Initial → Warning → Critical)
   - Resolution clears alert

4. **Golden:** Escalation timing (2 tests)
   - Known breach scenario → correct escalation at 2min, 5min
   - False positive rate <1%

---

## Assumptions

- Thresholds are portfolio-specific (configurable per portfolio)
- Escalation uses wall-clock time (not trading time)
- Automatic resolution when metric returns to safe level
- No deduplication (same threshold breach = one alert)

---

## Vertical Slice Boundary

✅ **In Scope:** Threshold evaluation + alert lifecycle + event publishing  
❌ **Out of Scope:** Notification delivery (VS-09), alert aggregation, custom ML rules

**Rationale:** Provides alert infrastructure; notifications/delivery separate concern
