feat(ui): responsive + WCAG AA polish pass across chat and sources — v1 feature complete
This commit is contained in:
@@ -1,59 +0,0 @@
|
||||
# Phase 05 — Story: Suggestion Chips
|
||||
|
||||
**Story:** `.agent/user_stories/suggestion-chips.md`
|
||||
**Context:** `.agent/PLAN.md` §7 (UI/UX), story file for chip spec
|
||||
|
||||
## Goal
|
||||
Zero-friction onboarding: 3–4 real example questions on first load,
|
||||
clickable → filled → submitted, keyboard-first, mobile-scrollable.
|
||||
|
||||
## Implementation steps
|
||||
1. `app/config.py` — confirm `suggestions` is env-overridable
|
||||
(`BOR_SUGGESTIONS` as JSON list via pydantic-settings) and tune the
|
||||
defaults against the *actually imported* Homelab/Deployments topics
|
||||
(read a sample of `documents` titles; pick questions real answers
|
||||
exist for).
|
||||
2. `app.js` — extract a `renderChips(container, items, {onSelect})` helper;
|
||||
real `<button type="button" class="suggestion-chip" role="listitem">`
|
||||
inside `#suggestions[role="list"]`; onboarding `onSelect` = fill
|
||||
`#message-input` + focus + `composer.requestSubmit()`. Reuse the same
|
||||
helper for deflection chips (Phase 04) with the same submit behavior.
|
||||
3. Empty-state lifecycle: first user message hides `#empty-state` (already
|
||||
done in `addMessage`) — verify chips don't linger in the conversation.
|
||||
4. Mobile CSS check: chip row `nowrap + overflow-x auto` at ≤640px (tokens
|
||||
already exist — verify, don't duplicate).
|
||||
|
||||
## UI Verification
|
||||
Against the story: pills 999px radius, ≥44px, brand-soft/brand-ink (≥6:1),
|
||||
hover/active states; desktop centered wrap vs mobile single scroll row;
|
||||
Tab order reaches chips before the composer input is required; screen
|
||||
reader: group labeled "Suggested questions". Screenshot pass 1280px + 375px.
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: `GET /api/suggestions` honors `BOR_SUGGESTIONS` env
|
||||
override (JSON list); default list has ≥3 non-empty strings.
|
||||
- Coverage: **>90%** on `app/` (JS is covered by E2E).
|
||||
|
||||
## Playwright Execution Phase
|
||||
Run ONLY this story's suite:
|
||||
|
||||
```bash
|
||||
uv run pytest tests/e2e/test_suggestion_chips.py -v --no-cov
|
||||
```
|
||||
|
||||
Implements the story mapping: chips render (≥3, role=list); chip click
|
||||
submits (user bubble with exact chip text + mock reply); keyboard Tab+Enter
|
||||
activates; 375px chip row is a horizontal scroll row.
|
||||
|
||||
## Success criteria
|
||||
- [ ] onboarding chips render from the API; click = one-tap question
|
||||
- [ ] keyboard + SR usable; mobile scroll row
|
||||
- [ ] deflection chips share the component + submit behavior
|
||||
- [ ] unit + integration green, coverage >90%
|
||||
- [ ] story E2E green in isolation
|
||||
- [ ] committed
|
||||
|
||||
## Commit
|
||||
```bash
|
||||
git add -A && git commit --no-gpg-sign -m "feat(ui): onboarding suggestion chips with one-tap submit, keyboard access, and mobile scroll row"
|
||||
```
|
||||
@@ -1,64 +0,0 @@
|
||||
# Phase 06 — Story: Loading Feedback & Progress
|
||||
|
||||
**Story:** `.agent/user_stories/loading-feedback.md`
|
||||
**Context:** `.agent/PLAN.md` §7.4 ("never stale" contract), §9
|
||||
|
||||
## Goal
|
||||
An unambiguous state machine — `idle → thinking → streaming → done |
|
||||
error → idle` — so the user always knows what's happening, and a stale
|
||||
Send button is impossible.
|
||||
|
||||
## Implementation steps
|
||||
1. `app.js` — formalize the state machine (single `setUiState(state)`
|
||||
function driving: typing indicator, send button disabled/spinner/label,
|
||||
`#send-status` live text). Replace ad-hoc busy handling from Phase 03.
|
||||
2. Pre-token: typing indicator (`role="status"`,
|
||||
`aria-label="Brain of Reese is thinking"`); after 10s pre-token, update
|
||||
the label with elapsed seconds (setInterval, cleared on state change).
|
||||
3. Streaming: first `delta` removes the typing indicator and starts
|
||||
appending to the answer bubble; button stays busy.
|
||||
4. Error paths: `{"type":"error"}` SSE event, non-2xx response, or
|
||||
**120s client-side timeout** (clear on first delta) → red banner
|
||||
`role="alert"` ("Try again — if this persists, check the LLM is
|
||||
reachable") + state → idle.
|
||||
5. `prefers-reduced-motion`: CSS already slows animations — verify; add a
|
||||
static fallback for the dots if needed.
|
||||
6. Server: confirm the per-turn log line includes `embed_ms` and
|
||||
`total_ms` (add if Phase 03 omitted it).
|
||||
|
||||
## UI Verification
|
||||
Walk the full state machine by hand (dev server + mock LLM slow path):
|
||||
submit → indicator + "Thinking…" disabled button → live tokens → done
|
||||
(enabled, focused input). Kill the mock mid-stream → banner + recovery.
|
||||
Contrast of disabled button + spinner OK; reduced-motion pass.
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: SSE error event serialization; timeout constant
|
||||
exported/testable; (JS logic is E2E-covered).
|
||||
- Coverage: **>90%** on `app/`.
|
||||
|
||||
## Playwright Execution Phase
|
||||
Run ONLY this story's suite:
|
||||
|
||||
```bash
|
||||
uv run pytest tests/e2e/test_loading_feedback.py -v --no-cov
|
||||
```
|
||||
|
||||
Implements the story mapping (mock LLM's 3s "pretend to think slowly"
|
||||
warm-up + a fixture that stops the mock): typing indicator visible during
|
||||
pre-token and gone by answer; button disabled→"Thinking…"→enabled "Send";
|
||||
streaming appends (two-timestamp length check); LLM-down ⇒ `role=alert`
|
||||
banner + button recovered.
|
||||
|
||||
## Success criteria
|
||||
- [ ] every in-flight state has a visible indicator; button never zombies
|
||||
- [ ] error + 120s timeout paths both recover cleanly
|
||||
- [ ] reduced-motion respected
|
||||
- [ ] unit + integration green, coverage >90%
|
||||
- [ ] story E2E green in isolation
|
||||
- [ ] committed
|
||||
|
||||
## Commit
|
||||
```bash
|
||||
git add -A && git commit --no-gpg-sign -m "feat(ui): explicit chat state machine — typing indicator, streaming progress, timeout and error recovery"
|
||||
```
|
||||
@@ -1,57 +0,0 @@
|
||||
# Phase 07 — Story: Responsive, Polished, Accessible UI
|
||||
|
||||
**Story:** `.agent/user_stories/responsive-polish.md`
|
||||
**Context:** `.agent/PLAN.md` §7 (the whole UI/UX strategy)
|
||||
|
||||
## Goal
|
||||
The final visual + accessibility audit pass across chat and Sources. No
|
||||
new features — enforce PLAN §7 end-to-end and fix every deviation.
|
||||
|
||||
## Implementation steps
|
||||
1. Viewport sweep (360 / 375 / 768 / 1280 / 1600) on both pages: fix
|
||||
overflow, pinched columns, dead whitespace. Chat column stays ≤46rem
|
||||
centered; Sources table full-width with horizontal scroll <640px.
|
||||
2. A11y sweep (both pages): landmarks, skip link, labels on every input,
|
||||
`aria-label` on every icon-only control, `:focus-visible` outline on
|
||||
every focusable, `aria-live` regions intact, no contrast <4.5:1
|
||||
(compute, don't eyeball — use the E2E helper).
|
||||
3. Reduced-motion + long-content pass (60-char paths, long answers).
|
||||
4. No-CDN re-verification on **both** pages (extend the integration test
|
||||
to `/sources.html` if it only covers `/`).
|
||||
5. Final README polish pass: screenshots section (optional), quickstart
|
||||
sanity, "Update your documents" workflow prominent.
|
||||
|
||||
## UI Verification
|
||||
This phase IS the verification: the E2E below is the acceptance test.
|
||||
Additionally, manual screenshot pass at 1280px + 375px for both pages,
|
||||
reviewed against PLAN §7.1–7.4 before committing.
|
||||
|
||||
## Testing & Quality
|
||||
- Integration: no-CDN check extended to Sources page; health unchanged.
|
||||
- Coverage: **>90%** on `app/` (final state of the whole app).
|
||||
- Whole suite green: `uv run pytest` (unit+integration) — the entire
|
||||
repo must be green at this phase.
|
||||
|
||||
## Playwright Execution Phase
|
||||
Run ONLY this story's suite:
|
||||
|
||||
```bash
|
||||
uv run pytest tests/e2e/test_responsive_polish.py -v --no-cov
|
||||
```
|
||||
|
||||
Implements the story mapping: no horizontal overflow at 5 viewports (both
|
||||
pages); chat column capped + centered at 1600px; Sources table ≥80%
|
||||
container at 1280px; landmarks/labels/skip-link sweep; WCAG contrast
|
||||
pairs ≥4.5:1 (computed); reduced-motion honored.
|
||||
|
||||
## Success criteria
|
||||
- [ ] all six mapping tests pass at every viewport
|
||||
- [ ] zero known a11y deviations against PLAN §7.2
|
||||
- [ ] whole pytest suite green + coverage >90%
|
||||
- [ ] README polished
|
||||
- [ ] committed (this commit marks v1.0 feature-complete)
|
||||
|
||||
## Commit
|
||||
```bash
|
||||
git add -A && git commit --no-gpg-sign -m "feat(ui): responsive + WCAG AA polish pass across chat and sources — v1 feature complete"
|
||||
```
|
||||
Reference in New Issue
Block a user