# Data Model: Dataset Lifecycle Workspace

## Entity Overview

```
GET /api/datasets?filter=all&page=1&page_size=10    GET /api/datasets/{id}
─────────────────────────────────────────────────────────────
DatasetsResponse              DatasetDetailResponse
├── datasets: DatasetItem[]   ├── ... (existing fields)
│   ├── id                     ├── metrics: MetricItem[]
│   ├── table_name             │   ├── id
│   ├── schema                 │   ├── metric_name
│   ├── database               │   ├── expression
│   ├── metric_count            │   ├── verbose_name
│   ├── mapped_fields          │   ├── description
│   └── last_task              │   └── metric_type
├── stats: StatsCounts         └── metric_count
│   ├── total
│   ├── unmapped_count
│   ├── mapped_count
│   └── linked_count
├── total, page, page_size,
│   total_pages (existing)
└── [unchanged pagination]

PUT /api/datasets/{id}/columns/{col_id}/description
PUT /api/datasets/{id}/metrics/{metric_id}/description
─────────────────────────────────────────────────────────────
Request:  ColumnDescriptionUpdate | MetricDescriptionUpdate
  { description: string }

Response: { success: true, description: string }
```

---

## Backend Pydantic Schemas (in `backend/src/api/routes/datasets.py`)

### MetricItem (new)
```python
class MetricItem(BaseModel):
    id: int
    metric_name: str
    expression: str | None = None
    verbose_name: str | None = None
    description: str | None = None
    metric_type: str | None = None
```

### StatsCounts (new)
```python
class StatsCounts(BaseModel):
    total: int                              # all datasets
    unmapped_count: int                     # mapped_fields.mapped == 0
    mapped_count: int                       # mapped_fields.mapped > 0
    linked_count: int                       # linked_dashboard_count > 0
```

### DatasetsResponse (modified)
```python
class DatasetsResponse(BaseModel):
    datasets: list[DatasetItem]
    stats: StatsCounts                      # NEW
    total: int
    page: int
    page_size: int
    total_pages: int
```

### DatasetDetailResponse (modified)
```python
class DatasetDetailResponse(BaseModel):
    # ... existing fields unchanged ...
    metrics: list[MetricItem]               # NEW
    metric_count: int                       # NEW
```

### ColumnDescriptionUpdate (new)
```python
class ColumnDescriptionUpdate(BaseModel):
    description: str
```

### MetricDescriptionUpdate (new)
```python
class MetricDescriptionUpdate(BaseModel):
    description: str
```

---

## Frontend Types (TypeScript / Svelte inferred)

```typescript
interface StatsCounts {
    total: number;
    unmapped_count: number;
    mapped_count: number;
    linked_count: number;
}

interface MetricItem {
    id: number;
    metric_name: string;
    expression?: string;
    verbose_name?: string;
    description?: string;
    metric_type?: string;
}

// UI-only state types (not in API)
type ColumnRow = {
    column_name: string;
    verbose_name?: string;
    type?: string;
    description?: string;
    is_dttm: boolean;
    is_active: boolean;
    id: number;
    isEditing?: boolean;   // UI state for inline edit
};

type MetricRow = {
    metric_name: string;
    expression?: string;
    verbose_name?: string;
    description?: string;
    metric_type?: string;
    id: number;
    isEditing?: boolean;   // UI state for inline edit
};

type StatsBarFilter = 'all' | 'unmapped' | 'mapped' | 'linked' | null;

// API query parameter for server-side filtering
// GET /api/datasets?filter=unmapped|mapped|linked|all&page=1&page_size=10
// When filter is active, backend filters full dataset list before pagination
```

---

## WebSocket Message

```json
{
  "type": "dataset.updated",
  "payload": {
    "env_id": "ss-dev",
    "dataset_ids": [32, 45, 78]
  }
}
```

---

## State Transitions

### Stats Bar Tile States
```
Idle → (click tile) → Active (highlighted, list filtered)
Active → (click same tile) → Idle (filter cleared)
Active → (click different tile) → Active (new tile, list re-filtered)
```

### Inline Edit States
```
Display → (click ✏️) → Editing (textarea visible)
Editing → (Save + API success) → Display (new description shown)
Editing → (Save + API error) → Editing (error message, textarea stays)
Editing → (Cancel) → Display (original description restored)
```

### Detail Panel States
```
NoSelection → (click card) → Loading → Loaded
Loaded → (click different card) → Loading → Loaded
Loaded → (deselect / bulk mode) → NoSelection
Loading → (API error) → Error → (Retry) → Loading
```

### Bulk Selection States
```
None → (check 1+ cards) → Selecting (bottom panel hidden for 1)
Selecting → (check 2+ cards) → BulkActive (bottom panel visible)
BulkActive → (uncheck all) → None
BulkActive → (click action) → Modal → (complete) → None
```
