feat(rooms): room info page with description + wiki (LC-86) #150
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-86-room-docs-wiki"
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?
Closes LC-86. Adds a
/room/{id}/infopage surfacing a long-form room description, a single wiki page, and (in a separate tab) the existing pinned-message list. Wiki and description bodies render through the same Markdown pipeline (views::markdown, LC-59) chat messages use, so:emoji:shortcodes resolve the same way.Schema
rooms.description,rooms.wiki_body,rooms.wiki_updated_at,rooms.wiki_updated_by(all nullable). Existing rooms unchanged. Absence ofwiki_bodyis the "no wiki yet" signal the template branches on.Code
models::Roomgains the four new fields; everySELECT * FROM roomssite updated.db::chat::set_room_descriptionandset_room_wikiwrite the columns.set_room_wikistampswiki_updated_at = datetime('now')andwiki_updated_byon save; an empty body clears all three fields.routes::room_infomodule: GET/room/{id}/inforenders the page (?tab=docs default, ?tab=pinned).GET /room/{id}/wikireturns the view fragment (cancel button target).GET /room/{id}/wiki/editreturns the inline textarea (Mod+ only via LC-84is_room_moderator).PATCH /room/{id}/wikiwrites the body + stamps metadata + logsroom_wiki_editaudit row + returns rendered HTML. Description mirrors the triplet, gated on the admin-tierroom_can_manage_overrides.routes::enclave::post_edit_roomnow also callsset_room_descriptionso the existing enclave-admin room-edit form can set it in one round trip.#room-nameblock is now an<a>to/room/{id}/info, plus an explicit "Info" button in the header action row so the page is also reachable when no topic is set.UI
?tab=anchor links (keyboard / screen-reader native, no HTMX dependence for navigation). Two HTMX-swappable slots inside the docs tab handle inline editing:#description-contentand#wiki-content. Save: PATCH and swap. Cancel: re-fetch view fragment and swap.Acceptance criteria coverage
/info).wiki_updated_at/wiki_updated_byon the row +room_wiki_editaction log).PATCH /room/:id/wikiand renders the updated content in place.Out of scope (open questions, deferred)
message_edits).Tests
routes_room_info.rs(6/6 passing): member can view the page; member 403s on PATCH wiki and description; admin can PATCH wiki (returns rendered HTML, writes audit row); admin can PATCH description; empty wiki body clears all three columns.just checkclean.just test/just test-saaspass aside from the pre-existingroutes_uploadsconcurrent-binary flake (CLAUDE.md-noted, out of scope).Migration drift: 0030 added to the seven hand-list test files (
db_uploads,uploads_sweep,routes_reconnect,routes_uploads,db_enclave,admin_uploads,db_private_rooms).common::poolcallers pick it up viasqlx::migrate!.A new `/room/{id}/info` page surfaces the room's long-form description, a single wiki page, and (via a tab) the existing pinned-message list. Wiki and description bodies render through the same Markdown pipeline (`views::markdown`, LC-59) chat messages use, so custom emoji shortcodes resolve the same way. Topic remains a header-only field; this PR adds editable storage for the longer description and the wiki. Schema - Migration 0030 adds `rooms.description`, `rooms.wiki_body`, `rooms.wiki_updated_at`, `rooms.wiki_updated_by` (all nullable). Existing rooms come out unchanged because the ALTER does not back-fill, and absence of `wiki_body` is the "no wiki yet" signal the template branches on. Code - `models::Room` gains the four new fields. `db::chat::map_room` and every `SELECT * FROM rooms` site updated (single-table queries get the bare column names, joined queries qualify with `r.`). - `db::chat::set_room_description(pool, room_id, body)` and `set_room_wiki(pool, room_id, body, actor)` write the new columns. `set_room_wiki` stamps `wiki_updated_at = datetime('now')` and `wiki_updated_by` on save; passing `None` for the body clears all three fields. - New `routes::room_info` module: `GET /room/{id}/info` renders the page with tab nav (`?tab=docs` default, `?tab=pinned`). `GET /room/{id}/wiki` returns the rendered view fragment (used by the cancel button). `GET /room/{id}/wiki/edit` returns the inline textarea editor (Mod+ only). `PATCH /room/{id}/wiki` writes the body, stamps metadata, logs a `room_wiki_edit` mod-action row, and returns the re-rendered view fragment. Description has the same `GET / GET edit / PATCH` triplet, gated on the admin-tier `room_can_manage_overrides` predicate (same as moderator-grant authorisation). - `routes::enclave::post_edit_room` now also calls `set_room_description` so the existing enclave-admin room-edit form can set the description in one round trip (the form already takes `name` and `topic`). - `routes::pinned::resolve_author_labels` exposed as `pub(crate)` so the info page can build pinned-tab rows without duplicating the bulk auth-lookup helper. - `partials/room_header.html`: the topic / room-name block is now a single link to `/room/{id}/info`, plus a new "Info" button in the header action row so the page is also reachable when there is no topic to click. UI - `templates/room/info.html` is the page. Tab nav is plain anchor links (`?tab=`) so the page is keyboard / screen-reader native; no HTMX dependence for navigation. Two HTMX-swappable slots inside the docs tab handle inline editing: `#description-content` and `#wiki-content`. The edit forms swap a textarea in place; save submits via `PATCH` and replaces the slot with the rendered view; cancel re-fetches the read-only fragment. Audit log - Wiki saves record `room_wiki_edit` rows. Description edits do not currently log (admin-tier action with no security stake beyond the visible body; we can add a row in a follow-up if anyone cares). Out of scope (open questions, deferred) - Wiki revision history (append-only table like `message_edits`). - Wiki full-text search. - Per-enclave shared wikis. Tests - New integration binary `routes_room_info.rs` (6/6 passing): member can view the page, member cannot PATCH wiki or description (403), admin can edit wiki (200 + audit row), admin can set description (200), and an empty wiki PATCH clears all three wiki columns. - `just check` clean. Migration drift: 0030 added to the seven hand-list tests (`db_uploads`, `uploads_sweep`, `routes_reconnect`, `routes_uploads`, `db_enclave`, `admin_uploads`, `db_private_rooms`). Tests under `common::pool` pick it up via `sqlx::migrate!`.