# UX Reference: Dataset Lifecycle Workspace

**Feature Branch**: `030-dataset-lifecycle-workspace`
**Created**: 2026-05-19
**Status**: Draft

## 1. User Persona & Context

- **Who is the user?**: Data Analyst / Data Engineer, работающий с датасетами Apache Superset через ss-tools. Технически подкован, понимает структуру таблиц, колонок и метрик.
- **What is their goal?**: Быстро оценить состояние датасетов (какие без маппинга, какие без описаний), просмотреть детали конкретного датасета, отредактировать описания колонок/метрик, запустить bulk-операции (маппинг, генерация документации).
- **Context**: Работает в браузере на десктопе (1920×1080) или ноутбуке (1366×768). Может использовать планшет. Всегда в рамках выбранного окружения (dev/staging/prod).

## 2. The "Happy Path" Narrative

Аналитик открывает страницу датасетов и сразу видит Stats Bar: 142 датасета всего, 38 без маппинга, 89 с маппингом, 12 связаны с дашбордами. Он кликает «⚠️ Без маппинга» — Stats Bar подсвечивает метрику, фронтенд отправляет запрос `?filter=unmapped&page=1`, сервер возвращает отфильтрованные 38 датасетов с серверной пагинацией. Выбирает первый датасет в списке — DatasetHub фетчит `GET /api/datasets/{id}`, справа без перезагрузки открывается детальная панель: хедер с именем таблицы и схемой, секция колонок с progress-индикаторами описаний, секция метрик. Видит колонку без описания, кликает «✏️ Добавить описание» — появляется textarea, вводит описание, сохраняет через `PUT /api/datasets/{id}/columns/{col_id}/description`. Описание мгновенно отображается. Затем выделяет 3 датасета через чекбоксы, внизу появляется панель — запускает «Маппинг колонок» для всех трёх одним кликом.

## 3. Interface Mockups

### UI Layout & Flow

**Page**: `/datasets`

- **Layout**: Двухколоночный split-view (40/60) на десктопе. При < 768px — одноколоночный с slide-over для деталей.
- **Key Elements**:
    - **Stats Bar**: 4 метрики в строке вверху, каждая — кнопка-фильтр (`<button>` с `aria-pressed`) с иконкой, числом и подписью. Активная метрика подсвечена (primary background).
    - **Left Panel**: Список карточек датасетов с поиском и пагинацией. Каждая карточка содержит чекбокс.
    - **Right Panel**: Детальная панель с хедером, таблицами колонок/метрик, связанными дашбордами.
    - **Bulk Action Bar**: Fixed bottom panel, slides up when 2+ datasets selected.
    - **Map Columns Modal**: Reused from existing implementation.
    - **Generate Docs Modal**: Reused from existing implementation.
- **Contract Mapping**:
    - **`@UX_STATE`**:
        - `Loading` — Stats Bar skeleton + Left panel skeleton (5 placeholder cards).
        - `Loaded` — Stats Bar with counts + left panel cards + right panel placeholder ("Выберите датасет").
        - `Loaded-Detail` — Right panel filled with dataset details.
        - `Filtered` — Stats Bar with active metric highlighted + filtered card list.
        - `Selecting` — Checkboxes checked on cards + floating bulk action panel visible.
        - `Editing` — Inline textarea open on a column/metric row.
        - `Saving` — Textarea disabled with spinner, save button shows "Сохранение...".
        - `Error-Detail` — Right panel error banner with retry.
        - `Error-List` — Full page error banner with retry.
    - **`@UX_FEEDBACK`**:
        - Stats Bar metric click → instant list filter + metric highlight.
        - Dataset card click → right panel loads detail (spinner then content).
        - Save description → "✓ Сохранено" toast + textarea closes.
        - Save error → red border on textarea + "⚠️ Ошибка сохранения" below.
        - Slide-over (mobile) → smooth slide from right with backdrop.
    - **`@UX_RECOVERY`**:
        - API error in right panel → click "Retry" to reload dataset detail.
        - API error in list → click "Retry" to reload full list.
        - Save succeeds regardless of concurrent edits (last-write-wins); next detail load shows current value.
        - Network offline → show offline banner, auto-retry on reconnect.
    - **`@UX_REACTIVITY`**: 
        - `$state` for: `selectedDatasetId`, `activeFilter`, `selectedIds`, `editingCell`
        - `$derived` for: `filteredDatasets` (based on `activeFilter` + `searchQuery`)
        - `$effect` for: loading dataset detail when `selectedDatasetId` changes
        - `$props` for: reusable card component (`DatasetCard.svelte`), detail panel component (`DatasetDetailPanel.svelte`)
- **States**:
    - **Idle/Default**: Stats Bar shows counts, left panel shows paginated cards, right panel shows "Выберите датасет для просмотра деталей" placeholder.
    - **Loading**: Skeleton loaders for Stats Bar (4 count placeholders), Left Panel (5 card placeholders with shimmer), Right Panel placeholder.
    - **Success**: All data loaded, interactions responsive (filter, select, edit).
    - **Error/Degraded**: If list fails → full page error. If detail fails → error in right panel only, list still navigable.

## 4. The "Error" Experience

**Philosophy**: Не просто сообщить об ошибке, а дать пользователю путь к восстановлению.

**Semantic Requirement**: Every documented failure path here should map to `@UX_RECOVERY` and, where relevant, `@UX_FEEDBACK` in the generated component contracts.

### Scenario A: API 503 (Superset недоступен)

- **User Action**: Открывает страницу датасетов.
- **System Response**:
    - (UI) Full-page error banner: "⚠️ Не удалось загрузить датасеты. Сервер Superset временно недоступен." + кнопка "Повторить".
    - Stats Bar скрыт или показывает "--" для всех метрик.
- **Recovery**: Кнопка "Retry" перезагружает список. Автоматический retry через 30s.

### Scenario B: Ошибка загрузки деталей датасета

- **User Action**: Кликает на карточку датасета в левой панели.
- **System Response**:
    - (UI) В правой панели появляется ошибка: "⚠️ Не удалось загрузить детали датасета." + кнопка "Повторить".
    - Левая панель остаётся рабочей — пользователь может выбрать другой датасет.
- **Recovery**: Клик "Retry" перезагружает детали. Список остаётся навигабельным.

### Scenario C: Ошибка сохранения описания (inline edit)

- **User Action**: Вводит описание в textarea, нажимает "Сохранить".
- **System Response**:
    - (UI) Красная обводка textarea + сообщение под ней: "⚠️ Ошибка сохранения. Проверьте соединение и попробуйте снова."
    - Textarea остаётся открытой с введённым текстом (не теряется).
- **Recovery**: Повторное нажатие "Сохранить" либо "Отмена" для выхода без сохранения.

### Scenario D: Ресайз окна между десктопом и мобильным

- **User Action**: Изменяет ширину окна браузера между ≥768px и <768px.
- **System Response**:
    - (UI) Выбранный датасет сохраняется при любом ресайзе.
    - При сжатии до <768px: если детальная панель открыта — она становится slide-over (открытым). Список занимает 100% ширины.
    - При расширении до ≥768px: split-view восстанавливается. Если slide-over был закрыт — правая панель показывает последний выбранный датасет или placeholder «Выберите датасет».
- **Recovery**: Не требуется — состояние сохраняется.

- **User Action**: Сохраняет описание.
- **System Response**: Last-write-wins — последнее сохранение перезаписывает предыдущее. Конфликт не детектируется (ETag/блокировки — out of scope). При успешном сохранении сразу показывается актуальное значение.
- **Recovery**: Не требуется. Если другой пользователь перезаписал описание — при следующей загрузке деталей датасета отобразится его версия.

## 5. Tone & Voice

- **Style**: Concise, technical, task-oriented. Русский и английский.
- **Terminology**: "Датасет" (не "таблица" или "источник данных"), "Маппинг" (не "сопоставление"), "Колонка" (не "столбец" или "поле"), "Метрика" (не "показатель").
