generated from coulomb/repo-seed
Some checks failed
Build and Deploy / build-push-deploy (push) Has been cancelled
300 lines
12 KiB
Markdown
300 lines
12 KiB
Markdown
---
|
||
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; 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-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.
|