feat(pwa): replace top-nav with left sidebar app shell (#140) #161

Merged
james merged 1 commit from 140-app-shell-sidebar into main 2026-06-20 01:34:13 +00:00
Owner

Closes #140.

Summary

  • Replaces the horizontal top nav with a fixed 248px left sidebar at the layout level (app/(app)/layout.tsx). Three grouped sections — Carol surfaces (Chat, Applications) · career data (Profile, Skills, Experience, Projects, Network) · Account — with thin dividers, brand row at the top, pinned footer.
  • Footer: segmented Light/Dark theme switch (round-trips through the existing cookie + PATCH /api/settings flow, ADR-0008) and a user card with avatar initials / name / email / logout button.
  • New placeholder routes /chat (epic #47) and /applications (epic #2) render the existing <Placeholder> component.
  • Carol DS token aliases (--bg, --surface, --accent, --text-*, --radius-*) used directly — no legacy --color-* bridge in new code, per ADR-0023.
  • lucide-react (already in package.json from #7) supplies nav icons.

Removed

Dead code from the old top-nav stack: top-nav.tsx, theme-switcher.tsx, locale-picker.tsx, locale-picker-server.tsx (the top-nav was the sole caller of each).

Out-of-scope notes

  • The "auto" theme preference stays in the registry/init script but isn't surfaced in the sidebar — strict ticket reading is segmented Light/Dark only. Follow-up can re-expose Auto in a settings panel.
  • Locale switching disappears with the locale-picker; it can resurface in the Account-screen rebuild.
  • No ADR added — no new architectural decision (theme persistence is ADR-0008, DS tokens are ADR-0023).

Test plan

  • Lint clean, typecheck clean, 440 vitest tests pass.
  • Live-verified against npm run dev:
    • /profile 200 → sidebar renders, /profile link has data-active="true" aria-current="page".
    • /chat 200 → placeholder renders ("epic #47"), /chat link active.
    • /applications 200 → placeholder renders ("epic #2").
    • Theme switch → PATCH /api/settings returns 200 and sets carol_theme=dark.
    • Logout → Set-Cookie: carol_session= cleared; next /profile request 302 → /login.
  • Manual UAT: sidebar in both themes; keyboard navigation; user card with a profile that has a name set vs. nameless.

🤖 Generated with Claude Code

Closes #140. ## Summary - Replaces the horizontal top nav with a fixed 248px left sidebar at the layout level (`app/(app)/layout.tsx`). Three grouped sections — Carol surfaces (Chat, Applications) · career data (Profile, Skills, Experience, Projects, Network) · Account — with thin dividers, brand row at the top, pinned footer. - Footer: segmented Light/Dark theme switch (round-trips through the existing cookie + `PATCH /api/settings` flow, ADR-0008) and a user card with avatar initials / name / email / logout button. - New placeholder routes `/chat` (epic #47) and `/applications` (epic #2) render the existing `<Placeholder>` component. - Carol DS token aliases (`--bg`, `--surface`, `--accent`, `--text-*`, `--radius-*`) used directly — no legacy `--color-*` bridge in new code, per ADR-0023. - `lucide-react` (already in `package.json` from #7) supplies nav icons. ## Removed Dead code from the old top-nav stack: `top-nav.tsx`, `theme-switcher.tsx`, `locale-picker.tsx`, `locale-picker-server.tsx` (the top-nav was the sole caller of each). ## Out-of-scope notes - The "auto" theme preference stays in the registry/init script but isn't surfaced in the sidebar — strict ticket reading is segmented Light/Dark only. Follow-up can re-expose Auto in a settings panel. - Locale switching disappears with the locale-picker; it can resurface in the Account-screen rebuild. - No ADR added — no new architectural decision (theme persistence is ADR-0008, DS tokens are ADR-0023). ## Test plan - [x] Lint clean, typecheck clean, 440 vitest tests pass. - [x] Live-verified against `npm run dev`: - `/profile` 200 → sidebar renders, `/profile` link has `data-active="true" aria-current="page"`. - `/chat` 200 → placeholder renders ("epic #47"), `/chat` link active. - `/applications` 200 → placeholder renders ("epic #2"). - Theme switch → `PATCH /api/settings` returns 200 and sets `carol_theme=dark`. - Logout → `Set-Cookie: carol_session=` cleared; next `/profile` request 302 → `/login`. - [ ] Manual UAT: sidebar in both themes; keyboard navigation; user card with a profile that has a `name` set vs. nameless. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(pwa): replace top-nav with left sidebar app shell (#140)
Some checks failed
Commits / Conventional Commits (pull_request) Successful in 10s
PR / OSV-Scanner (pull_request) Successful in 35s
PR / Static analysis (pull_request) Successful in 40s
PR / Package age policy (soft) (pull_request) Successful in 27s
Secrets / gitleaks (pull_request) Successful in 24s
PR / Trivy (image) (pull_request) Failing after 1m28s
PR / npm audit (pull_request) Successful in 3m10s
PR / Test (sqlite) (pull_request) Successful in 3m15s
PR / Test (postgres) (pull_request) Successful in 3m17s
PR / Lint (pull_request) Successful in 3m35s
PR / Typecheck (pull_request) Successful in 3m46s
PR / Build (pull_request) Successful in 3m55s
PR / Coverage (soft) (pull_request) Successful in 3m55s
66a615909d
Carol now opens into a sidebar-driven shell — a fixed 248px left rail
with three grouped sections (Carol surfaces · career data · account),
brand row at the top, and a pinned footer with a segmented light/dark
theme switch + user card. Mirrors the DS prototype in
../carol-design/design_files/index.html and uses the Carol DS token
aliases directly (no --color-* bridge).

New routes /chat (epic #47) and /applications (epic #2) render the
existing Placeholder. lucide-react (already in package.json) supplies
the nav icons. Theme persistence still round-trips through the existing
cookie + PATCH /api/settings flow (ADR-0008); the "auto" preference
stays in the registry but isn't surfaced in the sidebar — strict
ticket reading is segmented Light/Dark only, follow-up can re-expose
Auto in a settings panel.

Removed dead code: top-nav.tsx, theme-switcher.tsx, locale-picker.tsx,
locale-picker-server.tsx (the old top-nav was the sole caller of each).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Trivy (container image)

Threshold: high  ·  Total findings: 121  ·  At/above threshold: 1

critical high medium low
0 1 50 70
severity id package installed / range fix
high CVE-2026-12151 undici 6.25.0 6.27.0, 7.28.0, 8.5.0
<!-- scanner-comment: trivy --> ### Trivy (container image) **Threshold:** `high` &nbsp;·&nbsp; **Total findings:** 121 &nbsp;·&nbsp; **At/above threshold:** 1 | critical | high | medium | low | |---:|---:|---:|---:| | 0 | 1 | 50 | 70 | | severity | id | package | installed / range | fix | |---|---|---|---|---| | high | [CVE-2026-12151](https://avd.aquasec.com/nvd/cve-2026-12151) | undici | 6.25.0 | `6.27.0, 7.28.0, 8.5.0` |

📊 Test coverage

Patch coverage: 0.0% (0/159 added lines) ⚠️ (soft target ≥ 80%)

Overall (app/, lib/, db/, excluding UI per ADR-0019):

Metric Value Soft target
Lines 84.3% ≥ 50%
Branches 81.1% ≥ 75%
Functions 89.4% informational

Changed files in this PR (source only — tests excluded):

File Patch coverage Overall lines Branches
app/(app)/components/sidebar-nav.tsx 0.0% (0/40) 0.0% 0.0%
app/(app)/components/sidebar-theme-switcher.tsx 0.0% (0/61) 0.0% 0.0%
app/(app)/components/sidebar.tsx 0.0% (0/58) 0.0% 0.0%

Soft thresholds per ADR-0019. Coverage is informational and does not block merge.

<!-- coverage-comment --> ## 📊 Test coverage **Patch coverage:** 0.0% (0/159 added lines) ⚠️ *(soft target ≥ 80%)* **Overall** (`app/`, `lib/`, `db/`, excluding UI per ADR-0019): | Metric | Value | Soft target | |---|---|---| | Lines | 84.3% ✅ | ≥ 50% | | Branches | 81.1% ✅ | ≥ 75% | | Functions | 89.4% | informational | **Changed files in this PR** (source only — tests excluded): | File | Patch coverage | Overall lines | Branches | |---|---|---|---| | `app/(app)/components/sidebar-nav.tsx` | 0.0% (0/40) | 0.0% | 0.0% | | `app/(app)/components/sidebar-theme-switcher.tsx` | 0.0% (0/61) | 0.0% | 0.0% | | `app/(app)/components/sidebar.tsx` | 0.0% (0/58) | 0.0% | 0.0% | Soft thresholds per [ADR-0019](docs/adr/0019-coverage-soft-targets.md). Coverage is informational and does not block merge.
james merged commit f7aed4d14a into main 2026-06-20 01:34:13 +00:00
james deleted branch 140-app-shell-sidebar 2026-06-20 01:34:13 +00:00
Sign in to join this conversation.
No description provided.