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

300 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: IHUB-WP-0020
type: workplan
title: "Personal Dashboard Framework"
domain: inter_hub
repo: inter-hub
status: backlog
owner: tegwick
topic_slug: inter_hub
created: "2026-05-03"
updated: "2026-06-07"
phase: 13
state_hub_workstream_id: "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
```task
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)
```task
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; `InteractionEvent`s 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)
```task
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
```sql
-- 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:
```haskell
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
```task
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.