feat(sidebar): per-user channel-category schema + CRUD (LC-79 phase 1a) #129
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-79-sidebar-categories-phase1"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Lands LC-79 phase 1a: the persistence layer and HTMX endpoints for Slack-style per-user channel categories. Phase 1b (sidebar template grouped render + view-struct fan-out) is split into a follow-up PR to keep this diff focused.
Closes LC-79 phase 1a.
Schema
Two new tables in
auth.db(per LC-79's "categorization is private" decision):sidebar_categories (id, user_id, name, position, collapsed, created_at)sidebar_category_rooms (user_id, room_id, category_id, position)withPRIMARY KEY (user_id, room_id)so a room belongs to at most one category per user, andON DELETE CASCADEon category_id so deleting a category drops its assignments but leaves the rooms joined.Position is a sparse integer assigned as
MAX(position) + 1on insert; rebalancing is deferred until drag-and-drop lands.Endpoints
All return the existing flat sidebar fragment via
SidebarUpdateFragment(the same shape WebSocket-driven sidebar updates use). The grouped render arrives in phase 1b.POST /sidebar/categories(create)PATCH /sidebar/categories/{id}(rename / toggle collapsed; either field independent)DELETE /sidebar/categories/{id}(cascade clears assignments)PATCH /sidebar/categories/{id}/rooms/{room_id}(assign; gated byis_room_accessibleso the endpoint cannot disclose private-room existence)DELETE /sidebar/categories/rooms/{room_id}(unassign, falls back to "All rooms")Phase 1b (follow-up PR)
SidebarCategoryGroupview struct + grouped render inpartials/sidebar.html.sidebar_categoriesfield to every view struct that today hassidebar_rooms: &[SidebarRoom](~25 files: views/{enclave,home,bookmarks,admin,pinned,settings,voice,dm,room,not_found}.rs + ws_fragments.rs).Test plan
just check(fmt + clippy across standalone and saas)../dev/cargo test -p lets-chat-server --test routes_sidebar_categories(6 tests pass: create-empty rejects, create persists, rename then delete, cascade clears assignment, assign requires room access, unassign without unjoining).just test(standalone) - all green.just test-saas- one known flake (routes_uploads::send_message_with_attachment_renders_inline_image, passes in isolation; documented in CLAUDE.md test-maintenance section). Unrelated to this PR.curl -X POST -d 'name=Work' /sidebar/categoriesreturns 200 and persists.Drift maintenance
Migration 0016 added to every test file that hand-rolls the auth migration list (CLAUDE.md test-maintenance section 2). Covered both array-form (15 files) and verbose-per-migration shapes (3 files: db_auth.rs, db_invite.rs, rbac.rs).
Lands the persistence layer and HTMX endpoints for Slack-style channel categories (LC-79 phase 1a). Two new tables in auth.db cover the per-user categorization without touching chat.db: `sidebar_categories` (id, user_id, name, position, collapsed, created_at) and `sidebar_category_rooms` (user_id, room_id, category_id, position) with `ON DELETE CASCADE` so deleting a category drops its room assignments but leaves the rooms themselves joined. Endpoints (all return the existing sidebar fragment so the requesting tab refreshes; the grouped render lands in phase 1b alongside the view-struct fan-out): - `POST /sidebar/categories` (create) - `PATCH /sidebar/categories/{id}` (rename / toggle collapsed) - `DELETE /sidebar/categories/{id}` (cascade clears assignments) - `PATCH /sidebar/categories/{id}/rooms/{room_id}` (assign; gated by `is_room_accessible` so the endpoint cannot disclose private-room existence) - `DELETE /sidebar/categories/rooms/{room_id}` (unassign, falls back to "All rooms") Phase 1b will add `SidebarCategory` view structs, thread them through every page (~25 construction sites in views/{enclave,home,bookmarks,admin,pinned,settings,voice,dm,room,not_found}.rs + ws_fragments.rs), and rewrite `partials/sidebar.html` to render grouped. Splitting keeps this PR's diff focused on schema + endpoints; the view fan-out is mechanical and lands separately. Drift maintenance: added migration 0016 to every test file that hand-rolls the auth migration list (CLAUDE.md test-maintenance section 2). Both array-form and verbose-per-migration shapes covered.