Files
ss-tools/specs/030-dataset-lifecycle-workspace/data-model.md
2026-05-20 09:59:11 +03:00

183 lines
5.0 KiB
Markdown

# Data Model: Dataset Lifecycle Workspace
## Entity Overview
```
GET /api/datasets GET /api/datasets/{id}
─────────────────────────────────────────────────────────────
DatasetsResponse DatasetDetailResponse
├── datasets: DatasetItem[] ├── ... (existing fields)
│ ├── id ├── metrics: MetricItem[]
│ ├── table_name │ ├── id
│ ├── schema │ ├── metric_name
│ ├── database │ ├── expression
│ ├── mapped_fields │ ├── verbose_name
│ └── last_task │ ├── description
├── stats: StatsCounts │ └── metric_type
│ ├── total └── metric_count
│ ├── 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;
```
---
## WebSocket Message
```json
{
"type": "dataset.updated",
"payload": {
"env_id": "ss-dev",
"dataset_ids": ["242377ce-bdbd-42df-85da-ca1340a72fbb"]
}
}
```
---
## 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
```