generated from coulomb/repo-seed
docs(wp): IHUB-WP-0018 personal dashboard framework
Some checks failed
Build and Deploy / build-push-deploy (push) Has been cancelled
Some checks failed
Build and Deploy / build-push-deploy (push) Has been cancelled
Four-task research-first workplan: T01 surveys Grafana/Kibana/Retool/ Linear/Notion/Observable/Metabase/Streamlit for transplantable patterns; T02 produces a PRS (4 personas, MoSCoW, perf NFRs, IHF governance fit); T03 produces an FDD (schema, 8-panel catalogue, 12-col grid layout, server-rendered pipeline, edit flow, default seeding); T04 breaks the FDD into IHUB-WP-0019 implementation tasks. Design constraints: server-first, type-safe PanelConfig ADT, IHF widget envelope on every panel, Tailwind + CSS Grid, minimal JS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
292
workplans/IHUB-WP-0018-personal-dashboard-framework.md
Normal file
292
workplans/IHUB-WP-0018-personal-dashboard-framework.md
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
---
|
||||||
|
id: IHUB-WP-0018
|
||||||
|
type: workplan
|
||||||
|
title: "Personal Dashboard Framework"
|
||||||
|
domain: inter-hub
|
||||||
|
status: todo
|
||||||
|
owner: tegwick
|
||||||
|
created: "2026-05-03"
|
||||||
|
updated: "2026-05-03"
|
||||||
|
phase: 13
|
||||||
|
---
|
||||||
|
|
||||||
|
# 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-0018-T01
|
||||||
|
status: todo
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
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-0018-T02
|
||||||
|
status: todo
|
||||||
|
priority: high
|
||||||
|
depends_on: T01
|
||||||
|
```
|
||||||
|
|
||||||
|
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-0018-T03
|
||||||
|
status: todo
|
||||||
|
priority: high
|
||||||
|
depends_on: T02
|
||||||
|
```
|
||||||
|
|
||||||
|
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-0018-T04
|
||||||
|
status: todo
|
||||||
|
priority: medium
|
||||||
|
depends_on: T03
|
||||||
|
```
|
||||||
|
|
||||||
|
Break T03's FDD into a detailed, sequenced task list suitable for execution as a new
|
||||||
|
workplan (IHUB-WP-0019). Each task must have a clear entry/exit criterion and fit within
|
||||||
|
the 8k token soft budget.
|
||||||
|
|
||||||
|
**Expected task structure of IHUB-WP-0019:**
|
||||||
|
|
||||||
|
```
|
||||||
|
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-0019 workplan file committed; T01–T12 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-0019-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.
|
||||||
Reference in New Issue
Block a user