Skip to content

Dashboard Architecture

Overview

The Duckalog dashboard is a modern, reactive web application built with:

  • Litestar - High-performance async web framework
  • Datastar - Reactive UI framework with server-sent events (SSE)
  • htpy - Pythonic HTML templating
  • Tailwind CSS - Utility-first CSS framework
  • DuckDB - Embedded analytical database

Architecture Diagram

┌─────────────────────────────────────────────────────────────────┐
│                         Client Browser                          │
│                                                                  │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐         │
│  │   Home Page  │  │  Views Page  │  │  Query Page  │         │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘         │
│         │                 │                 │                   │
│         └─────────┬───────┴─────────┬───────┘                   │
│                   │                 │                           │
│            ┌──────▼──────┐  ┌──────▼──────┐                    │
│            │  Datastar   │  │  Datastar   │                    │
│            │   (SSE)     │  │   (SSE)     │                    │
│            └──────┬──────┘  └──────┬──────┘                    │
│                   │                 │                           │
│                   └─────────┬───────┘                           │
│                             │                                   │
└─────────────────────────────┼───────────────────────────────────┘
                              │ HTTP/WebSocket
┌─────────────────────────────▼───────────────────────────────────┐
│                    Dashboard Server (Litestar)                 │
│                                                                  │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐         │
│  │   Routes     │  │  Components  │  │    State     │         │
│  │              │  │              │  │              │         │
│  │  - home.py   │  │  - layout.py │  │  - Dashboard │         │
│  │  - views.py  │  │  - tables.py │  │    Context   │         │
│  │  - query.py  │  │  - forms.py  │  │              │         │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘         │
│         │                 │                 │                   │
│         └─────────┬───────┴─────────┬───────┘                   │
│                   │                 │                           │
│            ┌──────▼──────┐  ┌──────▼──────┐                    │
│            │  Datastar   │  │   DuckDB    │                    │
│            │     SDK     │  │  Database   │                    │
│            └─────────────┘  └─────────────┘                    │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

Core Components

1. Routes (src/duckalog/dashboard/routes/)

Routes define HTTP endpoints and request handlers:

  • home.py - Dashboard home page with catalog statistics
  • views.py - List and detail views for catalog views
  • query.py - SQL query interface with real-time execution

Each route returns HTML generated by htpy components.

2. Components (src/duckalog/dashboard/components/)

Reusable UI components built with htpy:

  • layout.py - Base layout, navigation, theme toggle
  • tables.py - Data table components
  • forms.py - Form components

Components are Python functions that return htpy Element objects.

3. State Management (src/duckalog/dashboard/state.py)

DashboardContext manages application state:

  • Database connections
  • View definitions
  • Query execution
  • Row limit configuration

4. App Factory (src/duckalog/dashboard/app.py)

create_app() initializes the Litestar application:

  • Registers routes
  • Configures static file serving
  • Sets up Datastar integration
  • Enables CORS and middleware

Datastar Integration

Server-Sent Events (SSE)

Datastar uses SSE for real-time communication:

  1. Query Execution (/query/execute)
  2. Sends query results as they execute
  3. Updates UI without page refresh
  4. Streams results incrementally

  5. Build Status (/build/status)

  6. Streams build progress updates
  7. Shows real-time build status
  8. Heartbeat every 30 seconds

Signal-Based State

Client-side state is managed via Datastar signals:

// Example signal structure
{
  search: "",           // View search query
  sql: "",              // SQL query text
  loading: false,       // Loading state
  error: "",            // Error messages
  results: [...]        // Query results
}

Signals update reactively when server sends patches.

Datastar Attributes

HTML elements use Datastar attributes for reactivity:

  • data-bind - Bind element to signal
  • data-on-click - Handle click events
  • data-on-input - Handle input changes
  • data-signals - Initialize signals
  • data-show - Conditional display
  • data-text - Set element text

HTML Templating with htpy

htpy provides Pythonic HTML generation:

from htpy import div, button, span

def my_component():
    return div(class_="container")[
        button(
            id="submit-btn",
            **{"data-on-click": "$$post('/api/submit')"}
        )["Submit"],
        span(id="status")["Ready"]
    ]

Benefits: - Type-safe HTML generation - Python IDE support - No template syntax to learn - Composability via Python functions

Styling

Tailwind CSS

Utility-first CSS framework:

  • Rapid UI development
  • Consistent design system
  • Responsive breakpoints (sm, md, lg, xl)
  • Dark mode support

Basecoat CSS

Additional component styling via CDN:

  • Consistent spacing
  • Typography
  • Component primitives

Theme System

Dark/light mode toggle:

  • Stored in localStorage
  • Applied to html element
  • Class: dark
  • Persists across sessions

Static Files

Served from /static/ directory:

  • datastar.js - Datastar client library
  • Custom CSS/JS (if needed)

Configured in Litestar app factory with cache headers.

Request Flow

1. Page Load

Browser → Litestar Route → Component → htpy HTML → Response

2. Interactive Action

Browser (Datastar) → SSE POST → Route Handler → Datastar SDK
Browser (DOM) ← SSE Response ← Signal Update ← Execute Query

3. Query Execution

User Input → Datastar Signal → POST /query/execute
                                 Execute Query
                              Datastar SSE Response
                              Update UI Reactively

Development Workflow

Adding a New Route

  1. Create routes/new_page.py
  2. Define controller class with @get() decorator
  3. Use htpy components for HTML
  4. Register in app.py

Adding a New Component

  1. Create components/new_component.py
  2. Define function returning htpy Element
  3. Use Datastar attributes for interactivity
  4. Import and use in routes

Adding a New Feature

  1. Define route handler
  2. Create/update components
  3. Add Datastar signals as needed
  4. Write tests
  5. Update documentation

Performance Considerations

SSE Connections

  • Keep-alive connections
  • Automatic reconnection
  • Heartbeat every 30 seconds
  • Limited concurrent connections

Query Results

  • Row limit configurable (default: 500)
  • Streaming for large results
  • Pagination for view listings
  • Responsive table rendering

Static Assets

  • CDN for Tailwind/Basecoat
  • Local Datastar.js
  • Cache headers configured
  • Minimal bundle size

Testing

Test Structure

  • Unit tests - Context, components, routes
  • Integration tests - Datastar SSE, search, filtering
  • CLI tests - Command-line interface
  • Responsive tests - Mobile/tablet layouts

Running Tests

# All tests
uv run pytest tests/test_dashboard.py -v

# Specific test class
uv run pytest tests/test_dashboard.py::TestSSEDashboard -v

# With coverage
uv run pytest --cov=src/duckalog/dashboard tests/test_dashboard.py

Deployment

Dependencies

Install UI dependencies:

pip install duckalog[ui]

Includes: - litestar - datastar-py - htpy - uvicorn - python-multipart

Running the Dashboard

# Via CLI
duckalog ui config.yaml

# Or programmatically
from duckalog.cli import ui
ui("config.yaml", host="127.0.0.1", port=8787)

Production Considerations

  • Use reverse proxy (nginx)
  • Enable HTTPS
  • Set appropriate row limits
  • Configure CORS if needed
  • Monitor SSE connections
  • Set up logging

Migration from Legacy Dashboard

The previous ASGI-based dashboard has been completely replaced. Key changes:

Old New
Legacy ASGI framework Litestar
Custom HTML htpy
No reactivity Datastar SSE
No styling Tailwind CSS
Disabled CLI Working CLI

See Migration Guide for details.

Future Enhancements

Potential improvements:

  • Pagination - For large datasets
  • Caching - Static file and query caching
  • Authentication - User management
  • Export - CSV/JSON export
  • Charts - Visualization components
  • Keyboard Shortcuts - Power user features
  • Themes - Custom color schemes