generated from coulomb/repo-seed
docs: complete personal dashboard framework and implementation plan
Finish IHUB-WP-0020 design work (status finished, all design tasks done) and add IHUB-WP-0021 with the 12-task implementation workplan plus research, PRs, and FDD deliverables produced during the 2026-06-16 review.
This commit is contained in:
@@ -4,11 +4,11 @@ type: workplan
|
||||
title: "Personal Dashboard Framework"
|
||||
domain: inter_hub
|
||||
repo: inter-hub
|
||||
status: backlog
|
||||
status: finished
|
||||
owner: tegwick
|
||||
topic_slug: inter_hub
|
||||
created: "2026-05-03"
|
||||
updated: "2026-06-07"
|
||||
updated: "2026-06-16"
|
||||
phase: 13
|
||||
state_hub_workstream_id: "72fc022b-0196-492a-aaba-3475f8768f06"
|
||||
---
|
||||
@@ -17,283 +17,399 @@ state_hub_workstream_id: "72fc022b-0196-492a-aaba-3475f8768f06"
|
||||
|
||||
## 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.
|
||||
Design the first personal dashboard layer for inter-hub: an authenticated,
|
||||
per-user landing surface that composes the most important existing hub,
|
||||
governance, API, marketplace, and learning signals into a configurable daily
|
||||
operator view.
|
||||
|
||||
## Motivation
|
||||
This workplan is now a design and implementation-planning workplan. It should
|
||||
produce the current-state audit, product requirements, functional design, and
|
||||
follow-on implementation workplan needed to build the feature safely.
|
||||
|
||||
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.
|
||||
## Review Update: 2026-06-15
|
||||
|
||||
---
|
||||
This workplan was reviewed against the current repository state and updated
|
||||
from `backlog` to `ready`.
|
||||
|
||||
The original version assumed inter-hub mainly had a raw Hubs list and needed a
|
||||
greenfield dashboard framework. That assumption is outdated. The repo now has
|
||||
many dashboard-like surfaces and governed interaction primitives that should be
|
||||
reused instead of bypassed:
|
||||
|
||||
- Public root/intro pages exist from IHUB-WP-0015; the authenticated login flow
|
||||
still redirects to `HubsAction`.
|
||||
- Hub-level dashboard actions already exist in `Web.Controller.Hubs`, including
|
||||
hub show, triage, governance, antifragility, agent audit, adapter
|
||||
compatibility, friction heatmap, bottleneck, hub health history, and the
|
||||
operational review board.
|
||||
- Cross-hub and platform dashboards already exist: federated governance, policy
|
||||
compliance, API usage, marketplace, and learning dashboard.
|
||||
- The governed interaction substrate is mature: `widgets`, `widget_versions`,
|
||||
`interaction_events`, `annotations`, type registries, hub manifests,
|
||||
ownership/routing, API request logs, hub health snapshots, learning insights,
|
||||
and institutional knowledge are all present.
|
||||
- There is no personal dashboard schema, controller, saved panel catalogue,
|
||||
user preference model, or role-aware default layout yet.
|
||||
- Existing dashboards are mostly hard-coded controller queries plus HSX view
|
||||
fragments. They are useful source material, but they are not yet reusable
|
||||
panel renderers.
|
||||
- The `users` table has no role column. `stewardship_roles.assigned_to` is text
|
||||
and hub-scoped, so role-aware defaults must be designed carefully instead of
|
||||
assuming a user-role foreign key exists.
|
||||
|
||||
The updated scope is therefore integration-first: define a personal dashboard
|
||||
contract that reuses existing data sources and view patterns, then introduce a
|
||||
small panel renderer abstraction only where it removes real duplication.
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
|
||||
- Authenticated personal dashboard route and post-login redirect design.
|
||||
- Per-user saved dashboard record with ordered panel instances.
|
||||
- A server-rendered panel catalogue backed by existing inter-hub models.
|
||||
- Simple layout editing through IHP forms; no drag-and-drop in the first slice.
|
||||
- Hub/time filters for panels where the underlying queries already support
|
||||
bounded data.
|
||||
- Panel-level governance: each rendered saved panel must be annotatable and
|
||||
event-capturable through the existing `widgetEnvelope` convention.
|
||||
- A migration path that reuses current dashboard queries before attempting broad
|
||||
refactors.
|
||||
|
||||
### Out of Scope for the First Implementation Workplan
|
||||
|
||||
- Client-side dashboard frameworks or client-side data fetching.
|
||||
- External datasource connectors.
|
||||
- Shared/team dashboards.
|
||||
- Mobile-native layout editing.
|
||||
- Drag-and-drop layout editing.
|
||||
- A general purpose report builder.
|
||||
- Rewriting every existing dashboard into panel renderers.
|
||||
|
||||
## Current Design Constraints
|
||||
|
||||
- Server-rendered IHP views remain the default. `autoRefresh` is acceptable for
|
||||
panels that already use live refresh patterns.
|
||||
- Tailwind and existing HSX view conventions should be reused.
|
||||
- Runtime panel config may be stored as JSONB, but renderer code should decode
|
||||
into explicit Haskell config types before use.
|
||||
- Do not create an ungoverned visual component layer. A saved dashboard panel
|
||||
must either reference or create a `Widget` row, most likely using the existing
|
||||
framework-level `panel` widget type, so annotations and interaction events
|
||||
remain first-class IHF artifacts.
|
||||
- Avoid adding a `users.role` column unless the PRS/FDD proves it is needed.
|
||||
Prefer defaults derived from current user identity, stewardship assignments,
|
||||
selected watched hubs, or explicit dashboard template choice.
|
||||
|
||||
## Proposed First-Slice Panel Catalogue
|
||||
|
||||
The initial catalogue should be limited to panels that can be built from
|
||||
existing tables and controllers:
|
||||
|
||||
| Panel key | Label | Source surface/data | Live? |
|
||||
|---|---|---|---|
|
||||
| `watched-hubs` | Watched Hubs | `hubs`, `hub_health_snapshots`, optional saved hub filter | No |
|
||||
| `recent-interactions` | Recent Activity | `interaction_events` plus `widgets` and `hubs` | Yes |
|
||||
| `triage-queue` | Triage Queue | open `requirement_candidates` | Yes |
|
||||
| `recent-decisions` | Recent Decisions | `decision_records`, requirements, candidates | No |
|
||||
| `hub-health` | Hub Health | latest `hub_health_snapshots`, bottlenecks | Yes |
|
||||
| `agent-proposals` | Agent Proposals | `agent_proposals`, `agent_review_records` | No |
|
||||
| `api-usage` | API Usage | `api_consumers`, `api_request_log` | Yes |
|
||||
| `marketplace-trending` | Marketplace Trending | `widget_patterns`, adoptions, templates | No |
|
||||
| `learning-digest` | Learning Digest | `learning_insights`, `institutional_knowledge_entries` | Yes |
|
||||
| `my-annotations` | My Annotations | `annotations` filtered by current user when available | No |
|
||||
|
||||
The implementation workplan should start with a smaller subset if needed:
|
||||
`watched-hubs`, `recent-interactions`, `triage-queue`, `recent-decisions`,
|
||||
`hub-health`, and `learning-digest` are enough to prove the framework.
|
||||
|
||||
## Tasks
|
||||
|
||||
### T01 — Research: Dashboard frameworks and patterns for inspiration
|
||||
### T01 - Current-state audit and dashboard pattern research
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0020-T01
|
||||
status: todo
|
||||
status: done
|
||||
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).
|
||||
Produce a short research note that starts with the current inter-hub codebase,
|
||||
then uses external dashboard systems only for secondary inspiration.
|
||||
|
||||
**Research targets:**
|
||||
Required current-state inventory:
|
||||
|
||||
- Existing routes and views that behave like dashboards.
|
||||
- Existing `autoRefresh` usage and query patterns that are safe to reuse.
|
||||
- Existing type registry, `Widget`, `widgetEnvelope`, annotation, and event
|
||||
capture constraints.
|
||||
- Existing tables that can power first-slice personal panels.
|
||||
- Gaps: personal dashboard persistence, panel catalogue, saved filters, layout
|
||||
model, and user preference/defaulting model.
|
||||
|
||||
External systems may still be sampled, but the output should focus on patterns
|
||||
that are practical in IHP/HSX/Tailwind:
|
||||
|
||||
| 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 |
|
||||
| Grafana | Panel/grid layout model, dashboard variables, bounded refresh |
|
||||
| Kibana dashboards | Saved-search panels, time range filters, role visibility |
|
||||
| Retool/Appsmith | Widget catalogue and data binding concepts, not their client runtime |
|
||||
| Linear home view | Flat "my work" aggregation across entities |
|
||||
| Notion linked databases | Saved filters/sorts as user-facing views |
|
||||
| Metabase | Question-as-unit model and governed saved queries |
|
||||
| Streamlit | Declarative layout vocabulary suitable for server rendering |
|
||||
|
||||
**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?
|
||||
Questions to answer:
|
||||
|
||||
**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
|
||||
1. Which existing inter-hub dashboard fragments can become first-slice panel
|
||||
renderers without broad refactoring?
|
||||
2. Which panel configs must exist on day one: hub filter, time range, limit,
|
||||
display mode, or sort order?
|
||||
3. Which panels need live refresh, and which should stay static per request?
|
||||
4. How should each saved panel map to a governed `Widget` row?
|
||||
5. What should be explicitly deferred to avoid building a report builder?
|
||||
|
||||
**Exit criteria:** Research notes written in `docs/research/dashboard-frameworks.md`.
|
||||
Exit criteria: `docs/research/personal-dashboard-current-state.md` exists and
|
||||
has enough evidence to drive the PRS.
|
||||
|
||||
Completion note (2026-06-16): added
|
||||
`docs/research/personal-dashboard-current-state.md`, covering the current
|
||||
dashboard inventory, AutoRefresh/query patterns, governed widget constraints,
|
||||
first-slice panel candidates, external pattern extraction, and T02/T03
|
||||
recommendations.
|
||||
|
||||
---
|
||||
|
||||
### T02 — Product Requirements Specification (PRS)
|
||||
### T02 - Product Requirements Specification
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0020-T02
|
||||
status: todo
|
||||
status: done
|
||||
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.
|
||||
Produce a formal PRS based on T01 and the current implementation.
|
||||
|
||||
**Required sections:**
|
||||
Required sections:
|
||||
|
||||
1. **Problem statement** — who uses the dashboard, what decisions they make with it,
|
||||
what pain the current flat-nav approach causes
|
||||
1. Problem statement: authenticated users currently land on the Hubs list and
|
||||
must manually navigate to specialized dashboards to answer daily operating
|
||||
questions.
|
||||
2. Personas:
|
||||
- Hub operator: watches hub health, recent events, candidates, and
|
||||
bottlenecks.
|
||||
- Governance reviewer: triages candidates, decisions, policy coverage, and
|
||||
annotations.
|
||||
- AI orchestrator: watches agent proposals, review outcomes, and learning
|
||||
signals.
|
||||
- Platform admin: watches API usage, hub registry health, manifests, and
|
||||
cross-hub propagation.
|
||||
3. Core requirements using MoSCoW:
|
||||
- Must: per-user saved dashboard, seeded default dashboard, panel catalogue,
|
||||
server-rendered panels, persisted layout, governed panel widget identity,
|
||||
post-login route design, bounded panel queries.
|
||||
- Should: hub/time filters, simple edit mode, live refresh on selected
|
||||
panels, keyboard-accessible forms, link-outs to existing source
|
||||
dashboards.
|
||||
- Could: dashboard templates, saved watched-hub sets, shared dashboards,
|
||||
richer display modes.
|
||||
- Won't: drag-and-drop, external datasources, client-side fetching, mobile
|
||||
layout editor, complete refactor of existing dashboards.
|
||||
4. Non-functional requirements:
|
||||
- First paint target remains sub-second for seeded dashboards with bounded
|
||||
panel queries.
|
||||
- Panel queries must use limits and existing indexes or propose new indexes.
|
||||
- Dashboard save/load must be simple transactional IHP controller work.
|
||||
- No new JS framework.
|
||||
5. Governance fit:
|
||||
- Saved panel instances are governed IHF widgets or reference governed
|
||||
widgets.
|
||||
- Panel views use `widgetEnvelope`.
|
||||
- Panel interactions emit existing event types where possible.
|
||||
- Annotations attach to the panel widget identity, not to a transient DOM
|
||||
block.
|
||||
|
||||
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
|
||||
Exit criteria: `docs/prs/personal-dashboard-prs.md` exists and is ready for
|
||||
FDD work.
|
||||
|
||||
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.
|
||||
Completion note (2026-06-16): added
|
||||
`docs/prs/personal-dashboard-prs.md`, defining the problem statement,
|
||||
personas, MoSCoW requirements, first-slice panel catalogue, governance
|
||||
requirements, acceptance criteria, risks, and FDD open questions.
|
||||
|
||||
---
|
||||
|
||||
### T03 — Functional Design Document (FDD)
|
||||
### T03 - Functional Design Document
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0020-T03
|
||||
status: todo
|
||||
status: done
|
||||
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.
|
||||
Translate the PRS into a concrete FDD covering schema, controller actions,
|
||||
panel renderer contract, layout, seed/default behavior, and migration strategy.
|
||||
|
||||
**Required sections:**
|
||||
|
||||
#### 3.1 Data model
|
||||
The FDD must update the old greenfield schema sketch. A likely shape is:
|
||||
|
||||
```sql
|
||||
-- A user's named dashboard
|
||||
CREATE TABLE dashboards (
|
||||
CREATE TABLE personal_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()
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- An instance of a panel type on a dashboard, with position
|
||||
CREATE TABLE dashboard_panels (
|
||||
CREATE TABLE dashboard_panel_types (
|
||||
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,
|
||||
key 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
|
||||
default_col_span INT NOT NULL DEFAULT 4,
|
||||
default_row_span INT NOT NULL DEFAULT 1,
|
||||
live_update BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
status TEXT NOT NULL DEFAULT 'active'
|
||||
);
|
||||
|
||||
CREATE TABLE dashboard_panels (
|
||||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
||||
dashboard_id UUID NOT NULL REFERENCES personal_dashboards(id) ON DELETE CASCADE,
|
||||
panel_type_id UUID NOT NULL REFERENCES dashboard_panel_types(id),
|
||||
widget_id UUID NOT NULL REFERENCES widgets(id),
|
||||
config JSONB NOT NULL DEFAULT '{}',
|
||||
col INT NOT NULL DEFAULT 0,
|
||||
row INT NOT NULL DEFAULT 0,
|
||||
col_span INT NOT NULL DEFAULT 4,
|
||||
row_span INT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
```
|
||||
|
||||
#### 3.2 Panel catalogue (Phase 13 scope)
|
||||
The FDD must also resolve:
|
||||
|
||||
| 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 |
|
||||
- Naming: whether tables should use `personal_dashboards` or another prefix to
|
||||
avoid confusing them with existing dashboard actions.
|
||||
- Panel config: JSONB storage plus explicit Haskell ADT decoding and validation.
|
||||
- Governance identity: how `dashboard_panels.widget_id` is created, versioned,
|
||||
and named.
|
||||
- Renderer contract:
|
||||
|
||||
#### 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
|
||||
...
|
||||
data DashboardPanelConfig
|
||||
= WatchedHubsConfig WatchedHubsOptions
|
||||
| RecentInteractionsConfig RecentInteractionsOptions
|
||||
| TriageQueueConfig TriageQueueOptions
|
||||
| RecentDecisionsConfig RecentDecisionsOptions
|
||||
| HubHealthConfig HubHealthOptions
|
||||
| LearningDigestConfig LearningDigestOptions
|
||||
|
||||
renderDashboardPanel
|
||||
:: DashboardPanelType
|
||||
-> DashboardPanel
|
||||
-> DashboardPanelConfig
|
||||
-> ModelContext
|
||||
-> IO Html
|
||||
```
|
||||
|
||||
#### 3.5 Edit flow
|
||||
- Layout: 12-column grid on desktop, single-column below the existing Tailwind
|
||||
breakpoint, stable row/span constraints, no drag-and-drop in the first slice.
|
||||
- Routes/actions:
|
||||
- `PersonalDashboardAction`
|
||||
- `EditPersonalDashboardAction`
|
||||
- `UpdatePersonalDashboardAction`
|
||||
- `AddDashboardPanelAction`
|
||||
- `UpdateDashboardPanelAction`
|
||||
- `RemoveDashboardPanelAction`
|
||||
- Login behavior: `CreateSessionAction` should redirect to the personal
|
||||
dashboard after authentication, while public root pages remain unchanged.
|
||||
- Defaulting model: seed a default dashboard on first visit without requiring a
|
||||
`users.role` column.
|
||||
- Query safety: each panel query must be bounded, indexed, and compatible with
|
||||
current PostgreSQL type decoding practices such as casting `COUNT(*)` to
|
||||
integer when read as `Int`.
|
||||
- Tests and smoke checks needed for the follow-on implementation workplan.
|
||||
|
||||
`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.
|
||||
Exit criteria: `docs/fdd/personal-dashboard-fdd.md` exists, schema decisions
|
||||
are concrete enough to implement, and open questions are explicitly listed.
|
||||
|
||||
#### 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.
|
||||
Completion note (2026-06-16): added
|
||||
`docs/fdd/personal-dashboard-fdd.md`, resolving schema names, panel config
|
||||
typing, renderer/view-model shape, default seeding, governed panel widget
|
||||
lifecycle, query constraints, routes, layout, tests, and handoff shape for
|
||||
IHUB-WP-0021.
|
||||
|
||||
---
|
||||
|
||||
### T04 — Implementation workplan
|
||||
### T04 - Implementation workplan
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0020-T04
|
||||
status: todo
|
||||
status: done
|
||||
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.
|
||||
Create the execution workplan for implementation as `IHUB-WP-0021`.
|
||||
|
||||
**Expected task structure of IHUB-WP-0021:**
|
||||
Expected task structure for `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
|
||||
```
|
||||
| Task | Focus |
|
||||
|---|---|
|
||||
| T01 | Schema migration for personal dashboards, panel types, and panel instances |
|
||||
| T02 | Seed dashboard panel types and any required framework `panel` widgets/type vocabulary |
|
||||
| T03 | Add controller/action/route skeleton and default dashboard lookup/seed helper |
|
||||
| T04 | Implement first three renderers: watched hubs, recent interactions, triage queue |
|
||||
| T05 | Implement dashboard show view and responsive CSS grid |
|
||||
| T06 | Implement remaining first-slice renderers: recent decisions, hub health, learning digest |
|
||||
| T07 | Implement edit flow: reorder/update layout, add/remove panels, validate config |
|
||||
| T08 | Add governed widget identity creation and `widgetEnvelope` wrapping for panels |
|
||||
| T09 | Redirect successful login to the personal dashboard |
|
||||
| T10 | Add `autoRefresh` only around selected live panels or the whole page if finer wrapping is not practical |
|
||||
| T11 | Add focused tests for seeding, panel config validation, route access, and bounded queries |
|
||||
| T12 | Manual smoke: login, seeded dashboard, edit layout, annotate a panel, verify source dashboards still load |
|
||||
|
||||
**Exit criteria:** IHUB-WP-0021 workplan file committed; T01–T12 each have
|
||||
entry/exit criteria; ready for execution.
|
||||
Each task must have entry criteria, exit criteria, rollback notes, and the
|
||||
smallest reasonable test/smoke requirement. Keep implementation slices small
|
||||
enough for Codex sessions to finish without broad refactors.
|
||||
|
||||
---
|
||||
Exit criteria: `workplans/IHUB-WP-0021-personal-dashboard-implementation.md`
|
||||
exists with all tasks in `todo` state and enough detail to start implementation.
|
||||
|
||||
Completion note (2026-06-16): added
|
||||
`workplans/IHUB-WP-0021-personal-dashboard-implementation.md` with twelve
|
||||
sequenced implementation tasks covering schema, seeds, controller skeleton,
|
||||
panel renderers, show/edit views, governed panel widget lifecycle, login
|
||||
redirect, AutoRefresh/query hardening, tests, and manual smoke.
|
||||
|
||||
## 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 |
|
||||
| T01 | `docs/research/personal-dashboard-current-state.md` | done |
|
||||
| T02 | `docs/prs/personal-dashboard-prs.md` | done |
|
||||
| T03 | `docs/fdd/personal-dashboard-fdd.md` | done |
|
||||
| T04 | `workplans/IHUB-WP-0021-personal-dashboard-implementation.md` | done |
|
||||
|
||||
## Design Principles (binding throughout)
|
||||
## Binding Design Principles
|
||||
|
||||
- **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.
|
||||
- Server-first: every panel renders on the server in the normal IHP request
|
||||
lifecycle.
|
||||
- Integration-first: reuse current dashboard query patterns before extracting
|
||||
shared abstractions.
|
||||
- Governed panels: saved panel instances have stable IHF widget identity and
|
||||
use `widgetEnvelope`.
|
||||
- Type-safe runtime config: JSONB is storage, not the unchecked runtime API.
|
||||
- Bounded queries: every panel limits rows and uses existing indexes or proposes
|
||||
a specific migration.
|
||||
- Minimal JS: no framework and no client-side data fetch loop.
|
||||
- Tailwind only: use existing view style and responsive grid conventions.
|
||||
|
||||
623
workplans/IHUB-WP-0021-personal-dashboard-implementation.md
Normal file
623
workplans/IHUB-WP-0021-personal-dashboard-implementation.md
Normal file
@@ -0,0 +1,623 @@
|
||||
---
|
||||
id: IHUB-WP-0021
|
||||
type: workplan
|
||||
title: "Personal Dashboard Implementation"
|
||||
domain: inter_hub
|
||||
repo: inter-hub
|
||||
status: ready
|
||||
owner: codex
|
||||
topic_slug: inter_hub
|
||||
created: "2026-06-16"
|
||||
updated: "2026-06-16"
|
||||
phase: 13
|
||||
depends_on: IHUB-WP-0020
|
||||
related_docs:
|
||||
- docs/research/personal-dashboard-current-state.md
|
||||
- docs/prs/personal-dashboard-prs.md
|
||||
- docs/fdd/personal-dashboard-fdd.md
|
||||
state_hub_workstream_id: "79f72176-fb3f-4d59-9678-d42f5ff1e679"
|
||||
---
|
||||
|
||||
# Personal Dashboard Implementation
|
||||
|
||||
## Goal
|
||||
|
||||
Implement the personal dashboard framework designed in IHUB-WP-0020: a
|
||||
server-rendered authenticated landing page with persisted per-user panels,
|
||||
governed panel widget identity, default dashboard seeding, simple edit forms,
|
||||
and six first-slice panel renderers.
|
||||
|
||||
## Inputs
|
||||
|
||||
- `docs/research/personal-dashboard-current-state.md`
|
||||
- `docs/prs/personal-dashboard-prs.md`
|
||||
- `docs/fdd/personal-dashboard-fdd.md`
|
||||
- Existing dashboard surfaces in `Web/Controller/Hubs.hs`,
|
||||
`Web/Controller/LearningDashboard.hs`, `Web/Controller/ApiDashboard.hs`,
|
||||
`Web/Controller/MarketplaceDashboard.hs`, and federated governance
|
||||
controllers.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Keep implementation additive.
|
||||
- Preserve public root/static routes.
|
||||
- Do not refactor all existing dashboards.
|
||||
- No client-side data fetching framework.
|
||||
- No drag-and-drop layout in this workplan.
|
||||
- Every saved dashboard panel must have stable `Widget` identity and render
|
||||
through `widgetEnvelope`.
|
||||
- Bound every panel query.
|
||||
- Cast aggregate `COUNT(*)` queries when decoding as `Int`, or decode as
|
||||
`Int64`.
|
||||
|
||||
## Tasks
|
||||
|
||||
### T01 - Add personal dashboard schema
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T01
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "bb7366a3-78ec-42d8-9f16-b7ed4979ec53"
|
||||
```
|
||||
|
||||
Add the schema from the FDD:
|
||||
|
||||
- `personal_dashboards`
|
||||
- `dashboard_panel_types`
|
||||
- `dashboard_panels`
|
||||
|
||||
Implementation notes:
|
||||
|
||||
- Add an `Application/Migration/<timestamp>-personal-dashboard-framework.sql`
|
||||
migration.
|
||||
- Update `Application/Schema.sql` consistently with the migration.
|
||||
- Use `panel_key`, not `key`, on `dashboard_panel_types`.
|
||||
- Include `removed_at` on `dashboard_panels`.
|
||||
- Include indexes and layout CHECK constraints from the FDD.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- IHUB-WP-0020 is done.
|
||||
- FDD exists and is reviewed enough for implementation.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- Schema files contain the three new tables and indexes.
|
||||
- `rg "personal_dashboards|dashboard_panel_types|dashboard_panels" Application`
|
||||
finds the expected migration/schema entries.
|
||||
- No existing table or route behavior is changed.
|
||||
|
||||
Verification:
|
||||
|
||||
- Run `git diff --check`.
|
||||
- If the IHP dev environment is available, run the repo compile/schema check
|
||||
used by prior inter-hub workplans.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- Before production data exists, rollback is removing the migration/schema
|
||||
additions.
|
||||
- After production data exists, rollback requires preserving linked `widgets`
|
||||
and `interaction_events`; do not delete panel widgets casually.
|
||||
|
||||
---
|
||||
|
||||
### T02 - Seed panel types and framework panel vocabulary
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T02
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: T01
|
||||
state_hub_task_id: "d298eab2-736d-48ed-b6d4-84afa1604de9"
|
||||
```
|
||||
|
||||
Add idempotent seed data for:
|
||||
|
||||
- framework hub with slug `inter-hub` and `hub_kind = 'framework'` if absent;
|
||||
- active widget type `panel` if absent;
|
||||
- six first-slice `dashboard_panel_types`:
|
||||
- `watched-hubs`
|
||||
- `recent-interactions`
|
||||
- `triage-queue`
|
||||
- `recent-decisions`
|
||||
- `hub-health`
|
||||
- `learning-digest`
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- T01 schema exists.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- Seed SQL or helper is idempotent.
|
||||
- Re-running seeds does not create duplicate framework hubs, widget types, or
|
||||
panel types.
|
||||
- Default configs match the FDD.
|
||||
|
||||
Verification:
|
||||
|
||||
- Inspect seed SQL for `ON CONFLICT DO NOTHING` or equivalent idempotency.
|
||||
- If DB is available, run a local seed twice and confirm row counts stay stable.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- Panel type seed rows are additive. If rollback is needed before use, remove
|
||||
only the new dashboard panel type rows and any framework hub created solely
|
||||
for this feature.
|
||||
|
||||
---
|
||||
|
||||
### T03 - Add controller skeleton, routes, and default dashboard helper
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T03
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: T02
|
||||
state_hub_task_id: "8a171c71-3762-46c7-88d7-10ffb87fc78a"
|
||||
```
|
||||
|
||||
Add:
|
||||
|
||||
- `PersonalDashboardsController` to `Web/Types.hs`;
|
||||
- `Web/Controller/PersonalDashboards.hs`;
|
||||
- `Web/View/PersonalDashboards/Show.hs`;
|
||||
- `Web/View/PersonalDashboards/Edit.hs` placeholder or minimal views;
|
||||
- route registration in `Web/Routes.hs`;
|
||||
- controller import and parser registration in `Web/FrontController.hs`;
|
||||
- helper module `Application/Helper/PersonalDashboard.hs`.
|
||||
|
||||
Implement:
|
||||
|
||||
- `ensureDefaultDashboard :: User -> IO PersonalDashboard`;
|
||||
- dashboard lookup scoped to current user;
|
||||
- idempotent default seeding with six panel rows;
|
||||
- linked `Widget` creation for each seeded panel;
|
||||
- initial `WidgetVersion` creation for panel widgets.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- T01/T02 complete.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- Authenticated user can hit `PersonalDashboardAction`.
|
||||
- First visit creates a default dashboard with six active panels.
|
||||
- A second visit does not duplicate panels.
|
||||
- Controller denies unauthenticated access through `ensureIsUser`.
|
||||
|
||||
Verification:
|
||||
|
||||
- Compile if environment is available.
|
||||
- Add or run focused helper tests if existing test harness supports it.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- Remove route/controller/helper additions if skeleton must be reverted.
|
||||
- Keep seeded widgets/events if any user interactions already happened.
|
||||
|
||||
---
|
||||
|
||||
### T04 - Implement first three panel view models/renderers
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T04
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: T03
|
||||
state_hub_task_id: "012dcd2a-d3e0-48ba-966b-f4c7afa51dad"
|
||||
```
|
||||
|
||||
Implement typed config decoding and view-model builders for:
|
||||
|
||||
- `watched-hubs`
|
||||
- `recent-interactions`
|
||||
- `triage-queue`
|
||||
|
||||
Requirements:
|
||||
|
||||
- Query from controller/helper, not from HSX views.
|
||||
- Clamp configured limits.
|
||||
- Apply optional hub filters.
|
||||
- Render empty states.
|
||||
- Include source links:
|
||||
- watched hub rows link to `ShowHubAction`;
|
||||
- recent interaction rows link to widget or hub context where available;
|
||||
- triage rows link to `ShowRequirementCandidateAction`.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- T03 controller/helper skeleton exists.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- The three panels render in the dashboard show action.
|
||||
- Invalid config falls back to defaults and records a warning in the panel view
|
||||
model.
|
||||
- Queries are bounded.
|
||||
|
||||
Verification:
|
||||
|
||||
- Compile if environment is available.
|
||||
- Manual smoke with empty DB and seeded fixture data if possible.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- Renderer additions are isolated to helper/view modules and can be reverted
|
||||
without dropping schema.
|
||||
|
||||
---
|
||||
|
||||
### T05 - Implement dashboard show view and responsive grid
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T05
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: T04
|
||||
state_hub_task_id: "b4c4de39-147b-45a0-954d-9bafad4aafa1"
|
||||
```
|
||||
|
||||
Build the dashboard show view:
|
||||
|
||||
- title and edit link;
|
||||
- responsive grid;
|
||||
- panel cards using row/col/span config;
|
||||
- panel title fallback to panel type label;
|
||||
- warning display for invalid config or unsupported panel;
|
||||
- source link area;
|
||||
- `widgetEnvelope` around every panel.
|
||||
|
||||
Implementation notes:
|
||||
|
||||
- Use current Tailwind and HSX conventions.
|
||||
- Add a small CSS helper in `static/app.css` only if needed for responsive
|
||||
collapse.
|
||||
- Keep text compact and operational.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- At least three panel view models exist.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- Seeded dashboard is usable as an authenticated landing surface.
|
||||
- Panels do not overlap at desktop or narrow widths.
|
||||
- Panel layout persists in the order defined by `row`, `col`, and `sort_order`.
|
||||
|
||||
Verification:
|
||||
|
||||
- Compile if environment is available.
|
||||
- Browser/manual smoke if a dev server is running.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- Show view changes can be reverted independently of schema/controller work.
|
||||
|
||||
---
|
||||
|
||||
### T06 - Implement remaining first-slice panel view models/renderers
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T06
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: T05
|
||||
state_hub_task_id: "8d0bd046-17b3-48d9-a945-8b2e9c001123"
|
||||
```
|
||||
|
||||
Implement:
|
||||
|
||||
- `recent-decisions`
|
||||
- `hub-health`
|
||||
- `learning-digest`
|
||||
|
||||
Requirements:
|
||||
|
||||
- Recent decisions: bounded by time range and limit; link to
|
||||
`ShowDecisionRecordAction`.
|
||||
- Hub health: latest snapshot per hub plus active bottleneck count; use
|
||||
aggregate count casting or `Int64`.
|
||||
- Learning digest: recent `learning_insights` and
|
||||
`institutional_knowledge_entries`; link to knowledge entries where possible.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- T05 show view can render panel view models.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- All six first-slice panels render.
|
||||
- All panel queries are bounded.
|
||||
- Empty states are sane for all six panels.
|
||||
|
||||
Verification:
|
||||
|
||||
- Compile if environment is available.
|
||||
- `git diff --check`.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- Each renderer should be separable so a single broken panel can be reverted
|
||||
without removing the framework.
|
||||
|
||||
---
|
||||
|
||||
### T07 - Implement edit flow
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T07
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: T06
|
||||
state_hub_task_id: "51a72b56-5c23-4baa-892f-4ab89fd8495c"
|
||||
```
|
||||
|
||||
Implement:
|
||||
|
||||
- `EditPersonalDashboardAction`;
|
||||
- `UpdatePersonalDashboardAction`;
|
||||
- `AddDashboardPanelAction`;
|
||||
- `UpdateDashboardPanelAction`;
|
||||
- `RemoveDashboardPanelAction`.
|
||||
|
||||
Edit view capabilities:
|
||||
|
||||
- show existing panels in layout order;
|
||||
- edit row, col, col span, row span, title, and sort order;
|
||||
- edit supported config fields such as limit, time range, display mode, and
|
||||
hub filter;
|
||||
- add active panel type;
|
||||
- remove panel.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- All six panels render on show view.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- User can modify layout and config through server-rendered forms.
|
||||
- User can add a panel and remove a panel.
|
||||
- Invalid layout/config re-renders edit view with an error.
|
||||
- A user cannot edit another user's dashboard/panel.
|
||||
|
||||
Verification:
|
||||
|
||||
- Manual edit smoke.
|
||||
- Focused authorization/config tests if available.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- If edit flow is unstable, keep show-only dashboard and disable edit links
|
||||
until fixed.
|
||||
|
||||
---
|
||||
|
||||
### T08 - Complete governed panel widget lifecycle
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T08
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: T07
|
||||
state_hub_task_id: "ca70b76d-766f-4e6e-84f1-19943c0a347c"
|
||||
```
|
||||
|
||||
Harden widget lifecycle behavior:
|
||||
|
||||
- create panel widget on panel add/seed;
|
||||
- create initial `WidgetVersion` snapshot;
|
||||
- create a new `WidgetVersion` snapshot when material panel config changes;
|
||||
- render every panel through `widgetEnvelope`;
|
||||
- preserve annotations/events when panels are removed;
|
||||
- archive/deprecate linked widget on panel removal.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- Edit flow can add/remove/update panels.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- Every active dashboard panel has a linked active `Widget`.
|
||||
- Every linked widget has non-empty `view_context`.
|
||||
- Annotate link opens the existing widget annotation flow.
|
||||
- Removing a panel does not delete widget history.
|
||||
|
||||
Verification:
|
||||
|
||||
- Manual smoke: add panel, annotate panel, remove panel, confirm widget/event
|
||||
history is not deleted.
|
||||
- Inspect generated HTML for expected `data-widget-*` attributes.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- Do not delete existing `widgets`, `annotations`, or `interaction_events`.
|
||||
Disable dashboard rendering if needed while preserving history.
|
||||
|
||||
---
|
||||
|
||||
### T09 - Redirect login and add navigation
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T09
|
||||
status: todo
|
||||
priority: medium
|
||||
depends_on: T08
|
||||
state_hub_task_id: "2fd1041b-9135-49e4-a9d1-e5d0b67d8fd7"
|
||||
```
|
||||
|
||||
Update:
|
||||
|
||||
- `Web/Controller/Sessions.hs` to redirect successful login to
|
||||
`PersonalDashboardAction`;
|
||||
- `Web/FrontController.hs` sidebar to include `Dashboard`;
|
||||
- any relevant public page management links only if they should point to the
|
||||
dashboard rather than Hubs.
|
||||
|
||||
Do not change:
|
||||
|
||||
- public root route;
|
||||
- `LandingAction`;
|
||||
- capabilities/tutorial/extension guide pages;
|
||||
- `HubsAction` availability.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- Dashboard show route is stable and governed panel lifecycle is complete.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- Successful login lands on personal dashboard.
|
||||
- Hubs remain reachable from sidebar.
|
||||
- Public pages still render without login.
|
||||
|
||||
Verification:
|
||||
|
||||
- Manual login smoke.
|
||||
- Route smoke for `/`, Hubs, dashboard, Learning, API Dashboard, Marketplace.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- If dashboard redirect fails, revert only the login redirect and keep
|
||||
dashboard accessible from sidebar.
|
||||
|
||||
---
|
||||
|
||||
### T10 - Add AutoRefresh and query hardening pass
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T10
|
||||
status: todo
|
||||
priority: medium
|
||||
depends_on: T09
|
||||
state_hub_task_id: "e19c06e7-ec95-40ca-8087-df669b575f86"
|
||||
```
|
||||
|
||||
Wrap `PersonalDashboardAction` in `autoRefresh do` and audit all six panel
|
||||
queries:
|
||||
|
||||
- every query is bounded;
|
||||
- optional hub filter is applied before broad fetches where practical;
|
||||
- aggregate counts decode safely;
|
||||
- no secrets are selected or displayed;
|
||||
- dashboard refresh remains acceptable with default seed data.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- Dashboard route, renderers, edit flow, and login redirect exist.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- Dashboard updates using existing IHP AutoRefresh behavior.
|
||||
- Query review notes are either captured in code comments or tests where useful.
|
||||
- No known `COUNT(*)` as `Int` decode hazard remains in dashboard code.
|
||||
|
||||
Verification:
|
||||
|
||||
- Compile if environment is available.
|
||||
- Manual refresh smoke by adding an interaction/candidate and observing the
|
||||
dashboard update, when a dev DB is available.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- Remove `autoRefresh` wrapper if it causes unacceptable behavior; keep static
|
||||
dashboard route.
|
||||
|
||||
---
|
||||
|
||||
### T11 - Add focused tests
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T11
|
||||
status: todo
|
||||
priority: medium
|
||||
depends_on: T10
|
||||
state_hub_task_id: "32b4f55e-ede6-4830-a171-b0785afe88e1"
|
||||
```
|
||||
|
||||
Add focused tests where the current harness supports them:
|
||||
|
||||
- default dashboard seeding is idempotent;
|
||||
- seeded dashboard has six active panels;
|
||||
- each active panel has linked widget identity;
|
||||
- config decoder clamps limits and rejects unknown values safely;
|
||||
- remove action soft-removes panel and archives widget;
|
||||
- users cannot edit another user's dashboard;
|
||||
- aggregate counts in dashboard helpers decode safely.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- T10 implementation is stable enough to test.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- Relevant test files exist or a documented reason explains why the current
|
||||
harness cannot cover a case.
|
||||
- Tests pass where runnable in the local environment.
|
||||
|
||||
Verification:
|
||||
|
||||
- Run available test command.
|
||||
- If unavailable, record exact blocker in this workplan before closing T11.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- Do not weaken production behavior to satisfy a brittle test; adjust the test
|
||||
to match the intended FDD contract.
|
||||
|
||||
---
|
||||
|
||||
### T12 - Manual smoke and closeout
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0021-T12
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: T11
|
||||
state_hub_task_id: "8c6648ae-d33e-48f6-9d56-ee557f367d80"
|
||||
```
|
||||
|
||||
Run a manual smoke pass:
|
||||
|
||||
1. Log in as an existing admin user.
|
||||
2. Confirm redirect lands on personal dashboard.
|
||||
3. Confirm all six seeded panels render.
|
||||
4. Click source links from watched hubs, triage queue, and learning digest.
|
||||
5. Open Annotate for one panel.
|
||||
6. Edit layout and save.
|
||||
7. Sign out/in and confirm layout persists.
|
||||
8. Add and remove a panel.
|
||||
9. Confirm Hubs, Hub show, Ops Review, Federation, Learning, API Dashboard,
|
||||
Hub Registry, and Marketplace still load.
|
||||
10. Run `git diff --check`.
|
||||
|
||||
Entry criteria:
|
||||
|
||||
- T01 through T11 complete or have explicit accepted caveats.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- Smoke evidence is recorded in this workplan or a short docs/evidence note.
|
||||
- WP-0021 tasks reflect final status.
|
||||
- State Hub progress note is logged.
|
||||
- Operator is reminded to run `make fix-consistency REPO=inter-hub` from
|
||||
`~/state-hub` after workplan/status changes.
|
||||
|
||||
Rollback notes:
|
||||
|
||||
- If smoke fails after login redirect, first rollback is reverting the login
|
||||
redirect while keeping dashboard route available for debugging.
|
||||
|
||||
## Workplan Exit Criteria
|
||||
|
||||
- Personal dashboard schema, seeds, controller, views, helper, and route are
|
||||
implemented.
|
||||
- Successful login reaches the personal dashboard.
|
||||
- Default dashboard seeding is idempotent.
|
||||
- Six first-slice panels render with bounded queries.
|
||||
- Panel edit flow works.
|
||||
- Every panel has governed widget identity.
|
||||
- Existing source dashboards remain functional.
|
||||
- Checks/smoke evidence is recorded.
|
||||
Reference in New Issue
Block a user