docs(04): capture phase context

This commit is contained in:
2026-03-24 09:28:51 +01:00
parent 46614574c4
commit 9810b4dc1b
2 changed files with 299 additions and 0 deletions

View File

@@ -0,0 +1,118 @@
# Phase 4: UX Improvements - Context
**Gathered:** 2026-03-24
**Status:** Ready for planning
<domain>
## Phase Boundary
Deliver UX features that make the dashboard genuinely usable at scale: bulk dismiss (all + per-group), search and filter across updates, new-update indicators (badge, tab title, toast, highlight), and accessibility fixes (theme toggle, always-visible drag handle). No new database tables — bulk dismiss adds Store methods; search/filter is client-side; indicators use localStorage.
</domain>
<decisions>
## Implementation Decisions
### Bulk dismiss (BULK-01, BULK-02)
- **D-01:** Add two new Store methods: `AcknowledgeAll() (count int, err error)` and `AcknowledgeByTag(tagID int) (count int, err error)` — consistent with existing `AcknowledgeUpdate(image)` pattern
- **D-02:** Two new API endpoints: `POST /api/updates/acknowledge-all` and `POST /api/updates/acknowledge-by-tag` (with `tag_id` in body) — returning the count of dismissed items
- **D-03:** UI placement: "Dismiss All" button in the header/stats area; "Dismiss Group" button in each TagSection header next to the existing delete button
- **D-04:** Confirmation: modal/dialog confirmation for dismiss-all (high-impact action); inline confirm pattern (matching existing tag delete) for per-group dismiss
### Search and filter (SRCH-01 through SRCH-04)
- **D-05:** Client-side filtering only — all data is already in memory from polling, no new API endpoints needed
- **D-06:** Filter bar placed above the sections list, below the stats row
- **D-07:** Controls: text search input (filters by image name), status dropdown (all/pending/acknowledged), tag dropdown (all/specific tag/untagged), sort dropdown (date/name/registry)
- **D-08:** Filters do not persist across page reloads — reset on each visit (dashboard is a quick-glance tool)
### New-update indicators (INDIC-01 through INDIC-04)
- **D-09:** Pending update badge/counter displayed in the Header component next to the "Diun Dashboard" title — always visible
- **D-10:** Browser tab title reflects pending count: `"DiunDash (N)"` when N > 0, `"DiunDash"` when zero
- **D-11:** Toast notification when new updates arrive during polling — auto-dismiss after 5 seconds with manual dismiss button; non-stacking (latest update replaces previous toast)
- **D-12:** "New since last visit" detection via localStorage timestamp — store `lastVisitTimestamp` on page unload; updates with `received_at` after that timestamp get a visual highlight
- **D-13:** Highlight style: subtle left border accent (e.g., `border-l-4 border-amber-500`) on ServiceCard for new-since-last-visit items
### Accessibility and theme (A11Y-01, A11Y-02)
- **D-14:** Light/dark theme toggle placed in the Header bar next to the refresh button — icon button (sun/moon)
- **D-15:** Theme preference persisted in localStorage; on first visit, respects `prefers-color-scheme` media query; removes the hardcoded `classList.add('dark')` from `main.tsx`
- **D-16:** Drag handle on ServiceCard always visible at reduced opacity (`opacity-40`), full opacity on hover — removes the current `opacity-0 group-hover:opacity-100` pattern
### Claude's Discretion
- Toast component implementation (custom or shadcn/ui Sonner)
- Exact filter bar layout and responsive breakpoints
- Animation/transition details for theme switching
- Whether to show a count in the per-group dismiss button (e.g., "Dismiss 3")
- Sort order default (most recent first vs alphabetical)
</decisions>
<canonical_refs>
## Canonical References
**Downstream agents MUST read these before planning or implementing.**
### Store interface and handler patterns
- `pkg/diunwebhook/store.go` -- Store interface (9 methods; new bulk methods extend this)
- `pkg/diunwebhook/sqlite_store.go` -- SQLiteStore implementation (pattern for new methods)
- `pkg/diunwebhook/postgres_store.go` -- PostgresStore implementation (must also get new methods)
- `pkg/diunwebhook/server.go` -- Server struct and handler registration (new endpoints go here)
### Frontend components affected
- `frontend/src/App.tsx` -- Root component (filter state, bulk dismiss wiring, layout changes)
- `frontend/src/hooks/useUpdates.ts` -- Polling hook (toast detection, bulk dismiss callbacks, tab title)
- `frontend/src/components/Header.tsx` -- Header (badge counter, theme toggle, dismiss-all button)
- `frontend/src/components/TagSection.tsx` -- Tag sections (per-group dismiss button)
- `frontend/src/components/ServiceCard.tsx` -- Service cards (new-update highlight, drag handle fix)
- `frontend/src/main.tsx` -- Entry point (theme initialization logic change)
### Requirements
- `.planning/REQUIREMENTS.md` -- BULK-01, BULK-02, SRCH-01-04, INDIC-01-04, A11Y-01, A11Y-02
</canonical_refs>
<code_context>
## Existing Code Insights
### Reusable Assets
- `Button` component (`frontend/src/components/ui/button.tsx`): use for dismiss-all and per-group dismiss buttons
- `Badge` component (`frontend/src/components/ui/badge.tsx`): use for pending count badge in header
- `cn()` utility (`frontend/src/lib/utils.ts`): conditional class composition for highlight styles
- `timeAgo()` utility (`frontend/src/lib/time.ts`): already used in ServiceCard, relevant for toast messages
- `AcknowledgeButton` component: existing per-item dismiss pattern to follow for bulk buttons
### Established Patterns
- `useUpdates` hook: centralized data fetching + state management -- extend with bulk dismiss, toast detection, and tab title side effects
- Optimistic updates: used for tag assignment -- apply same pattern for bulk dismiss (update UI immediately, fire API call)
- Polling at 5s intervals: toast detection can diff previous vs current poll results
- Dark mode via Tailwind `class` strategy: theme toggle adds/removes `dark` class on `document.documentElement`
- No global state library: filter state lives in `App.tsx` via `useState`, passed as props
### Integration Points
- `cmd/diunwebhook/main.go`: register 2 new routes on the mux
- `store.go`: add `AcknowledgeAll` and `AcknowledgeByTag` to Store interface
- `sqlite_store.go` + `postgres_store.go`: implement new Store methods in both dialects
- `server.go`: add handler methods for bulk acknowledge endpoints
- `App.tsx`: add filter state, wire filter bar component, pass bulk dismiss callbacks
- `Header.tsx`: add pending count badge, theme toggle button, dismiss-all button
- `main.tsx`: replace hardcoded dark mode with localStorage + prefers-color-scheme logic
</code_context>
<specifics>
## Specific Ideas
No specific requirements -- open to standard approaches. The existing shadcn/ui + Tailwind dark mode setup provides the foundation for theme toggling.
</specifics>
<deferred>
## Deferred Ideas
None -- discussion stayed within phase scope.
</deferred>
---
*Phase: 04-ux-improvements*
*Context gathered: 2026-03-24 via auto mode*