feat(home): Home dashboard (catch-up) + "Open on" landing preference (LC-575) #546

Merged
longjacksonle merged 1 commit from feat/lc575-home-dashboard into main 2026-07-13 16:04:21 +02:00

Resolves LC-575.

Adds a Home dashboard (catch-up) at / for authenticated users, plus an "Open on" landing preference so login can drop you into your last room (unchanged default) or onto the dashboard.

Dashboard

The authed home view (WelcomePage / home/welcome.html) now renders a five-card grid when the user has at least one accessible room or DM (show_dashboard), and keeps the existing onboarding welcome as the empty state for brand-new / no-room accounts. Cards:

  • Catch up - channels with unread, each row the channel + newest-message preview + unread count.
  • Mentions - per-room unread mention counts.
  • Threads - followed threads carrying replies newer than your read watermark.
  • Direct messages - recent DMs with avatars + unread counts.
  • Drafts - rooms / DMs with a fresh unsent draft.

The cards are workspace-wide (the sidebar chrome is enclave-scoped), assembled in a new build_dashboard fan-out that reuses existing helpers: list_room_unread_counts / list_dm_unread_counts drive the count pills, the shared unread inbox (inbox::list_unread) supplies channel/DM names + previews, count_unread_mentions_per_room and room_ids_with_drafts back their own cards, and one new read-only query (thread_followers::followed_threads_with_unread) backs Threads. Each card caps at six rows. No new tables. Rows deep-link to /room/{id}, /dm/{peer}, or /room/{id}#msg-{parent} (threads reuse the existing scroll-to-message fragment). The full-page /room/{id}/info and DM routes are untouched.

"Open on" preference

Plumbed exactly like theme_scale (commit c8f075f9): migration 0039_home_landing.sql adds the nullable home_landing column (NULL = last-room, so no existing user's login behavior moves unless they opt in), the column joins every users SELECT + the row projection, set_user_home_landing persists it, User::home_landing_or_default() validates last-room | home, and a select in the Appearance settings panel submits it with the existing appearance form. routes/home.rs skips the last-visited redirect when the pref is home; ?home=1 (the rail Home tile) still forces the dashboard regardless.

Notes

  • The prototype #home markup was not present on this machine, so the layout follows the app's existing ported component vocabulary (.card / .lc-count-pill / avatar) rather than a literal pixel port. It recolors with the palette/mode tokens like the rest of the ported UI.
  • New UI strings carry en + es keys (home-dash-*, settings-home-landing, home-landing-*).

Verification

just check (server standalone + saas), clippy, fmt all clean. Tests: i18n_catalog 2/2, lib 258, db_auth 19 (migration 0039 applies + new-column SELECTs), routes_settings_theme 6. The new followed_threads_with_unread query was validated against SQLite (correct unread-since-watermark counts).

🤖 Generated with Claude Code

https://claude.ai/code/session_01GJbJChgMXj7m1Q8GdnTPyT

Resolves LC-575. Adds a Home dashboard (catch-up) at `/` for authenticated users, plus an "Open on" landing preference so login can drop you into your last room (unchanged default) or onto the dashboard. ## Dashboard The authed home view (`WelcomePage` / `home/welcome.html`) now renders a five-card grid when the user has at least one accessible room or DM (`show_dashboard`), and keeps the existing onboarding welcome as the empty state for brand-new / no-room accounts. Cards: - **Catch up** - channels with unread, each row the channel + newest-message preview + unread count. - **Mentions** - per-room unread mention counts. - **Threads** - followed threads carrying replies newer than your read watermark. - **Direct messages** - recent DMs with avatars + unread counts. - **Drafts** - rooms / DMs with a fresh unsent draft. The cards are workspace-wide (the sidebar chrome is enclave-scoped), assembled in a new `build_dashboard` fan-out that reuses existing helpers: `list_room_unread_counts` / `list_dm_unread_counts` drive the count pills, the shared unread inbox (`inbox::list_unread`) supplies channel/DM names + previews, `count_unread_mentions_per_room` and `room_ids_with_drafts` back their own cards, and one new read-only query (`thread_followers::followed_threads_with_unread`) backs Threads. Each card caps at six rows. **No new tables.** Rows deep-link to `/room/{id}`, `/dm/{peer}`, or `/room/{id}#msg-{parent}` (threads reuse the existing scroll-to-message fragment). The full-page `/room/{id}/info` and DM routes are untouched. ## "Open on" preference Plumbed exactly like `theme_scale` (commit `c8f075f9`): migration `0039_home_landing.sql` adds the nullable `home_landing` column (NULL = `last-room`, so no existing user's login behavior moves unless they opt in), the column joins every users `SELECT` + the row projection, `set_user_home_landing` persists it, `User::home_landing_or_default()` validates `last-room` | `home`, and a select in the Appearance settings panel submits it with the existing appearance form. `routes/home.rs` skips the last-visited redirect when the pref is `home`; `?home=1` (the rail Home tile) still forces the dashboard regardless. ## Notes - The prototype `#home` markup was not present on this machine, so the layout follows the app's existing ported component vocabulary (`.card` / `.lc-count-pill` / avatar) rather than a literal pixel port. It recolors with the palette/mode tokens like the rest of the ported UI. - New UI strings carry en + es keys (`home-dash-*`, `settings-home-landing`, `home-landing-*`). ## Verification `just check` (server standalone + saas), clippy, fmt all clean. Tests: `i18n_catalog` 2/2, lib 258, `db_auth` 19 (migration 0039 applies + new-column SELECTs), `routes_settings_theme` 6. The new `followed_threads_with_unread` query was validated against SQLite (correct unread-since-watermark counts). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01GJbJChgMXj7m1Q8GdnTPyT
feat(home): Home dashboard (catch-up) + "Open on" landing preference (LC-575)
All checks were successful
check-secrets / Nosey parker (push) Successful in 7s
check-secrets / Kingfisher (push) Successful in 9s
check-secrets / TruffleHog (push) Successful in 9s
check-secrets / Nosey parker (pull_request) Successful in 4s
check-secrets / TruffleHog (pull_request) Successful in 6s
check-secrets / Kingfisher (pull_request) Successful in 7s
Check / clippy + fmt + tests (pull_request) Successful in 3m23s
Create release / Create release from merged PR (pull_request) Has been skipped
359e8f7344
Gives authenticated users a Home dashboard at `/` that answers "what did I miss?" across the whole workspace, plus a preference to choose whether login drops them into their last room (today's behavior) or onto the dashboard.

Dashboard. The authed home view (WelcomePage) now renders a five-card grid when the user has any accessible room or DM, keeping the existing onboarding welcome as the empty state for brand-new/no-room accounts (`show_dashboard`). Cards: Catch up (unread channels + newest-message preview), Mentions (per-room unread mention counts), Threads (followed threads with replies past the read watermark), Direct messages (recent DMs with avatars), Drafts (rooms/DMs with a fresh unsent draft). The cards are workspace-wide (unlike the enclave-scoped sidebar), built in a new `build_dashboard` fan-out that reuses existing helpers: `list_room_unread_counts` / `list_dm_unread_counts` drive the count pills, the shared unread inbox (`inbox::list_unread`) supplies channel/DM names + previews, `count_unread_mentions_per_room` and `room_ids_with_drafts` back their cards, and one new read-only query (`thread_followers::followed_threads_with_unread`) backs Threads. Each card is capped at six rows. No new tables. Rows deep-link to `/room/{id}`, `/dm/{peer}`, or `/room/{id}#msg-{parent}` for threads. Built on the ported token + component look (card / count pill / avatar).

"Open on" preference. Plumbed exactly like `theme_scale` (commit c8f075f9): migration 0039 adds the nullable `home_landing` column (NULL = "last-room", so nobody's login moves unless they opt in), the column joins every users SELECT + the row projection, `set_user_home_landing` persists it, `User::home_landing_or_default()` validates "last-room" | "home", and a control in the Appearance settings panel submits it with the existing form. `routes/home.rs` skips the last-visited redirect when the pref is "home". `?home=1` (the rail Home tile) still forces the dashboard.

The prototype `#home` markup was not available on this machine, so the layout follows the app's existing ported component vocabulary rather than a pixel port.

New strings carry en + es keys. Verified: just check (standalone + saas), clippy, fmt, i18n_catalog (2/2), lib tests (258), db_auth (19, migration applies), routes_settings_theme (6); the new thread query validated against SQLite.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GJbJChgMXj7m1Q8GdnTPyT
longjacksonle scheduled this pull request to auto merge when all checks succeed 2026-07-13 05:31:15 +02:00
longjacksonle deleted branch feat/lc575-home-dashboard 2026-07-13 16:04:21 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!546
No description provided.