# API Contracts: Superset-Style UX Redesign

**Feature**: 019-superset-ux-redesign
**Date**: 2026-02-09

## Overview

This document defines the API contracts for new endpoints required by the Resource-Centric UI. All endpoints follow existing patterns in the codebase.

## New Endpoints

### 1. Dashboard Hub API

#### GET /api/dashboards

**Purpose**: Fetch list of dashboards from a specific environment for the Dashboard Hub grid.

**Query Parameters**:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| env_id | string | Yes | Environment ID to fetch dashboards from |
| search | string | No | Filter by title/slug |

**Response**:
```json
{
  "dashboards": [
    {
      "id": "uuid-string",
      "title": "Sales Report",
      "slug": "sales-2023",
      "url": "/superset/dashboard/sales-2023",
      "git_status": {
        "branch": "main",
        "sync_status": "OK" | "DIFF" | null
      },
      "last_task": {
        "task_id": "task-uuid",
        "status": "SUCCESS" | "RUNNING" | "ERROR" | "WAITING_INPUT" | null
      }
    }
  ]
}
```

**Errors**:
- `404`: Environment not found
- `503`: Superset connection error

---

### 2. Dataset Hub API

#### GET /api/datasets

**Purpose**: Fetch list of datasets from a specific environment for the Dataset Hub grid.

**Query Parameters**:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| env_id | string | Yes | Environment ID to fetch datasets from |
| search | string | No | Filter by table name |

**Response**:
```json
{
  "datasets": [
    {
      "id": "uuid-string",
      "table_name": "fact_orders",
      "schema": "public",
      "database": "Production DB",
      "mapped_fields": {
        "total": 20,
        "mapped": 15
      },
      "last_task": {
        "task_id": "task-uuid",
        "status": "SUCCESS" | null
      }
    }
  ]
}
```

---

### 3. Activity API

#### GET /api/activity

**Purpose**: Fetch summary of active and recent tasks for the navbar indicator.

**Response**:
```json
{
  "active_count": 3,
  "recent_tasks": [
    {
      "task_id": "task-uuid",
      "resource_name": "Sales Report",
      "resource_type": "dashboard",
      "status": "RUNNING",
      "started_at": "2026-02-09T10:00:00Z"
    }
  ]
}
```

---

### 4. Consolidated Settings API

#### GET /api/settings

**Purpose**: Fetch all settings categories for the consolidated settings page.

**Response**:
```json
{
  "environments": [
    { "id": "1", "name": "Development", "url": "http://dev...", "status": "OK" }
  ],
  "connections": [
    { "id": "1", "name": "Prod Clickhouse", "type": "clickhouse" }
  ],
  "llm": {
    "provider": "openai",
    "model": "gpt-4",
    "enabled": true
  },
  "logging": {
    "level": "INFO",
    "task_log_level": "DEBUG",
    "belief_scope_enabled": false
  }
}
```

---

## WebSocket Events (Existing)

The Task Drawer subscribes to existing WebSocket events:

### task:status
```json
{
  "task_id": "uuid",
  "status": "RUNNING" | "SUCCESS" | "ERROR" | "WAITING_INPUT"
}
```

### task:log
```json
{
  "task_id": "uuid",
  "timestamp": "2026-02-09T10:00:00Z",
  "level": "INFO",
  "source": "plugin",
  "message": "Starting migration..."
}
```

### task:input_required
```json
{
  "task_id": "uuid",
  "input_type": "password" | "mapping_selection",
  "prompt": "Enter database password"
}
```

---

## Module Contracts (Semantic Protocol)

### SidebarStore (frontend/src/lib/stores/sidebar.js)

```javascript
// [DEF:SidebarStore:Store]
// @TIER: STANDARD
// @PURPOSE: Manage sidebar visibility and navigation state
// @LAYER: UI
// @INVARIANT: isExpanded state is always synced with localStorage

// @UX_STATE: Idle -> Sidebar visible with current state
// @UX_STATE: Toggling -> Animation plays for 200ms

export const sidebarStore = writable({
  isExpanded: true,
  activeCategory: 'dashboards',
  activeItem: '/dashboards',
  isMobileOpen: false
});

export function toggleSidebar() { /* ... */ }
export function setActiveItem(path) { /* ... */ }
// [/DEF:SidebarStore:Store]
```

### TaskDrawerStore (frontend/src/lib/stores/taskDrawer.js)

```javascript
// [DEF:TaskDrawerStore:Store]
// @TIER: CRITICAL
// @PURPOSE: Manage Task Drawer visibility and resource-to-task mapping
// @LAYER: UI
// @INVARIANT: resourceTaskMap always reflects current task associations

// @UX_STATE: Closed -> Drawer hidden, no active task
// @UX_STATE: Open -> Drawer visible, logs streaming
// @UX_STATE: InputRequired -> Interactive form rendered in drawer

export const taskDrawerStore = writable({
  isOpen: false,
  activeTaskId: null,
  resourceTaskMap: {}
});

export function openDrawerForTask(taskId) { /* ... */ }
export function closeDrawer() { /* ... */ }
export function updateResourceTask(resourceId, taskId, status) { /* ... */ }
// [/DEF:TaskDrawerStore:Store]
```

### ActivityStore (frontend/src/lib/stores/activity.js)

```javascript
// [DEF:ActivityStore:Store]
// @TIER: STANDARD
// @PURPOSE: Track active task count for navbar indicator
// @LAYER: UI
// @RELATION: DEPENDS_ON -> WebSocket connection

export const activityStore = derived(taskDrawerStore, ($drawer) => {
  const activeCount = Object.values($drawer.resourceTaskMap)
    .filter(t => t.status === 'RUNNING').length;
  return { activeCount };
});
// [/DEF:ActivityStore:Store]
```
