Files
inter-hub/workplans/IHUB-WP-0020-personal-dashboard-framework.md
tegwick 7cc3173f59
Some checks failed
Build and Deploy / build-push-deploy (push) Has been cancelled
chore: sync IHUB-WP-0020 state hub ids
2026-06-07 19:15:38 +02:00

12 KiB
Raw Permalink Blame History

id, type, title, domain, repo, status, owner, topic_slug, created, updated, phase, state_hub_workstream_id
id type title domain repo status owner topic_slug created updated phase state_hub_workstream_id
IHUB-WP-0020 workplan Personal Dashboard Framework inter_hub inter-hub backlog tegwick inter_hub 2026-05-03 2026-06-07 13 72fc022b-0196-492a-aaba-3475f8768f06

Personal Dashboard Framework

Goal

Design and implement a personal dashboard framework that allows individual users to compose, configure, and persist a view of the inter-hub platform tailored to their role and focus. The dashboard is the post-login landing page and the primary daily driver surface for hub operators, governance reviewers, and AI orchestrators.

Motivation

The current post-login experience drops the user on a raw Hubs list. As inter-hub grows to 12+ phases of functionality, users need a curated, role-aware entry point that surfaces the signals that matter to them without requiring manual navigation. The dashboard is also the natural home for cross-cutting observability (recent decisions, open candidates, outcome signals) that cuts across the current controller-per-entity navigation.


Tasks

T01 — Research: Dashboard frameworks and patterns for inspiration

id: IHUB-WP-0020-T01
status: todo
priority: high
state_hub_task_id: "6074f195-636b-4517-b6d1-eb3c57394a82"

Survey existing dashboard systems to extract patterns that are re-implementable in Haskell / IHP / Tailwind under inter-hub's design constraints (server-rendered, type-safe, governed).

Research targets:

System What to extract
Grafana Panel/grid layout model; datasource abstraction; variable-driven filtering
Kibana (dashboards) Saved-search panels; time-range awareness; role-based visibility
Retool / Appsmith Widget catalogue approach; drag-grid layout; data binding model
Linear (home view) Flat "My Work" aggregation across entities; priority surfacing
Notion (linked databases) Filter/sort persistence per user; view types (table, board, calendar)
Observable Framework Reactive cell model; markdown + code co-location
Metabase Question-as-unit; dashboard as ordered collection of questions
Streamlit Declarative layout (columns, expanders); pure functional rendering loop

Questions to answer per system:

  1. How is a dashboard persisted? (JSON blob, relational rows, code-as-config?)
  2. How is a widget/panel parameterised? (datasource, filter, display options)
  3. How is layout described? (fixed grid, CSS grid, drag-and-drop, responsive breakpoints)
  4. How is per-user state separated from shared/team state?
  5. What is the update model? (full-page reload, WebSocket push, polling, partial HTMX swap)
  6. How are access controls expressed at panel level?

IHP/Haskell-specific constraints to keep in mind:

  • Server-rendered by default; AutoRefresh (WebSocket) available for live data
  • No client-side state management library; JS must be minimal
  • Type safety from DB schema → view layer is a first-class constraint
  • Tailwind CSS; no component library

Exit criteria: Research notes written in docs/research/dashboard-frameworks.md.


T02 — Product Requirements Specification (PRS)

id: IHUB-WP-0020-T02
status: todo
priority: high
depends_on: T01
state_hub_task_id: "698304bc-b91a-42e2-a617-b3ddbf749174"

Produce a formal PRS for the Personal Dashboard Framework based on T01 findings and inter-hub's design principles.

Required sections:

  1. Problem statement — who uses the dashboard, what decisions they make with it, what pain the current flat-nav approach causes

  2. User personas

    • Hub Operator: monitors activity within their hub; wants recent events, open candidates
    • Governance Reviewer: triages candidates, reviews decisions; needs queue and signal views
    • AI Orchestrator: monitors agent proposals, outcome correlations; needs performance panels
    • Platform Admin: watches system health, API usage, learning throughput
  3. Core requirements (MoSCoW)

    • Must: per-user dashboard persisted in DB; selectable panels from a catalogue; layout preserved across sessions; role-aware default layout on first login
    • Should: panel-level filtering (by hub, by time range); live-update via AutoRefresh for signal panels; keyboard-navigable
    • Could: drag-and-drop layout editing; shared/team dashboards; dashboard templates
    • Won't (Phase 13): mobile-native layout; client-side data fetching; external datasources
  4. Non-functional requirements

    • First paint < 500 ms (server-rendered, no JS data fetching)
    • Dashboard save/load < 100 ms
    • Each panel query < 200 ms (indexed, bounded result sets)
    • Zero JS frameworks; AutoRefresh WebSocket for live panels only
  5. Governance fit — dashboard widgets are themselves Widget records in the IHF sense; InteractionEvents recorded on dashboard interactions; annotations possible on any panel

Exit criteria: docs/prs/dashboard-framework-prs.md reviewed and accepted.


T03 — Functional Design Document (FDD)

id: IHUB-WP-0020-T03
status: todo
priority: high
depends_on: T02
state_hub_task_id: "438e5771-a043-4f26-a1ce-994ed478a760"

Translate the PRS into a concrete functional design covering schema, component model, rendering pipeline, and layout system. This is the authoritative reference for implementation.

Required sections:

3.1 Data model

-- A user's named dashboard
CREATE TABLE dashboards (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    user_id UUID NOT NULL REFERENCES users(id),
    name TEXT NOT NULL,
    is_default BOOLEAN NOT NULL DEFAULT FALSE,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- An instance of a panel type on a dashboard, with position
CREATE TABLE dashboard_panels (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    dashboard_id UUID NOT NULL REFERENCES dashboards(id) ON DELETE CASCADE,
    panel_type TEXT NOT NULL,  -- FK to panel_type_registry
    config JSONB NOT NULL DEFAULT '{}',
    col INT NOT NULL DEFAULT 0,
    row INT NOT NULL DEFAULT 0,
    col_span INT NOT NULL DEFAULT 1,
    row_span INT NOT NULL DEFAULT 1,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- Registry of available panel types
CREATE TABLE panel_type_registry (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    name TEXT NOT NULL UNIQUE,
    label TEXT NOT NULL,
    description TEXT,
    default_config JSONB NOT NULL DEFAULT '{}',
    requires_hub BOOLEAN NOT NULL DEFAULT FALSE,
    live_update BOOLEAN NOT NULL DEFAULT FALSE
);

3.2 Panel catalogue (Phase 13 scope)

Panel type name Label Description Live?
recent-interactions Recent Activity Latest interaction events across watched hubs Yes
open-candidates Open Candidates Requirement candidates awaiting triage No
decision-queue Decision Queue Decisions pending review No
outcome-signals Outcome Signals Recent outcome signal summary Yes
hub-health Hub Health Health snapshot per hub No
agent-proposals Agent Proposals Open AI agent proposals No
learning-digest Learning Digest Latest institutional knowledge entries No
my-annotations My Annotations Annotations by the current user No

3.3 Layout system

12-column CSS grid; panels occupy col_span columns and row_span rows. Row height fixed at 240px. No drag-and-drop in Phase 13; layout edited via form fields (col, row, span). Responsive: collapse to single column below 768px.

┌─────────────────────────────────────────────────────┐
│  [Recent Activity ×6]    [Decision Queue ×3] [Hub ×3]│
│                                                      │
├─────────────────────────────────────────────────────┤
│  [Open Candidates ×4]  [Outcome Signals ×4] [My ×4] │
└─────────────────────────────────────────────────────┘

3.4 Rendering pipeline

GET /Dashboard
  → DashboardController#show
  → fetch dashboard + panels (ordered by row, col)
  → for each panel: dispatch to panel renderer (panelHtml panelType config)
  → embed in DashboardView with CSS grid layout
  → AutoRefresh wraps live panels only

Each panel renderer is a Haskell function:

type PanelRenderer = PanelConfig -> ModelContext -> IO Html
renderPanel :: Text -> PanelConfig -> ModelContext -> IO Html
renderPanel "recent-interactions" = renderRecentInteractions
renderPanel "open-candidates"     = renderOpenCandidates
...

3.5 Edit flow

GET /Dashboard/Edit → grid with inline forms per panel (col/row/span inputs) + "Add Panel" dropdown from panel_type_registry. POST /Dashboard saves layout. No JavaScript needed for basic edit; optional HTMX for panel preview.

3.6 Default dashboard on first login

afterLoginRedirectPath (in SessionsControllerConfig) redirects to /Dashboard. On first visit, DashboardController checks for an existing dashboard; if absent, creates a default one seeded from the user's role (determined by a role field to be added to users, or a simple heuristic based on existing data).

Exit criteria: FDD reviewed; schema migrations drafted; panel catalogue agreed.


T04 — Implementation workplan

id: IHUB-WP-0020-T04
status: todo
priority: medium
depends_on: T03
state_hub_task_id: "970aa221-7e17-4500-8b37-9c98676280b1"

Break T03's FDD into a detailed, sequenced task list suitable for execution as a new workplan (IHUB-WP-0021). Each task must have a clear entry/exit criterion and fit within the 8k token soft budget.

Expected task structure of IHUB-WP-0021:

T01  Schema migration: dashboards, dashboard_panels, panel_type_registry
T02  Seed: default panel types in panel_type_registry
T03  DashboardController — show action (fetch + render)
T04  Panel renderers — first 3 panels (recent-interactions, open-candidates, decision-queue)
T05  DashboardView — CSS grid layout
T06  Panel renderers — remaining 5 panels
T07  Dashboard edit flow (layout form, add/remove panels)
T08  Default dashboard seeding on first login
T09  afterLoginRedirectPath → /Dashboard
T10  AutoRefresh for live panels (recent-interactions, outcome-signals)
T11  Role-aware default layout
T12  Smoke tests

Exit criteria: IHUB-WP-0021 workplan file committed; T01T12 each have entry/exit criteria; ready for execution.


Exit Criteria Summary

Task Deliverable Status
T01 docs/research/dashboard-frameworks.md todo
T02 docs/prs/dashboard-framework-prs.md todo
T03 docs/fdd/dashboard-framework-fdd.md todo
T04 workplans/IHUB-WP-0021-personal-dashboard-impl.md todo

Design Principles (binding throughout)

  • Server-first: every panel renders in a single round-trip. No client-side data fetching.
  • Type-safe config: PanelConfig is a Haskell ADT, not an opaque JSON blob at runtime.
  • IHF governed: each rendered panel is a Widget with a widgetEnvelope; interactions are recorded; annotations can be attached.
  • Tailwind only: no external component library. Layout via CSS Grid with inline style for structural properties (lessons learned from sidebar nav).
  • Minimal JS: AutoRefresh WebSocket for live panels; vanilla JS for any UX enhancement. No framework, no bundler beyond the existing IHP asset pipeline.