• v0.2.0 8bb8b6dd55

    v0.2.0
    Some checks failed
    check-secrets / Nosey parker (push) Successful in 3s
    Publish release artifacts / Build + publish lets-chat-desktop binaries (push) Failing after 3s
    check-secrets / Kingfisher (push) Successful in 9s
    check-secrets / TruffleHog (push) Successful in 16s
    Build desktop (Windows) / Build desktop (Windows x86_64) (release) Successful in 3m36s
    Build desktop (Linux) / Build desktop (Linux x86_64) (release) Successful in 4m55s
    Check / clippy + fmt + tests (push) Successful in 5m56s
    Build desktop (Windows) / Build desktop (Windows x86_64) (push) Successful in 8m36s
    Build OCI container / Build and push lets-chat (push) Successful in 12m5s
    Build desktop (Linux) / Build desktop (Linux x86_64) (push) Successful in 15m16s
    Stable

    David released this 2026-07-23 05:41:48 +02:00 | 190 commits to main since this release

    Changelog

    8bb8b6dd Merge pull request 'Release v0.2.0' (#581) from release/v0.2.0 into main
    aa755a55 Release v0.2.0
    db192d53 Merge pull request 'Reactions on thread replies, in their own id namespace (LC-595)' (#580) from feat/lc595-thread-reactions into main
    120c7096 feat(reactions): reactions on thread replies, in their own id namespace (LC-595)
    c0960d00 Merge pull request 'STT cost/load control: bounded concurrency, rate limits, scope gating (LC-592)' (#579) from feat/lc592-stt-load-control into main
    a4b430f6 feat(stt): bound STT concurrency, rate, and scope (LC-592)
    5ca2d38d Merge pull request 'STT reliability: timeout, retry, and surfaced failure state (LC-590)' (#578) from feat/lc590-stt-reliability into main
    57f5b364 feat(stt): timeout, retry, and surfaced transcription failures (LC-590)
    a456a957 Merge pull request 'STT provider seam with native Deepgram support (LC-593)' (#577) from feat/lc593-stt-providers into main
    f6207c32 feat(stt): provider seam with native Deepgram support (LC-593)
    31e3b434 Merge pull request 'STT language + prompt hinting and real segment timestamps (LC-591)' (#576) from feat/lc591-stt-accuracy into main
    c9d41fb0 feat(stt): language + prompt hinting and real segment timestamps (LC-591)
    299efaa5 Merge pull request 'Extract the shared bus-drain and control-dispatch machinery (LC-616)' (#575) from refactor/lc616-rtc-machinery into main
    5dfa68fa refactor(rtc): extract the shared bus-drain and control-dispatch machinery (LC-616)
    2b651922 Merge pull request 'Unify the call/huddle session lifecycle across the clients (LC-613)' (#574) from refactor/lc613-converge-rtc-clients into main
    2035f1b7 refactor(rtc): unify the call/huddle session lifecycle across the clients (LC-613)
    4788c6b0 Merge pull request 'Cover the 1:1 ring and huddle WS handlers (LC-614)' (#573) from test/lc614-call-huddle-coverage into main
    82b46e08 test(call): cover the 1:1 ring and huddle WS handlers (LC-614)
    b1181b7f Merge pull request 'Show an in-call indicator when a room has an active huddle (LC-612)' (#572) from feat/lc612-sidebar-incall into main
    47c40a40 feat(sidebar): show an in-call indicator when a room has an active huddle (LC-612)
    cb0a98e4 Merge pull request 'Carry huddle media over the SFU when LiveKit is configured (LC-610)' (#571) from feat/lc610-sfu-huddle-media into main
    efb81bff feat(huddle): carry huddle media over the SFU when LiveKit is configured (LC-610)
    2aa94c7c Merge pull request 'Ring room members when a huddle starts (LC-611)' (#570) from feat/lc611-huddle-ring into main
    396bee65 feat(huddle): ring room members when a huddle starts (LC-611)
    0694c301 Merge pull request 'Mint SFU tokens for huddles, and stop stages colliding with them (LC-596)' (#569) from feat/lc596-sfu-huddle-tokens into main
    ccd9649b feat(huddle): mint SFU tokens for huddles, and stop stages colliding with them (LC-596)
    aef25047 Merge pull request 'Transcribe a Stage, gated to whoever holds the floor (LC-597)' (#568) from feat/lc597-stage-transcription into main
    5a82f556 feat(stage): transcribe a Stage, gated to whoever holds the floor (LC-597)
    9e2f8b1d Merge pull request 'Tell an unkeyed build why it cannot self-update (LC-607)' (#567) from fix/lc607-updater-fails-before-network into main
    08b4f0e9 fix(desktop): tell an unkeyed build why it cannot self-update (LC-607)
    b2456479 Merge pull request 'Drop the DELETE FROM rooms crutch from the onboarding fixture (LC-603)' (#566) from test/lc603-onboarding-reachability into main
    ddec0a54 test(home): drop the DELETE FROM rooms crutch from the onboarding fixture (LC-603)
    81f651dd Merge pull request 'Make the login-approval attempt cap atomic (LC-608)' (#565) from fix/lc587-atomic-attempt-cap into main
    cc3f5835 fix(auth): make the login-approval attempt cap atomic (LC-608)
    3a050333 Merge pull request 'Fail fast on missing psa-systems org secrets, and stop shipping the old org's update URL (LC-594)' (#564) from chore/lc594-psa-systems-ci-secrets into main
    0abe6bbf fix(ci): correct the package owner to psa-systems-private
    ded73692 chore(ci): fail fast on missing psa-systems org secrets, fix stale update URL
    f602242e Merge pull request 'Gate DM Delete on the effective room role, not the org role (LC-599)' (#563) from fix/lc599-dm-delete-uses-effective-role into main
    fb812cff fix(dm): gate Delete on the effective room role, not the org role
    e612bb6c Merge pull request 'Scope the remaining room-visibility queries to the viewer's enclaves (LC-606)' (#562) from fix/lc606-scope-remaining-room-queries into main
    cc851be1 fix(db): scope the remaining room-visibility queries to the viewer's enclaves
    c4c64938 Merge pull request 'Run the integration tests in CI, and make the fixture check real (LC-605)' (#561) from fix/lc605-ci-runs-integration-tests into main
    b242f179 ci: run the integration tests, and make the fixture check real
    9590fcee Merge pull request 'Scope unread inbox + dashboard queries to the viewer's enclaves (LC-604)' (#560) from fix/lc604-inbox-enclave-scoping into main
    550069c2 fix(inbox): scope unread queries to the viewer's enclaves
    98a05c65 Merge pull request 'Cover both branches of / after the LC-575 dashboard (LC-600)' (#558) from fix/lc600-home-branch-tests into main
    9bbadc1c Merge pull request 'fix(auth): make login-approval consume atomic to close a TOCTOU (LC-601)' (#557) from fix/LC-601-login-approval-consume-toctou into main
    dfae0903 test(home): cover both branches of / after the LC-575 dashboard
    b1ce19e7 fix(auth): make login-approval consume atomic to close a TOCTOU (LC-601)
    28352522 Merge pull request 'Group the message overflow menu into scannable sections (LC-598)' (#556) from feat/lc-message-menu-grouping into main
    744bfc08 feat(room): group the message overflow menu into scannable sections
    4018da48 Merge pull request 'fix(ci): use the psa-systems package vars after the org move' (#554) from fix/ci-psa-systems-package-vars into main
    67d45da6 Merge pull request 'feat(auth): notify-and-approve gate for suspicious logins (LC-587)' (#555) from feat/LC-587-suspicious-login-approval into main
    add21bb0 feat(auth): notify-and-approve gate for suspicious logins (LC-587)
    770f3cbe fix(ci): use the psa-systems package vars after the org move
    526b6e49 Merge pull request 'Reactions that actually work, sidebar expand ribbon, huddle transcription' (#553) from feat/sidebar-collapse-ribbon into main
    15edf7d6 style(reactions): rustfmt the toggle_reaction insert
    0b05fbcc feat(transcription): support transcription in huddles
    03c8cd4f feat(sidebar): expand the collapsed sidebar from a ribbon on the rail seam
    0f34bf5c fix(reactions): atomic toggle + populate the one-tap quick-react bar
    0a153a1f feat(reactions): working emoji picker from the hover bar; conditional add-more
    1b61c3cc feat(settings): dismiss the settings page by clicking outside it or Escape
    e1c66b23 fix(thread): make typed text visible in the thread reply box
    25557987 Merge pull request 'Redesign chat UI to the prototype: rail, sidebar, panels, composer, settings' (#552) from fix/lc-576-active-row-invert into main
    3d57cb17 fix(composer): stop clipping the paperclip attachment icon
    a8a7db56 feat(thread): emoji picker for thread replies; fix attachment clipping
    28cdbe33 style(header): space between the # and the room name
    822ec4de style(timeline): merge adjacent mentioned messages into one accent block
    9b8c5044 style(composer): shrink the attachment icon so it doesn't clip
    06913c8f fix(sidebar): draft indicator is an SVG pencil, not a tofu dingbat
    963188bd style(settings): full-bleed palette preview cards
    1bc3da09 fix(rail): hide the profile hovercard while the account menu is open
    c59ee614 feat(room): close Details/Thread with an X; info toggles Details
    cab27504 style(composer): stopwatch glyph for the self-destruct timer
    54afdc4d feat(sidebar): render the @-mention badge on DM rows
    64e5662f style(composer): rework the self-destruct timer into a clock popover
    9624a579 feat(room): header member avatar stack and correct public-room member count
    49efc47e style(settings,sidebar): 4-up palette cards; shorter search placeholder
    c36ce47f feat(dev): mock OIDC can authenticate multiple identities
    5a0f29cc feat(room,sidebar): right-column collapse, platform-aware ⌘K, search icon
    df04002a style(settings): mini-window palette preview cards
    8d233a68 style(thread): accent-color the replied-to name in the thread header
    ed26a2fb feat(rail): curated settings dropdown and avatar hovercard
    8dd411eb style(details,rail): notifications dropdown chevron; accent unread badge
    99ae64c7 style(settings,timeline): comp-style Appearance controls; bare day divider
    fb72feb0 style(sidebar): add ⌘K search hint chip and focus binding
    4f8c5eff Merge remote-tracking branch 'origin/main' into fix/lc-576-active-row-invert
    06df7325 Merge pull request 'fix(auth): link bunyip_sub onto an existing verified-email account on SSO (LC-588)' (#551) from fix/LC-588-sso-email-link into main
    27b1df29 fix(auth): link bunyip_sub onto an existing verified-email account on SSO (LC-588)
    cf67ebcd Merge pull request 'feat(auth): alert users on a new-country login (LC-580)' (#550) from feat/lc580-login-location-alerts into main
    f4072213 fix(auth): show the full country name in the login-location alert (LC-580)
    11ee2e0a feat(auth): alert users on a new-country login (LC-580)
    d498e740 Merge pull request 'feat(dev): mock OIDC OP can authenticate for the local dev stack (LC-577)' (#549) from feat/lc577-mock-oidc-auth into main
    1135afd6 feat(dev): make the mock OIDC OP able to actually authenticate
    cb0080ec Merge pull request 'feat(enclave): surface configurable enclave icon on the settings page (LC-542)' (#548) from feat/lc542-enclave-icon-settings into main
    9b1b5344 feat(enclave): surface configurable enclave icon on the settings page (LC-542)
    fc3917cd Merge pull request 'fix(sidebar): invert glyph, draft pencil, and DM status on active row (LC-576)' (#547) from fix/lc576-active-row-invert into main
    d11c96b6 fix(sidebar): invert glyph, draft pencil, and DM status on active row (LC-576)
    a84a1481 Merge pull request 'feat(home): Home dashboard (catch-up) + "Open on" landing preference (LC-575)' (#546) from feat/lc575-home-dashboard into main
    359e8f73 feat(home): Home dashboard (catch-up) + "Open on" landing preference (LC-575)
    6db89f97 Merge pull request 'fix(i18n): correct Spanish room-details-pinned-yes to «Sí» (LC-579)' (#545) from fix/lc-579-es-pinned-yes-accent into main
    6839c2ec fix(i18n): correct Spanish room-details-pinned-yes to «Sí» (LC-579)
    689a055f Merge pull request 'chore(css): remove dead .lc-empty-wrap helper (LC-578)' (#544) from chore/lc-578-remove-dead-lc-empty-wrap into main
    5d470673 chore(css): remove dead .lc-empty-wrap helper (LC-578)
    bdee3bc3 feat(ui): one profile control in the rail, and rail ordering
    7a83cd96 feat(ui): one right column of subcards, and rail cleanup
    079ad180 feat(ui): restructure the sidebar and room header to the prototype
    8f736f21 feat(dev): make the mock OIDC OP able to actually authenticate
    a270f720 fix(ui): invert active-row glyphs and align thread/details/header to the prototype
    5e327d68 Merge pull request 'Apply the prototype new look across Let's Chat (phased)' (#539) from feat/lc-ui-port into main
    850a3f5d Merge branch 'main' into feat/lc-ui-port
    cee7ac0c Merge remote-tracking branch 'origin/main' into feat/lc-ui-port
    1b9c193e Merge pull request 'Rewrite Phase 3 plan with verified literal pixel-match gaps' (#538) from docs/pixel-match-phase3-literal-gaps into main
    0aec7dc4 test(chat): regenerate message fixtures for the new row geometry
    43eef075 Merge branch 'main' into docs/pixel-match-phase3-literal-gaps
    3bc4a417 style(room): give the room-info page the prototype hero
    03740847 test(dev): mirror the chat surface into the theme gallery
    5917e452 Merge pull request 'feat(composer): one-row restructure (LC-574)' (#543) from feat/lc574-composer-onerow into main
    3211d38f style(chat): reconcile the chat surface to the prototype
    d2204602 feat(composer): one-row restructure (LC-574)
    c8f075f9 feat(theme): server-persisted UI scaling (compact/default/large/xl)
    e7dddbff Merge pull request 'feat(timeline): polish room message hierarchy (LC-558)' (#542) from feat/lc558-timeline-polish into main
    33486fef feat(timeline): polish room message hierarchy (LC-558)
    b120661f Merge pull request 'fix(a11y): call-button 44x44 tap targets on touch (LC-573)' (#541) from feat/lc573-call-button-tap-targets into main
    a5f51a64 fix(a11y): call-button 44x44 tap targets on touch (LC-573)
    49acefb3 Merge pull request 'feat(admin): shared page-header component (LC-572)' (#540) from feat/lc572-admin-page-header into main
    385a81c2 feat(admin): shared page-header component (LC-572)
    07eeeb97 style(theme): contrast + surface-separation fixes across all palettes
    4da139ee docs(plan): rewrite Phase 3 with verified literal pixel-match gaps
    4bfca656 Merge pull request 'Mockup pixel-match: amethyst palette + room Details panel' (#537) from docs/lets-chat-mockup-pixel-match into main
    133e242e Merge branch 'main' into docs/lets-chat-mockup-pixel-match
    a770e987 Merge pull request 'docs: redesign completion roadmap + LC-UI tail reconcile' (#536) from docs/LC-553-redesign-tail-roadmap into main
    e6cb452f feat(dev): mock OIDC OP so dev-web-local boots without bunyip
    d2e30e67 docs(lets-chat): note SSO env requirement for local boot
    aeea958a docs(lets-chat): overnight progress log + morning screenshot checklist
    b6cc3b99 style(connection): theme the connection-status banner via tokens
    5d832fe7 feat(room): mount Details panel in the room right column
    88b81b9a feat(room): add Details panel partial
    510a3fd7 feat(room): add Details panel locale keys
    142c90ff refactor(room): expose member count and pinned flag to the room page view
    6ef017f1 fix(theme): render amethyst on load and tint its hc-dark accent surface
    9edd1d01 feat(theme): show amethyst in dev theme gallery
    bc94a7ff feat(theme): add amethyst swatch to settings picker
    682df62e feat(theme): allow amethyst palette in backend validation
    df605acc test(theme): cover amethyst palette in contrast checker
    2f0e88dd feat(theme): add amethyst violet palette tokens
    c54dba37 docs(lets-chat): plan the mockup pixel-match overhaul
    84cf107e docs(redesign): completion roadmap + tail reconcile
    14103395 Merge pull request '44px touch targets on the redesign icon controls (coarse pointer)' (#535) from feat/mobile-tap-targets into main
    b20f16f2 feat(a11y): 44px touch targets on the redesign icon controls (coarse pointer)
    a19f294b Merge pull request 'Migrate hand-rolled callout boxes to the .alert component (redesign follow-up)' (#534) from refactor/alert-component-migration into main
    1491843a refactor(ui): migrate hand-rolled callout boxes to the .alert component
    19e2f028 Merge pull request 'LC-565: a11y regression pass - composer focus ring + phantom danger token (redesign P5)' (#533) from fix/LC-565-a11y-regression-pass into main
    eda0b36f fix(a11y): composer focus ring + fix phantom danger-surface-content token (LC-565 / LC-UI-12)
    350966a2 Merge pull request 'LC-564: route login + welcome errors through the shared alert (redesign P5)' (#532) from feat/LC-564-entry-surface-alignment into main
    046fa0dc feat(entry): route login + welcome errors through the shared alert (LC-564 / LC-UI-11)
    79a5a4c2 Merge pull request 'LC-561: unify admin status indicators onto one chip vocabulary (redesign P3)' (#531) from feat/LC-561-admin-status-chips into main
    82b7251e feat(admin): unify status indicators onto one status-chip vocabulary (LC-561 / LC-UI-08)
    7b177512 Merge pull request 'LC-557: tokenize empty-state color residuals (redesign P3)' (#530) from fix/LC-557-empty-state-residuals into main
    bfbf2ebb fix(ui): tokenize empty-state color residuals (LC-557 / LC-UI-04)
    b860c6d9 Merge pull request 'LC-559: lift the composer onto an elevated card (redesign P2)' (#529) from feat/LC-559-composer-polish into main
    0e99d2b0 feat(composer): lift the composer onto an elevated card (LC-559 / LC-UI-06)
    9dd20357 Merge pull request 'LC-566: six-palette theme system foundation (redesign P1)' (#528) from docs/LC-541-redesign-p1-foundation into main
    e0fd465c fix(theme): persist palette on select; darkMode hc-dark
    8f5101a2 fix(theme): repoint JS data-theme reads to data-mode
    8641ce03 feat(theme): add .lc-table; retune radii/shadow
    b29d7d25 fix(theme): HC accent AAA + max-contrast ring
    1d1202d2 feat(theme): dev theme/component gallery
    388dcd63 fix(i18n): add es keys for palette picker
    b7e12fe4 feat(theme): appearance picker with palette swatches
    6c5f4cb9 feat(theme): two-axis no-flash bootstrap (palette + mode)
    ceff72f2 feat(theme): add 5 palettes across light/dark/hc
    fc0ee383 refactor(theme): split tokens into constant + palette layers
    8591825b feat(theme): key Tailwind dark: on data-mode
    4d6247d2 feat(theme): sync lc-mode + lc-palette cookies cross-device
    ad4ff3da feat(theme): persist palette; rename mode cookie to lc-mode
    142fefab feat(theme): db setters for mode + palette
    f8d78a35 feat(theme): mode + palette accessors on User
    c02de9d5 feat(theme): split theme pref into mode + palette
    39cb409f docs(redesign): P1 foundation implementation plan
    5c9c1b12 docs(redesign): P1 foundation design spec
    12da86bb Merge pull request 'fix(room): tokenize the inline edit form (LC-558)' (#527) from feat/LC-558-timeline-polish into main
    bb733f94 fix(room): tokenize the inline edit form so it themes correctly (LC-558 / LC-UI-05)
    183d9e81 Merge pull request 'feat(sidebar): dark-navy Blue Harbor sidebar + rail (LC-560)' (#526) from feat/LC-560-navy-sidebar into main
    9811b614 Merge pull request 'feat(css): add .alert* + layout-helper component classes (LC-555)' (#524) from feat/LC-555-alert-classes into main
    08b3718b Merge remote-tracking branch 'origin/feat/LC-555-alert-classes' into feat/LC-555-alert-classes
    a5ff2636 Merge remote-tracking branch 'origin/main' into feat/LC-555-alert-classes
    f604320e feat(sidebar): dark-navy Blue Harbor sidebar + rail in all themes (LC-560 / LC-UI-07)
    21e202b1 Merge pull request 'feat(css): add .lc-page-* width + layout utilities (LC-562)' (#525) from feat/LC-562-page-width-utils into main
    0ef4bb19 feat(css): add .lc-page-* width + layout utilities (LC-562 / LC-UI-09)
    1ee70a70 Merge branch 'main' into feat/LC-555-alert-classes
    4c65e961 feat(css): add .alert* + layout-helper component classes (LC-555 / LC-UI-02)
    e5a7dcb9 Merge pull request 'feat(css): add --sidebar-* chrome tokens (LC-554 phase 1b)' (#523) from feat/LC-554-sidebar-tokens into main
    73a15b8e feat(css): add --sidebar-* chrome tokens for all four themes (LC-554 phase 1b)
    c2d94d36 Merge pull request 'feat(css): Blue Harbor semantic-token retune (LC-554 phase 1a)' (#522) from feat/LC-554-blue-harbor-tokens into main
    ea4326f0 feat(css): retune semantic tokens to Blue Harbor (LC-554 phase 1a)
    8fcc6da4 Merge pull request 'feat(enclave): graduated member trust + posting gate (LC-551)' (#521) from feat/LC-551-trust-levels into main
    bb017eed test(routes): graduated member trust coverage (LC-551)
    1591c009 feat(enclave): trust pill + manual promote in the member list (LC-551)
    37014a60 feat(room): gate new-member posting rate and auto-graduate on send (LC-551)
    8a05b362 feat(db): enclave member trust column + graduation helpers (LC-551)
    dacdab02 Merge pull request 'feat(markdown): mermaid diagram rendering (LC-550)' (#520) from feat/LC-550-mermaid-diagrams into main
    e1269660 feat(assets): vendored mermaid + lazy-loading diagram enhancement (LC-550)
    0d28e860 feat(markdown): render ```mermaid fences as diagram containers (LC-550)
    209014bb Merge pull request 'feat(search): semantic / related-message search (LC-549)' (#519) from feat/LC-549-semantic-search into main
    0fdb724f test(routes): related + semantic search integration coverage (LC-549)
    cf447c29 i18n: related-search and semantic-toggle strings (LC-549)
    9baa892c feat(search): opt-in semantic search mode that degrades to FTS (LC-549)
    f0a8a4f8 feat(search): "Find related" messages backed by embeddings (LC-549)
    8533adb2 feat(state): wire embeddings client into AppState + config (LC-549)
    52135426 feat(db): message_embeddings sidecar table + storage and by-ids fetch (LC-549)
    de5254ac feat(embeddings): operator embeddings client with cosine + serde helpers (LC-549)
    d8afed98 Merge pull request 'feat(messages): AI suggested replies (LC-548)' (#518) from feat/LC-548-suggest-reply into main
    69142aa2 test(routes): integration coverage for suggested replies (LC-548)
    5edc37b5 i18n(room): suggested-reply menu label and panel heading (LC-548)
    0d7318d3 feat(ui): suggest-reply chips in the message menu, applied via the composer panel (LC-548)
    b8cc9c14 feat(routes): AI suggested-reply endpoint with chip parser (LC-548)
    5984b9a8 Merge pull request 'feat(error): friendlier generic error page (LC-552)' (#517) from feat/LC-552-friendly-error-page into main
    a89fc0c0 feat(error): redesign the generic error page, hide only internal detail (LC-552)
    2edec3c3 i18n(error): friendly per-status error-page descriptions (LC-552)
    2778e292 Merge pull request 'feat(messages): ephemeral / self-destruct messages (LC-547)' (#516) from feat/LC-547-ephemeral-messages into main
    e3f5e06f test(messages): sweep + composer coverage for ephemeral messages (LC-547)
    1361417b feat(composer): self-destruct timer select wired into post_message (LC-547)
    53bf6731 feat(messages): schedule the unconditional ephemeral sweeper (LC-547)
    61c3fb87 feat(retention): unconditional sweep for expired ephemeral messages (LC-547)
    fba7631c feat(messages): expires_at column + TTL parsing for self-destruct (LC-547)
    361ba0bc Merge pull request 'feat(threads): per-thread mute (LC-546)' (#515) from feat/LC-546-per-thread-mute into main
    48c10000 test(threads): db + route coverage for per-thread mute (LC-546)
    296e9102 feat(threads): mute toggle route, button, and thread-panel wiring (LC-546)
    ef610ee2 feat(threads): suppress muted followers from thread reply fan-out (LC-546)
    e9b81d91 feat(threads): thread_muters table + data layer (LC-546)
    e15e58b9 Merge pull request 'chore(repo): publish-readiness sanitization sweep (LC-521)' (#514) from chore/LC-521-publish-sanitization into main
    f009947c chore(ci): drop trufflehog --exclude-paths and the empty exclude file (LC-521)
    c2d89992 chore(repo): publish-readiness sanitization sweep (LC-521)
    0c607396 Merge pull request 'fix(enclave): friendly redirect for invalid/revoked invite code (LC-544)' (#513) from fix/LC-544-friendly-invalid-invite-code into main
    fa92f0ae test(enclave): assert discover renders the invalid-invite-code banner (LC-544)
    28ef74f6 fix(enclave): friendly redirect for invalid/revoked invite code (LC-544)
    627935c8 Merge pull request 'feat(uploads): accessible image alt text (LC-537)' (#512) from feat/LC-537-image-alt-text into main
    ab1090b6 test(uploads): alt-text round-trip + author-gated editor route (LC-537)
    31a0ce0c feat(uploads): author alt-text editor with live re-render (LC-537)
    4c12202b feat(uploads): store image alt text (LC-537)
    14772e09 Merge pull request 'feat(stats): personal member-stats recap page (LC-536)' (#511) from feat/LC-536-member-stats into main
    8a10f798 test(stats): member_stats aggregation + /stats page render (LC-536)
    2d747528 feat(stats): personal stats recap page at /stats (LC-536)
    6c7a0e5b feat(stats): personal member-stats aggregation (LC-536)
    ead0527d Merge pull request 'feat(profile): pronouns, links & local time on profiles (LC-533)' (#510) from feat/LC-533-profile-extras into main
    ff965166 test(profile): profile-extras round-trip + hovercard privacy gate (LC-533)
    7939228a feat(profile): show pronouns, links, local time on the hovercard (LC-533)
    61bff2c6 feat(profile): edit pronouns, links, timezone in settings (LC-533)
    b1e1315a feat(profile): pronouns, links, timezone columns + model plumbing (LC-533)
    2184b50a Merge pull request 'feat(mute): auto-expiring timed mutes (LC-535)' (#509) from feat/LC-535-timed-mutes into main
    f71dee54 test(mute): expiry sweep lifts past mutes, spares permanent and future (LC-535)
    d6492bbb feat(mute): timed-mute duration picker in the admin user table (LC-535)
    4e0c9d60 feat(mute): honour mute expiry at every posting gate (LC-535)
    0189ef34 feat(mute): auto-expiring timed-mute core (LC-535)
    7c46cabf Merge pull request 'feat(branding): standardize "Let's Chat" display name; guard tab title (LC-538)' (#508) from feat/LC-538-standardize-name-casing into main
    2de2c5d3 feat(branding): standardize "Let's Chat" display name; guard tab title (LC-538)
    e4e25189 Merge pull request 'feat(room): per-channel slowmode (LC-534)' (#507) from feat/LC-534-slowmode into main
    d6662ee9 test(slowmode): end-to-end enforcement, off, and mod-exempt (LC-534)
    8d3e2a64 feat(slowmode): room-manage control to set the cooldown (LC-534)
    0f11e577 feat(slowmode): enforce per-channel slowmode in post_message (LC-534)
    077ccbba feat(slowmode): rooms.slowmode_seconds column + cooldown limiter (LC-534)
    5629c7eb Merge pull request 'feat(compose): AI writing assistant in the composer (LC-532)' (#506) from feat/LC-532-composer-ai-assist into main
    07089ce9 test(compose): end-to-end AI-assist happy path + gates (LC-532)
    30f0e596 feat(compose): wire the AI-assist button, panel slot, and apply/dismiss (LC-532)
    168597f0 feat(compose): AI writing-assistant endpoint + result panel (LC-532)
    885c33e9 Merge pull request 'feat(kudos): per-user opt-out of the leaderboard (LC-526 follow-up)' (#505) from feat/LC-526-kudos-optout into main
    5fdc4387 test(kudos): cover leaderboard exclusion of opted-out users (LC-526)
    81f25c0a feat(kudos): settings toggle to opt out of the leaderboard (LC-526)
    844858f4 feat(kudos): exclude opted-out users from the leaderboard (LC-526)
    03d5d5f6 feat(kudos): users.kudos_leaderboard_opt_out column + accessors (LC-526)
    ab1df775 Merge pull request 'feat(kudos): /kudos recognition command + leaderboard (LC-526)' (#504) from feat/LC-526-kudos into main
    566f1aa9 test(kudos): cover leaderboard ranking, enclave scoping, window (LC-526)
    2702495a feat(kudos): leaderboard page + sidebar nav entry (LC-526)
    8372010c feat(kudos): /kudos slash command that records + posts recognition (LC-526)
    0f924184 feat(kudos): kudos table + leaderboard aggregate db layer (LC-526)
    dc46e5dc Merge pull request 'feat(search): has:file / has:link / in:thread operators (LC-530)' (#503) from feat/LC-530-search-filters into main
    aad0af9f test(search): cover has:file / has:link / in:thread filters (LC-530)
    3ae1ca4c feat(search): parse and wire has:file / has:link / in:thread operators (LC-530)
    24827e97 feat(search): add has:file / has:link / in:thread filter columns (LC-530)
    2719e326 Merge pull request 'feat(room): reaction highlights recap page (LC-529)' (#502) from longjacksonle/feat/LC-529-reaction-highlights into main
    748e74f1 feat(room): reaction highlights recap page (LC-529)
    966a8b61 Merge pull request 'feat(transcripts): trackable follow-up tasks from call action items (LC-527)' (#501) from longjacksonle/feat/LC-527-followup-tasks into main
    82c47fb4 feat(transcripts): trackable follow-up tasks from call action items (LC-527)
    1362110b Merge pull request 'feat(room): read a message aloud via browser speech synthesis (LC-528)' (#500) from longjacksonle/feat/LC-528-read-aloud-messages into main
    0189663c feat(room): read a message aloud via browser speech synthesis (LC-528)
    0d5ea0ba Merge pull request 'feat(enclave): remove default enclave, prompt to create when none (LC-516)' (#499) from feat/LC-516-remove-default-enclave into main
    7031e2ee fix(enclave): guard disabled bots, cap name, drop redundant home query
    630f4112 feat(enclave): remove default enclave, prompt to create when none
    369afb83 Merge pull request 'ci: guard migration immutability against sqlx checksum drift' (#498) from feat/LC-515-migration-immutability-guard into main
    d3705be8 ci: guard migration immutability against sqlx checksum drift
    44c766cd Merge pull request 'test(auth): reconcile db_sessions with LC-514 hashed session id' (#497) from fix/LC-520-db-sessions-hashed-id-tests into main
    5a6a8a04 test(auth): reconcile db_sessions with LC-514 hashed session id
    b271392d Merge pull request 'fix(auth): [operator-action] hash session tokens at rest' (#496) from fix/LC-514-sessions-hash-at-rest into main
    18967022 fix(auth): [operator-action] hash session tokens at rest
    79baa64f Merge pull request 'feat(wiki): live wiki-editing presence banner (LC-498)' (#495) from feat/LC-498-wiki-editing-presence into main
    fdf001fe feat(wiki): live "X is editing the wiki" banner on the About page (LC-498)
    4a66642c feat(wiki): WS frame + render fragments for editing presence (LC-498)
    5106f731 feat(wiki): ephemeral wiki-editing presence in the hub (LC-498)
    05969ccf Merge pull request 'feat(clips): async video clips with transcription [operator-action] (LC-496)' (#494) from feat/LC-496-video-clips into main
    7c045e95 test+docs(clips): clip transcription coverage + STT env note (LC-496)
    592e5eed i18n(clips): en + es strings for the clip recorder (LC-496)
    981364f5 feat(clips): in-composer camera/screen recorder (LC-496)
    68138e38 feat(clips): transcribe video clips via the STT endpoint [operator-action] (LC-496)
    804e6865 feat(clips): inline

    Downloads
  • v0.1.0 7d56e2b296

    v0.1.0
    Some checks failed
    check-secrets / Nosey parker (push) Successful in 7s
    check-secrets / Kingfisher (push) Successful in 8s
    check-secrets / TruffleHog (push) Successful in 10s
    Build desktop (Windows) / Build desktop (Windows x86_64) (push) Successful in 2m17s
    Build desktop (Windows) / Build desktop (Windows x86_64) (release) Successful in 2m18s
    Build OCI container / Build and push lets-chat (push) Successful in 2m43s
    Build desktop (Linux) / Build desktop (Linux x86_64) (release) Successful in 3m36s
    Publish release artifacts / Build + publish lets-chat-desktop binaries (push) Failing after 4m50s
    Check / clippy + fmt + tests (push) Successful in 7m59s
    Build desktop (Linux) / Build desktop (Linux x86_64) (push) Successful in 12m13s
    Stable

    David released this 2026-06-24 17:31:16 +02:00 | 700 commits to main since this release

    Changelog

    7d56e2b Merge pull request 'Release v0.1.0' (#440) from release/v0.1.0 into main
    2dcfd05 Release v0.1.0
    f33f41e Merge pull request 'fix(ci): derive desktop publish version from trigger to kill twin-publish race' (#391) from fix/desktop-twin-trigger-publish into main
    bf76d8a Merge branch 'main' into fix/desktop-twin-trigger-publish
    51a2156 Merge pull request 'feat(transcripts): delete, bulk-clean, row polish, live search (LC-440)' (#439) from feat/transcripts-list-delete into main
    c4e382d feat(transcripts): delete + bulk-clean empty + row polish + live search (LC-440)
    e43b948 Merge pull request 'fix(settings): never-silent avatar upload errors (LC-439)' (#438) from fix/avatar-upload-error-feedback into main
    2834e25 fix(settings): never-silent avatar upload - client validation + raised body limit + htmx error net (LC-439)
    dc8bee3 Merge pull request 'feat(dm): system-event rows, grouping window, header icons, call end-state feedback (LC-433)' (#437) from feat/dm-view-call-feedback into main
    8dc799e feat(dm): system-event rows, 5-min grouping, header icons, call end-state feedback (LC-433)
    f86c69f Merge pull request 'fix(settings): single avatar preview, status placement, file-input tooltip (LC-432)' (#436) from fix/settings-profile-polish into main
    b067834 fix(settings): single avatar preview, status placement, file-input tooltip (LC-432)
    09b19aa Merge pull request 'feat(settings): tabbed redesign + per-action HTMX feedback (LC-426)' (#435) from feat/settings-redesign-feedback into main
    fb0ca33 feat(settings): tabbed redesign + per-action HTMX feedback (LC-426)
    5952c5d Merge pull request 'feat(calls): balanced participant grid + pre-join lobby (LC-416)' (#434) from feat/lc-416-voice-grid-lobby into main
    7c2d5f5 feat(calls): balance the participant grid + redesign the pre-join lobby (LC-416)
    0f122a5 Merge pull request 'fix(calls): affirmative recording state + control-bar tooltips (LC-416)' (#433) from feat/lc-416-recording-state-tooltips into main
    3d5bf40 fix(calls): make recording state affirmative + add control tooltips (LC-416)
    0f8b57f Merge pull request 'feat(calls): redesign voice control bar + call view (LC-416)' (#432) from feat/lc-416-voice-callbar-redesign into main
    cc1f8b7 feat(calls): redesign voice control bar + call view (LC-416)
    49e7ace Merge pull request 'fix(sidebar): explicit current-enclave header for sidebar re-renders + membership gate (LC-415)' (#431) from fix/sidebar-enclave-context-hardening into main
    f89b907 fix(sidebar): send viewer's current enclave as an explicit header for sidebar re-renders (LC-415)
    2c78f78 Merge pull request 'fix(sidebar): keep enclave context when re-rendering after a category mutation (LC-415)' (#430) from fix/sidebar-category-create-enclave-context into main
    67541ff fix(sidebar): keep enclave context when re-rendering after a category mutation (LC-415)
    970d6a9 Merge pull request 'fix(auth): drop lets-chat session on Bunyip identity swap (LC-414)' (#429) from fix/LC-414-session-bunyip-sub-reconcile into main
    4ca6292 fix(auth): drop lets-chat session on Bunyip identity swap (LC-414)
    58272ac Merge pull request 'feat(auth): mirror Bunyip admin role onto lets-chat users.role (LC-413)' (#428) from feat/LC-413-mirror-bunyip-admin-role into main
    a109866 feat(auth): mirror Bunyip admin role onto lets-chat users.role (LC-413)
    579175b Merge pull request 'feat(calls): in-call transcript open/copy/download (LC-411)' (#427) from feat/lc-411-transcript-export into main
    1d7be5c feat(calls): in-call transcript open/copy/download from the drawer (LC-411)
    724a18d Merge pull request 'feat(calls): bring the 1:1 DM call control bar to parity (LC-412)' (#426) from feat/lc-412-dm-modal-parity into main
    1ca5aef feat(calls): bring the 1:1 DM call control bar to parity (LC-412)
    25124af Merge pull request 'fix(calls): screen-share stage never engaged on the receiver (LC-408)' (#425) from fix/lc-408-screenshare-receiver-pin into main
    50f3e10 fix(calls): screen-share stage never engaged on the receiver (LC-408)
    41da0cc Merge pull request 'feat(calls): per-peer connection-quality indicator (LC-410)' (#424) from feat/lc-410-connection-quality into main
    d48c506 feat(calls): per-peer connection-quality indicator (LC-410)
    aff111d Merge pull request 'fix(calls): screen-share stage never applied + could stick on peers (LC-408)' (#423) from fix/lc-408-screenshare-stage into main
    fe07580 fix(calls): screen-share stage never applied + could stick on peers (LC-408)
    84a61f0 Merge pull request 'feat(calls): mobile/responsive pass for the in-call UI (LC-409)' (#422) from feat/lc-409-call-mobile into main
    e33e28d feat(calls): mobile/responsive pass for the in-call UI (LC-409)
    4655328 Merge pull request 'feat(calls): pin screen-share to a stage tile (LC-408)' (#421) from feat/lc-408-screenshare-pinned-tile into main
    b209329 feat(calls): pin screen-share to a stage tile (LC-408)
    0f9db73 Merge pull request 'feat(calls): propagate voice mute state over WS so peers see it (LC-407)' (#420) from feat/lc-402-remote-mute into main
    142bb80 feat(calls): propagate voice mute state over WS so peers see it (LC-407)
    580f838 Merge pull request 'feat(calls): redesign the in-call voice UI (LC-402)' (#419) from feat/lc-402-voice-call-redesign into main
    4f3a37f feat(calls): redesign the in-call voice UI (LC-402)
    bf0f48a Merge pull request 'fix(room): restore the delete-room affordance on the room info page (LC-400)' (#418) from fix/lc-400-room-delete-ui into main
    6eeadff fix(room): restore the delete-room affordance on the room info page (LC-400)
    13acb35 Merge pull request 'fix(enclave): land the creator in the newly created room (LC-400)' (#417) from fix/lc-400-post-create-redirect into main
    7a781b5 fix(enclave): land the creator in the newly created room (LC-400)
    c283749 Merge pull request 'fix(sidebar): move add-room form to a modal so live swaps can't clobber it (LC-400)' (#416) from fix/lc-400-addroom-modal into main
    8ef08c7 fix(sidebar): move add-room form to a modal so live swaps can't clobber it (LC-400)
    f10a1ac Merge pull request 'fix(composer): clear the live markdown overlay after send (LC-399)' (#415) from fix/lc-399-overlay-stale-after-send into main
    904fb0d fix(composer): clear the live markdown overlay after send (LC-399)
    27db813 Merge pull request 'feat(composer): live markdown highlight overlay (LC-399)' (#414) from feat/lc-399-composer-live-markdown-overlay into main
    f5e7eae feat(composer): live markdown highlight overlay (LC-399)
    a340391 Merge pull request 'docs: document call transcription STT/LLM env vars for operators (LC-398)' (#413) from docs/lc-398-transcription-env-docs into main
    6002b83 docs: document call transcription STT/LLM env vars for operators (LC-398)
    78c884c Merge pull request 'fix(ws): always echo a message to its author, even when unsubscribed (LC-397)' (#412) from fix/lc-397-author-echo-unconditional into main
    ea228b7 fix(ws): always echo a message to its author, even when unsubscribed (LC-397)
    036d063 Merge pull request 'fix(calls): drive 1:1 transcription UI from the start response (LC-396)' (#411) from fix/lc-396-1on1-transcribe-response-driven into main
    1921239 fix(calls): drive 1:1 transcription UI from the start response (LC-396)
    1201436 Merge pull request 'feat(calls): optional LLM transcript summaries (LC-396)' (#410) from feat/lc-396-transcript-llm-summary into main
    a410751 feat(calls): optional LLM transcript summaries [operator-action] (LC-396)
    6e7caa9 Merge pull request 'feat(calls): transcript export (txt/vtt) + archive search (LC-393 Phase 4)' (#409) from feat/lc-395-transcript-export-search into main
    f27914d feat(calls): transcript export (txt/vtt) + archive search (LC-393 Phase 4)
    f21bc8b Merge pull request 'feat(calls): transcripts archive page + harden 1:1 toggle (LC-394)' (#408) from feat/lc-394-transcript-archive into main
    ebbc73b feat(calls): transcripts archive page + harden 1:1 toggle (LC-394)
    9f75902 Merge pull request 'feat(calls): Phase 3 - self-hosted server-side STT provider (LC-393)' (#407) from feat/lc-393-phase3-server-stt into main
    0e2f7ad feat(calls): Phase 3 - self-hosted server-side STT provider [operator-action] (LC-393)
    8ffb297 Merge pull request 'feat(calls): Phase 2 - transcription for enclave voice channels (LC-393)' (#406) from feat/lc-393-phase2-voice-transcription into main
    5ea34ba feat(calls): Phase 2 - transcription for enclave voice channels (LC-393)
    7f5b745 Merge pull request 'feat(calls): meeting transcription - live captions + saved transcript (LC-393)' (#405) from feat/lc-393-call-transcription into main
    563f082 feat(calls): meeting transcription - live captions + saved transcript (LC-393)
    d6479f7 Merge pull request 'fix(search): make the sidebar People tab actually query /users/search (LC-392)' (#404) from fix/lc-392-people-search into main
    db65327 fix(search): make the sidebar People tab actually query /users/search (LC-392)
    b94a389 Merge pull request 'fix(reactions): make the picker filter actually hide cells (LC-391)' (#403) from feat/lc-389-full-emoji-picker into main
    dcbca36 fix(reactions): make the picker filter actually hide cells (LC-391)
    2deef73 Merge pull request 'fix(reactions): self-heal the Recent emoji row after a react (LC-390)' (#402) from fix/lc-390-recent-emoji-refresh into main
    61a1b55 fix(reactions): self-heal the Recent emoji row after a react (LC-390)
    eb7eb21 Merge pull request 'feat(composer): full categorized emoji picker, shared catalog (LC-389)' (#401) from feat/lc-389-full-emoji-picker into main
    5a931fc feat(composer): full categorized emoji picker, shared catalog (LC-389)
    1c6cf31 Merge pull request 'feat(reactions): full categorized, searchable emoji picker (LC-389)' (#400) from feat/lc-389-full-emoji-picker into main
    e075476 feat(reactions): full categorized, searchable emoji picker (LC-389)
    d0f61bb Merge pull request 'feat(ui): align the room header action cluster (LC-388)' (#399) from feat/lc-388-header-spacing into main
    94c8949 feat(ui): align the room header action cluster (LC-388)
    2edbd63 Merge pull request 'feat(ui): widen same-author message grouping to 15 min + day-break (LC-387)' (#398) from feat/lc-387-grouping-pills into main
    9d17e71 feat(ui): widen same-author message grouping to 15 min + day-break (LC-387)
    4b2caf5 Merge pull request 'fix(ui): show-more visibility + reaction-picker dismissal regressions' (#397) from fix/room-polish-regressions into main
    7df2e4b Merge remote-tracking branch 'origin/main' into fix/room-polish-regressions
    07aa0bd fix(ui): show-more visibility + reaction-picker dismissal regressions
    6d2d5da Merge pull request 'feat(ui): replace the jump-to-date native picker with a custom calendar (LC-386)' (#396) from feat/lc-386-jumpdate into main
    b29c1be feat(ui): replace the jump-to-date native picker with a custom calendar (LC-386)
    113da67 Merge pull request 'feat(ui): intentional long-message truncation (LC-385)' (#395) from feat/lc-385-truncation into main
    11eb7a7 feat(ui): intentional long-message truncation (LC-385)
    5f281e0 Merge pull request 'feat(ui): float the reaction emoji picker as an anchored popover (LC-384)' (#394) from feat/lc-384-reaction-popover into main
    981e646 feat(ui): float the reaction emoji picker as an anchored popover (LC-384)
    4bd5f79 Merge pull request 'feat(ui): align + lighten the sidebar room/DM list (LC-381)' (#393) from feat/lc-381-room-list-polish into main
    f250373 feat(ui): align + lighten the sidebar room/DM list (LC-381)
    6df2314 Merge pull request 'fix(composer): reconcile a stuck send in place, not by reloading #messages (LC-382)' (#392) from fix/lc-382-inplace-reconcile into main
    88209b9 fix(composer): reconcile a stuck send in place, not by reloading #messages (LC-382)
    40db0de fix(ci): derive desktop publish version from trigger, not git describe
    f14535e Merge pull request 'fix(composer): self-heal a stuck "Sending..." optimistic placeholder (LC-382)' (#390) from fix/lc-382-sending-stuck-watchdog into main
    17673f2 Merge pull request 'feat(ui): tidy the two-tier composer (LC-380)' (#389) from feat/lc-380-composer-cleanup into main
    af38a89 fix(composer): self-heal a stuck "Sending..." optimistic placeholder (LC-382)
    4b04860 feat(ui): tidy the two-tier composer (LC-380)
    31fb16d Merge pull request 'feat(ui): refine the day / unread divider styling (LC-379)' (#388) from feat/lc-379-day-divider into main
    bb86b82 feat(ui): refine the day / unread divider styling (LC-379)
    1a069b2 Merge pull request 'feat(ui): room header notify pill + title polish (LC-378)' (#387) from feat/lc-378-room-header-notify into main
    aebbe5e feat(ui): room header notify pill + title polish (LC-378)
    fd9c529 Merge pull request 'feat(ui): message grouping rhythm + add-reaction affordance (LC-377)' (#386) from feat/lc-377-message-grouping into main
    6b550fe feat(ui): message grouping rhythm + add-reaction affordance (LC-377)
    f31c3c4 Merge pull request 'feat(ui): message action bar -> icon toolbar + overflow menu (LC-376)' (#385) from feat/lc-376-message-action-menu into main
    3120075 feat(ui): message action bar -> icon toolbar + overflow menu (LC-376)
    4537810 Merge pull request 'feat(ui): polish message rows, reactions, and the composer (LC-374)' (#384) from feat/lc-374-message-composer-polish into main
    47ecc59 feat(ui): polish message rows, reactions, and the composer (LC-374)
    0987e5b Merge pull request 'feat(ui): unify the room / DM / home headers (LC-373)' (#383) from feat/lc-373-room-header into main
    4c4eee2 feat(ui): unify the room / DM / home headers (LC-373)
    a27446c Merge pull request 'feat(ui): redesign the welcome empty state (LC-372)' (#382) from feat/lc-372-welcome-empty-state into main
    cc4d55b feat(ui): redesign the welcome empty state (LC-372)
    b4e4ccc Merge pull request 'feat(ui): group and polish the sidebar room/DM list (LC-371)' (#381) from feat/lc-371-room-list-sections into main
    f555856 feat(ui): group and polish the sidebar room/DM list (LC-371)
    8adac0c Merge pull request 'feat(ui): unify the two sidebar search boxes (LC-369)' (#380) from feat/lc-369-search-consolidation into main
    c6fff78 feat(ui): unify the two sidebar search boxes (LC-369)
    f7d764a Merge pull request 'feat(ui): turn the sidebar profile header into an account menu (LC-368)' (#379) from feat/lc-368-account-menu into main
    dc27ebf feat(ui): turn the sidebar profile header into an account menu (LC-368)
    2869aa1 Merge pull request 'feat(ui): group the sidebar nav into icon sections (LC-367)' (#378) from feat/lc-367-sidebar-grouping into main
    7c55c10 feat(ui): group the sidebar nav into icon sections (LC-367)
    cac1b08 Merge pull request 'feat(ui): redesign the enclave rail with semantic tokens (LC-366)' (#377) from feat/lc-366-enclave-rail into main
    020bd2d feat(ui): redesign the enclave rail with semantic tokens (LC-366)
    a760003 Merge pull request 'feat(ui): styled app-wide tooltip component (LC-370)' (#376) from feat/lc-370-tooltip-component into main
    090e7b9 feat(ui): styled app-wide tooltip component (LC-370)
    64d6fee Merge pull request 'feat(ui): semantic typography scale + spacing rhythm (LC-365)' (#375) from feat/lc-365-design-tokens into main
    29fcd5c feat(ui): add a semantic typography scale + spacing rhythm (LC-365)
    c8fb5e5 Merge pull request 'fix(tests): remove SMTP-env race behind the email-notification flake (LC-363)' (#374) from fix/lc-363-email-notification-flake into main
    9e34c97 fix(tests): stop the email-notification flake from racing on SMTP env vars (LC-363)
    b8920d3 Merge pull request 'feat(i18n): localize client-side JS strings via window.__lcI18n catalog (LC-361)' (#373) from fix/lc-361-js-i18n into main
    f6f8991 feat(i18n): localize the remaining outbox/devices/recorder JS strings (LC-361)
    56f0d91 feat(i18n): localize client-side JS strings via a window._lcI18n catalog (LC-361)
    19ecc00 Merge pull request 'feat(ci): cap native check.yml parallelism at nproc/2' (#372) from feat/GOV-10-native-check-nproc-cap into main
    2d92967 feat(ci): cap native check.yml parallelism at nproc/2
    795133c Merge pull request 'fix(a11y): accessible names for search inputs + settings selects; reaction OOB label (LC-362)' (#371) from fix/lc-362-a11y-labels into main
    425d90d Merge pull request 'fix: webhook/email avatar fallback + inline settings form errors (LC-356, LC-360)' (#370) from fix/lc-356-360-audit-ux into main
    ce57fc4 fix(a11y): give search inputs and settings selects accessible names; fix reaction OOB drift (LC-362)
    f95c68d fix(settings): flash profile/delete-account errors inline instead of a full-page error (LC-356)
    b749c08 fix(room): fall back to initials when a webhook/email avatar fails to load (LC-360)
    6fda0c3 Merge pull request 'fix: four validation/correctness audit findings (LC-355, LC-357, LC-358, LC-359)' (#369) from fix/lc-355-357-358-359-audit-med into main
    3883d50 fix(admin): validate bridge/webhook targets and bound rate-limit/quota (LC-357, LC-358)
    6fafefc fix(room): use a textarea for inline message edit so multiline is editable (LC-359)
    f3c22ac fix(branding): cap login heading/body length on the write path (LC-355)
    5c10f82 Merge pull request 'fix: remaining HIGH audit findings - dead 2FA cleanup + <html lang> (LC-353, LC-354)' (#368) from fix/lc-353-354-audit-high-cleanup into main
    8786932 fix(i18n): drive <html lang> from the resolved request locale (LC-354)
    26421eb chore: remove dead 2FA UI cruft left by the LC-22 Bunyip SSO cutover (LC-353)
    952ace8 Merge pull request 'fix: four HIGH correctness/security fixes from the UI audit (LC-349..352)' (#367) from fix/lc-349-352-audit-high-correctness into main
    7c4bddd fix(admin): block removing the last active admin (LC-352)
    4d26c85 fix(enclave): refuse role changes that would demote the Owner (LC-351)
    3701e9e fix(polls): clamp poll closes_in to avoid Duration overflow panic (LC-350)
    ede91bc fix(scheduled): cap scheduled-message body length on the write path (LC-349)
    4e3497c Merge pull request 'fix(avatar): revalidate /avatars with ETag so changes appear promptly (LC-348)' (#366) from fix/lc-348-avatar-etag-revalidation into main
    bdc8977 fix(avatar): revalidate /avatars with ETag so changes appear promptly (LC-348)
    1d41ca8 Merge pull request 'fix(settings): confirm profile-picture upload and refresh the preview (LC-347)' (#365) from fix/lc-347-avatar-upload-feedback into main
    797916b Merge remote-tracking branch 'origin/main' into fix/lc-347-avatar-upload-feedback
    7beca2a chore: drop accidental .claude/scheduled_tasks.lock change from LC-347
    e573216 fix(settings): confirm profile-picture upload and refresh the preview (LC-347)
    ccda09a Merge pull request 'docs: refresh auth docs for Bunyip-SSO-only (LC-22) + document dev-web SSO setup' (#364) from docs/dev-web-bunyip-sso-setup into main
    7e57e54 docs: refresh auth docs for Bunyip-SSO-only (LC-22) + document dev-web SSO setup
    2214053 Merge pull request 'fix(dev): serve dev-web on the nebula-secure entrypoint too' (#363) from fix/dev-web-nebula-entrypoint into main
    c23d097 fix(dev): serve dev-web on the nebula-secure entrypoint too
    9fa846c Merge pull request '[operator-action] fix(dev): make dev-web bootable against the Bunyip OP (LC-22 fallout)' (#362) from fix/dev-web-bunyip-sso-startup into main
    72fba3d [operator-action] fix(dev): make dev-web bootable against the Bunyip OP (LC-22 fallout)
    c07fc39 Merge pull request 'fix(composer): preserve in-progress message across reconnect soft-refresh (LC-346)' (#361) from fix/lc-346-composer-refresh-preserve into main
    daab33b fix(composer): preserve in-progress message across reconnect soft-refresh
    1eed22b Merge pull request 'feat(settings): section off the user settings page with a sticky nav (LC-345)' (#360) from feat/lc-345-settings-sections into main
    2d516ba feat(settings): section off the user settings page with a sticky nav (LC-345)
    7812fbb Merge pull request 'feat(moderation): shame-tag community moderation prototype (LC-342)' (#359) from feat/lc-342-shame-tags into main
    866539f feat(moderation): shame-tag community moderation prototype (LC-342)
    33352db Merge pull request 'docs(test): correct enclave_rooms helper comment (LC-341)' (#358) from test/lc-341-coyote-trigger into main
    d813d7f docs(test): correct enclave_rooms helper comment (LC-341)
    100e7a1 Merge pull request 'test(enclave): assert Coyote Mode auto-ban trigger deterministically (LC-341)' (#357) from test/lc-341-coyote-trigger into main
    78a87cb test(enclave): assert Coyote Mode auto-ban trigger deterministically (LC-341)
    c34e4a4 Merge pull request 'feat(enclave): banned-list UI with per-user unban (LC-340)' (#356) from feat/lc-340-enclave-banlist into main
    c2f510d feat(enclave): banned-list UI with per-user unban
    10b114f Merge pull request 'feat(enclave): Coyote Mode anti-spam (cross-room burst -> enclave ban + 24h soft-purge) (LC-339)' (#355) from feat/lc-339-coyote-mode into main
    d4f990e test(enclave): HTTP coverage for Coyote Mode gate + ban enforcement; clarify exemption copy
    c7b3cea feat(enclave): Coyote Mode anti-spam (cross-room burst -> enclave ban + 24h soft-purge)
    65f14ab Merge pull request 'fix(composer): do not wipe in-progress text on draft-autosave (LC-338)' (#354) from fix/lc-338-composer-draft-wipe into main
    8b9277c fix(composer): do not wipe in-progress text on draft-autosave (LC-338)
    db8df9e Merge pull request 'fix(ws): render_sidebar uses recipient's current enclave, not None (LC-337)' (#353) from fix/lc-337-render-sidebar-enclave-aware into main
    0917b76 fix(ws): render_sidebar uses the recipient's current enclave, not None
    d03fd53 Merge pull request 'feat(enclave): remove landing menu; sidebar + create-chat, invite-search to settings' (#352) from feat/lc-336-remove-enclave-landing-menu into main
    927ea7c feat(enclave): remove landing menu; sidebar + create-chat, invite-search to settings
    6fb0404 Merge pull request 'fix(oidc): pass raw 32-byte Ed25519 key, not SPKI-wrapped DER (LC-22)' (#351) from fix/lc-22-ed25519-spki-verify into main
    c6065f3 fix(oidc): pass raw 32-byte Ed25519 key, not SPKI-wrapped DER (LC-22)
    db87b28 Merge pull request 'style: cargo fmt the report.rs use ordering' (#350) from fix/lc-22-routes-reports-appstate-drift into main
    d0ddb7e style: cargo fmt the report.rs use ordering
    811e535 Merge pull request 'fix(report): gate admin-queue helpers behind standalone (LC-22 / LC-334)' (#349) from fix/lc-22-routes-reports-appstate-drift into main
    e22c95a fix(report): gate admin-queue helpers behind standalone (LC-22 / LC-334)
    f4f513d Merge pull request 'fix(tests): AppState drift in routes_reports - add bunyip_sso None (LC-22)' (#348) from fix/lc-22-routes-reports-appstate-drift into main
    1fee553 fix(tests): AppState drift in routes_reports - add bunyip_sso None (LC-22)
    efd5c6b Merge pull request 'style: cargo fmt run on LC-22 cutover additions' (#347) from feat/lc-22-bunyip-rp-cutover into main
    6d1b912 fix(tests): drop unused send_with_ip helpers in routes_anti_spam (LC-22)
    900a7b4 style: cargo fmt run on LC-22 cutover additions
    194f12e Merge pull request 'feat/lc-22-bunyip-rp-cutover' (#346) from feat/lc-22-bunyip-rp-cutover into main
    99d9745 Merge pull request 'feat(moderation): report a message to moderators with a site-admin review queue (LC-334)' (#345) from feat/lc-334-message-reports into main
    d0602f0 test(sso): adapt fixtures for users.bunyip_sub UNIQUE constraint (LC-22)
    6080041 feat(moderation): report a message to moderators with a site-admin review queue
    6a960b2 fix(sso): retire 2FA-enrollment middleware + stale anti-spam knobs (LC-22)
    a1df3a2 [operator-action] feat(sso): pure-RP Bunyip cutover; retire local auth (LC-22)
    01a1169 Merge pull request 'feat(composer): live character counter near the message-length cap (LC-332)' (#344) from feat/lc-332-composer-char-counter into main
    9f35028 feat(composer): live character counter near the message-length cap
    7b75d98 Merge pull request 'fix(ws): delay reconnect banner so page nav does not flash it (LC-318)' (#343) from fix/lc-318-reconnect-banner-grace into main
    128ff46 fix(ws): keep missed-content recovery on short real outages
    7cfae7d fix(ws): delay reconnect banner so page nav does not flash it
    7787976 Merge pull request 'fix(sidebar): live category change uses enclave-keyed nav fragment (LC-331)' (#342) from fix/lc-331-sidebar-categories-live into main
    f5b7b4d fix(sidebar): live category change uses enclave-keyed nav fragment
    95a0d9c Merge pull request 'feat(markdown): copy button on fenced code blocks (LC-329)' (#341) from feat/lc-329-code-block-copy into main
    98f9f99 feat(markdown): copy button on fenced code blocks (LC-329)
    d8f9385 Merge pull request 'feat(settings): per-user message text size (LC-327)' (#340) from feat/lc-327-message-text-size into main
    cd9e2db feat(settings): per-user message text size (LC-327)
    5d72760 Merge pull request 'feat(room): jump-to-date navigation (LC-325)' (#339) from feat/lc-325-jump-to-date into main
    a67eec8 feat(room): jump-to-date navigation (LC-325)
    5c0c01b Merge pull request 'feat(composer): #channel-link autocomplete and clickable links (LC-323)' (#338) from feat/lc-323-channel-link-autocomplete into main
    0df7d1f feat(composer): #channel-link autocomplete and clickable links (LC-323)
    cfcd40c Merge pull request 'feat(room): per-room nickname (LC-321)' (#337) from feat/lc-321-per-room-nickname into main
    a04f947 feat(room): per-room nickname (LC-321)
    67f529d Merge pull request 'feat(status): auto-expiring custom status (LC-319)' (#336) from feat/lc-319-auto-expiring-status into main
    86bc5cf feat(status): auto-expiring custom status (LC-319)
    f723490 Merge pull request 'feat(composer): emoji picker button (LC-316)' (#335) from feat/lc-316-composer-emoji-picker into main
    a548784 feat(composer): emoji picker button (LC-316)
    658c35a Merge pull request 'feat(ui): relative message timestamps (LC-314)' (#334) from feat/lc-314-relative-timestamps into main
    825a9d3 feat(ui): relative message timestamps (LC-314)
    4981851 Merge pull request 'feat(search): saved searches (LC-312)' (#333) from feat/lc-312-saved-searches into main
    17a32a1 feat(search): saved searches (LC-312)
    8ba5805 Merge pull request 'feat(threads): thread following / subscribe (LC-310)' (#332) from feat/lc-310-thread-following into main
    a1746ee feat(threads): thread following / subscribe (LC-310)
    f6e435b Merge pull request 'feat(ui): unread-only sidebar filter (LC-308)' (#331) from feat/lc-308-unread-only-sidebar into main
    32f26a4 feat(ui): unread-only sidebar filter (LC-308)
    03551bb Merge pull request 'feat(notifications): keyword / highlight-word notifications (LC-304)' (#330) from feat/lc-304-keyword-notifications into main
    0008406 feat(notifications): keyword / highlight-word notifications (LC-304)
    ff09979 Merge pull request 'feat(ui): quick-reaction hover bar on messages (LC-302)' (#329) from feat/lc-302-quick-reaction-bar into main
    188869c feat(ui): quick-reaction hover bar on messages (LC-302)
    4117eb8 Merge pull request 'feat(composer): list, quote, and strikethrough toolbar buttons (LC-300)' (#328) from feat/lc-300-composer-toolbar-blocks into main
    3b2f5ce feat(composer): list, quote, and strikethrough toolbar buttons (LC-300)
    4a5ec67 Merge pull request 'feat(ui): user profile hovercard on username hover (LC-298)' (#327) from feat/lc-298-profile-hovercard into main
    c08f3fa feat(ui): user profile hovercard on username hover (LC-298)
    e0294e3 Merge pull request 'feat(composer): emoji :shortcode: autocomplete (LC-296)' (#326) from feat/lc-296-emoji-autocomplete into main
    efbd24e feat(composer): emoji :shortcode: autocomplete (LC-296)
    ea79458 Merge pull request 'feat(ui): jump to first unread - floating pill returns to the unread divider (LC-294)' (#325) from feat/lc-294-jump-to-first-unread into main
    4466325 feat(ui): jump to first unread - floating pill returns to the unread divider (LC-294)
    d36a25e Merge pull request 'feat(ui): theme quick-toggle in the sidebar footer (LC-292)' (#324) from feat/lc-292-theme-quick-toggle into main
    b67fad9 feat(ui): theme quick-toggle in the sidebar footer (LC-292)
    843d4a7 Merge pull request 'feat(markdown): spoiler text - ||text|| renders click-to-reveal (LC-290)' (#323) from feat/lc-290-spoiler-markdown into main
    a88e50e feat(markdown): spoiler text - ||text|| renders click-to-reveal (LC-290)
    7d07c94 Merge pull request 'feat(ui): recently-used emoji row in the reaction picker (LC-288)' (#322) from feat/lc-288-recent-emoji into main
    c973ef3 feat(ui): recently-used emoji row in the reaction picker (LC-288)
    1963680 Merge pull request 'feat(ui): mark a conversation unread from a message (LC-286)' (#321) from feat/lc-286-mark-unread into main
    7570383 feat(ui): mark a conversation unread from a message (LC-286)
    2f6a324 Merge pull request 'feat(ui): highlight messages that @-mention the viewer (LC-284)' (#320) from feat/lc-284-self-mention-highlight into main
    e767434 feat(ui): highlight messages that @-mention the viewer (LC-284)
    fbf1d71 Merge pull request 'feat(ui): copy a message's text from the hover menu (LC-282)' (#319) from feat/lc-282-copy-message-text into main
    ccd6825 feat(ui): copy a message's text from the hover menu (LC-282)
    42d2da0 Merge pull request 'feat(ui): search operators from: and before:/after: (LC-280)' (#318) from feat/lc-280-search-operators into main
    ac257f3 feat(ui): search operators from: and before:/after: (LC-280)
    c36762c Merge pull request 'feat(ui): forward a message to another room or DM (LC-278)' (#317) from feat/lc-278-message-forwarding into main
    c0d9864 feat(ui): forward a message to another room or DM (LC-278)
    1c3d268 Merge pull request 'feat(ui): markdown preview toggle in the composer (LC-276)' (#316) from feat/lc-276-markdown-preview into main
    08f3dbb feat(ui): markdown preview toggle in the composer (LC-276)
    55a858e Merge pull request 'feat(ui): filter field on the reaction emoji picker (LC-274)' (#315) from feat/lc-274-reaction-picker-filter into main
    6b7bf70 feat(ui): filter field on the reaction emoji picker (LC-274)
    88a0000 Merge pull request 'feat(ui): copy button on code blocks (LC-272)' (#314) from feat/lc-272-code-copy-button into main
    cfd0d0f feat(ui): copy button on code blocks (LC-272)
    75277d5 Merge pull request 'feat(ui): collapse the room sidebar to the enclave rail (LC-270)' (#313) from feat/lc-270-sidebar-collapse-rail into main
    d6c8c87 feat(ui): collapse the room sidebar to the enclave rail (LC-270)
    c820970 Merge pull request 'feat(ui): per-room scoped search from the room header (LC-268)' (#312) from feat/lc-268-per-room-search into main
    dce7e88 feat(ui): per-room scoped search from the room header (LC-268)
    bcc5fb4 Merge pull request 'feat(ui): who-reacted tooltip on reaction pills (LC-266)' (#311) from feat/lc-266-who-reacted-tooltip into main
    d495540 feat(ui): who-reacted tooltip on reaction pills (LC-266)
    0b4ec6d Merge pull request 'feat(ui): collapsible pinned-messages strip (LC-264)' (#310) from feat/lc-264-pinned-strip-collapse into main
    24725a1 feat(ui): collapsible pinned-messages strip (LC-264)
    ad8dad5 Merge pull request 'feat(ui): image lightbox - click an inline image to view it enlarged (LC-262)' (#309) from feat/lc-262-image-lightbox into main
    47a81c1 feat(ui): image lightbox - click an inline image to view it enlarged (LC-262)
    8c9b351 Merge pull request 'feat(ui): quick switcher - Ctrl/Cmd+K palette to jump anywhere (LC-260)' (#308) from feat/lc-260-quick-switcher into main
    7b2b7c6 Merge remote-tracking branch 'origin/main' into feat/lc-260-quick-switcher
    efc0956 feat(ui): quick switcher - Ctrl/Cmd+K palette to jump anywhere (LC-260)
    638dee6 Merge pull request 'feat(ui): per-room mark-as-read from the sidebar (LC-258)' (#307) from feat/lc-258-per-room-mark-read into main
    397239e feat(ui): per-room mark-as-read from the sidebar (LC-258)
    526fcca Merge pull request 'feat(ui): collapse long messages with Show more / Show less (LC-256)' (#306) from feat/lc-256-collapse-long-messages into main
    4d919f8 feat(ui): collapse long messages with Show more / Show less (LC-256)
    8b96dbf Merge pull request 'feat(ui): composer formatting toolbar - bold/italic/code/link (LC-254)' (#305) from feat/lc-254-composer-format-toolbar into main
    a4498df feat(ui): composer formatting toolbar - bold/italic/code/link (LC-254)
    4abe5e8 Merge pull request 'feat(ui): keyboard shortcuts overlay - '?' opens a cheat-sheet (LC-252)' (#304) from feat/lc-252-shortcuts-overlay into main
    c83de4e feat(ui): keyboard shortcuts overlay - '?' opens a cheat-sheet (LC-252)
    d275c60 Merge pull request 'feat(justfile): add dev-clean / dev-clean-all teardown recipes' (#303) from feat/dev-clean-recipes into main
    76d55b1 feat(justfile): add dev-clean / dev-clean-all teardown recipes
    74efa83 Merge pull request 'feat(ui): mark all as read - clear unread across every conversation (LC-250)' (#302) from feat/lc-250-mark-all-read into main
    8c452f2 feat(ui): mark all as read - clear unread across every conversation (LC-250)
    0822d90 Merge pull request 'feat(ui): Arrow-Up in an empty composer edits your last message (LC-248)' (#301) from feat/lc-248-arrowup-edit-last into main
    8fa338c feat(ui): Arrow-Up in an empty composer edits your last message (LC-248)
    90f2378 Merge pull request 'feat(ui): copy message link permalink that scrolls to + highlights the message (LC-246)' (#300) from feat/lc-246-message-permalink into main
    6b7ea81 feat(ui): copy message link permalink that scrolls to + highlights the message (LC-246)
    bd217dc Merge pull request 'feat(ui): message-list date separators (Today / Yesterday / date) (LC-244)' (#299) from feat/lc-244-date-separators into main
    ed7ec4b feat(ui): message-list date separators (Today / Yesterday / date) (LC-244)
    edf1f63 Merge pull request 'feat(ui): jump-to-latest pill with new-message count in the message list (LC-242)' (#298) from feat/lc-242-jump-to-latest-pill into main
    c4e87a1 feat(ui): jump-to-latest pill with new-message count in the message list (LC-242)
    2236657 Merge pull request 'feat(ui): per-conversation draft sidebar indicators + caret restore (LC-237)' (#297) from feat/lc-237-draft-sidebar-indicators into main
    b42ccf7 feat(ui): per-conversation draft sidebar indicators + caret restore (LC-237)
    e6f67be Merge pull request 'chore(build): bump rust-builder-glibc to v1.0.1' (#296) from chore/bump-rust-builder-glibc-v1.0.1 into main
    cdc2150 chore(build): bump rust-builder-glibc to v1.0.1
    1e5df9d Merge pull request 'chore: Sync .gitignore' (#295) from chore/sync-gitignore into main
    72b61c7 chore: Sync .gitignore
    e789968 Merge pull request 'feat(ui): optimistic local echo for composer sends (LC-230)' (#294) from feat/lc-230-optimistic-echo into main
    c78d54b fix(ui): address LC-230 review findings - quarantine ghost, retry data loss, debounced failure flip
    ddfc493 feat(ui): optimistic local echo for composer sends (LC-230)
    4dcd642 Merge pull request 'perf(ui): cut composer per-keystroke costs (LC-229)' (#293) from perf/lc-229-composer-keystroke-costs into main
    3e8acc8 perf(ui): consolidate send-button writers, fix review findings (LC-229)
    0ce36bc perf(ui): cut composer per-keystroke costs (LC-229)
    1b1b2e4 Merge pull request 'perf(server): return 204 from post_message (LC-228)' (#292) from feat/lc-228-post-message-no-content into main
    5e586e0 perf(server): return 204 from slash dispatch too (LC-228)
    e48269c perf(server): return 204 from post_message instead of unused composer fragment (LC-228)
    ff650e9 Merge pull request 'fix(ci): generate release notes from commits since previous tag' (#291) from fix/release-notes-since-prev-tag into main
    8cb79a1 fix(ci): generate release notes from commits since previous tag
    031952b Merge pull request 'fix(http): remove dead auto-redirect SSRF footgun; prove the rebind window is closed at connect (LC-152-TOCTOU)' (#290) from fix/lc-152-pin-validated-ip into main
    9230df3 fix(http): remove dead auto-redirect SSRF footgun; prove + document the rebind window is closed at connect (LC-152-TOCTOU, #286)
    bcac695 Merge pull request 'test(desktop): net_guard grep-ban matches allow-list by full path + recursive src walk (LC-210-GREPBAN-FULLPATH)' (#289) from fix/lc-210-grepban-fullpath into main
    9a9da4e test(desktop): match net_guard ureq grep-ban allow-list by full path, walk src recursively (LC-210-GREPBAN-FULLPATH, #285)
    3e7a557 Merge pull request 'fix(uploads): bound image decode with explicit Limits, closing the unbounded GIF path [operator-action] (LC-206-IMAGE-LIMITS)' (#288) from fix/lc-206-image-limits into main
    ede3a2d fix(uploads): bound image decode with explicit Limits, closing the unbounded GIF path [operator-action] (LC-206-IMAGE-LIMITS, #284)
    0dc6858 Merge pull request 'fix(rooms): cap room description + wiki body length like chat messages (LC-153-WIKI-DESC-CAP)' (#287) from fix/lc-153-wiki-desc-cap into main
    235de2b fix(rooms): cap room description + wiki body length like chat messages (LC-153-WIKI-DESC-CAP, #283)
    332a320 Merge pull request 'docs: reconcile email-ingress/bridge docs + env tables with shipped behavior (LC-209-DOC-DRIFT)' (#282) from docs/lc-279-doc-drift into main
    9a0e1e4 docs: reconcile email-ingress/bridge docs + env tables with shipped behavior (LC-209-DOC-DRIFT, #279)
    bdf0a88 Merge pull request 'feat(admin): surface email-ingress / IMAP-poll / retention-sweep health on /admin/settings (LC-207-OBSERVABILITY)' (#281) from feat/lc-207-observability-ingress-sweep-imap into main
    e5cbca2 feat(admin): surface email-ingress, IMAP-poll, and retention-sweep health on /admin/settings (LC-207-OBSERVABILITY, #278)
    882bda9 Merge pull request 'feat(desktop): verify signed update manifest + binary hash before self-replace [operator-action] (LC-210-BINARY-INTEGRITY)' (#280) from feat/lc-210-binary-integrity-manifest-signing into main
    54c1fca feat(desktop): verify signed update manifest + binary hash before self-replace [operator-action] (LC-210-BINARY-INTEGRITY, #277)
    8e8feaf Merge pull request 'fix(desktop): SSRF-guard the self-updater with per-hop redirect validation (LC-210)' (#276) from fix/lc-210-desktop-updater-ssrf-guard into main
    52266b9 fix(desktop): SSRF-guard the self-updater with per-hop redirect validation (LC-210)
    4e3ee62 Merge pull request 'docs(release): CHANGELOG + operator-visible-change convention (LC-209)' (#275) from docs/lc-209-changelog-convention into main
    5110788 docs(release): CHANGELOG + operator-visible-change convention (LC-209)
    a46233a Merge pull request 'fix(uploads): unique write_atomic staging name to end routes_uploads flake (LC-208)' (#274) from fix/lc-208-write-atomic-unique-staging into main
    17c53a3 fix(uploads): unique write_atomic staging name to end routes_uploads flake (LC-208)
    222a95e Merge pull request 'feat(admin): bridge-avatar cache diagnostic page (LC-207)' (#273) from feat/lc-207-bridge-avatar-admin-diagnostics into main
    9ba932a feat(admin): bridge-avatar cache diagnostic page (LC-207)
    a8454a7 Merge pull request 'refactor(uploads): centralize image decode behind safe helpers + grep-ban (LC-206)' (#272) from refactor/lc-206-image-decode-safe-helper into main
    b0b81ad refactor(uploads): centralize image decode behind safe helpers + grep-ban (LC-206)
    3b90293 Merge pull request 'perf(ui): debounce mention popover refresh 200ms (LC-227)' (#271) from feat/lc-227-mention-popover-debounce into main
    af46d8d perf(ui): debounce mention popover refresh 200ms (LC-227)
    3eaf910 Merge pull request 'fix(ui): tokenize remaining .lc-md + .lc-quote-bar slate/blue (LC-226)' (#270) from feat/lc-226-lc-md-quote-bar-tokenize into main
    0bb6d21 Merge pull request 'feat(ui): tokenize message actor badges (webhook/email/bridge) (LC-225)' (#269) from feat/lc-225-actor-badge-tokenize into main
    0be2446 fix(ui): tokenize remaining .lc-md + .lc-quote-bar hardcoded slate/blue (LC-226)
    93d3238 feat(ui): tokenize message actor badges (webhook/email/bridge) (LC-225)
    2039991 Merge pull request 'fix(email-ingress): enqueue message.posted for LC-75 subscribers (LC-205)' (#268) from fix/lc-205-email-ingress-message-posted into main
    9096478 Merge pull request 'feat(ui): tokenize soft-success + soft-warning callouts (LC-224)' (#267) from feat/lc-224-success-warning-tokenize into main
    9a9f85f fix(ui): code-review fixes for LC-224 success/warning sweep
    04f034f fix(email-ingress): enqueue message.posted so LC-75 subscribers see it (LC-205)
    cdbf759 feat(ui): tokenize soft-success + soft-warning callouts (LC-224)
    1f4e406 Merge pull request 'feat(ui): tokenize accent / focus-ring drift (LC-222)' (#265) from feat/lc-222-accent-focus-tokenize into main
    8488a19 fix(ui): code-review fixes for LC-222 accent / focus-ring sweep
    e2382a0 Merge pull request 'test: retire hand-rolled migration lists, grep-ban drift (LC-204)' (#266) from fix/lc-204-retire-handrolled-migration-lists into main
    d42ad50 Merge branch 'main' into fix/lc-204-retire-handrolled-migration-lists
    37b5066 test: grep-ban hand-rolled migration lists + pin migration_enclaves (LC-204)
    9118c35 test: convert 34 hand-rolled migration lists to common::pool() (LC-204)
    eecea87 feat(ui): tokenize accent / focus-ring drift (LC-222)
    a79a6d9 Merge pull request 'fix(ui): tokenize .lc-md + swap 4 prose-slate no-ops onto lc-md (LC-221)' (#264) from feat/lc-221-markdown-tokenize into main
    8ec1b7f fix(ui): tokenize .lc-md + swap 4 prose-slate no-ops onto lc-md (LC-221)
    d37cc36 Merge pull request 'feat(error): styled themed error page for AppError::IntoResponse (LC-220)' (#263) from feat/lc-220-styled-error-page into main
    2f8e419 fix(error): code-review fixes for LC-220 styled error page
    ac538f4 feat(error): styled themed error page for AppError::IntoResponse (LC-220)
    83bd838 Merge pull request 'fix(ui): admin top nav scrolls horizontally instead of wrapping (LC-219)' (#262) from feat/lc-219-admin-nav-scroll into main
    8db5ba0 fix(ui): reserve right padding for the version chip on admin nav (LC-219)
    6a3f140 fix(ui): admin top nav scrolls horizontally instead of wrapping (LC-219)
    c16d02f Merge pull request 'fix(test): add 0057 migration to 18 hand-rolled test pools (LC-217 follow-up)' (#261) from fix/lc-217-migration-drift-test-pools into main
    f20b025 Merge pull request 'feat(ui): expand compact density to sidebar / header / composer (LC-218)' (#260) from feat/lc-218-density-compact-expanded into main
    3e91c70 fix(ui): split density row and row-dense for proportional compression (LC-218)
    7208b0b fix(test): add 0057 migration to 18 hand-rolled test pools (LC-217 follow-up)
    377660d feat(ui): expand compact density to sidebar / header / composer (LC-218)
    4daa202 Merge pull request 'feat(enclave): per-enclave message send rate-limit override (LC-217)' (#259) from feat/lc-217-enclave-msg-rate-limit into main
    3334651 docs(claude-md): polish LC-217 anti-spam section
    3a3ecc8 fix(test): tighten missed assertion in limits_are_per_enclave (LC-217)
    f50b0ed fix(enclave): code-review fixes for LC-217
    b0fa47a feat(enclave): per-enclave message send rate-limit override (LC-217)
    2cbb5fd Merge pull request 'fix(ui): debounce composer "Could not send" banner (LC-216)' (#258) from fix/lc-216-composer-error-debounce into main
    4551adf fix(ui): cancel pending composer error timer on form teardown (LC-216)
    436bd5a fix(ui): debounce composer "Could not send" banner (LC-216)
    a1c830e Merge pull request 'feat(ui): tokenize soft-danger callouts for dark themes (LC-215)' (#257) from feat/lc-215-danger-surface-tokens into main
    6de86d7 fix(ui): tokenize outbox.js failed-send label (LC-215)
    6d2acfe fix(ui): code-review fixes for LC-215 danger-surface sweep
    bd262a4 feat(ui): tokenize soft-danger callouts for dark themes (LC-215)
    728aeb1 Merge pull request 'fix(ci): inject git_hash / git_version / build_date as build args (LC-214)' (#256) from fix/lc-214-ci-build-provenance into main
    9429dcc fix(ci): inject git_hash / git_version / build_date as build args (LC-214)
    3f8258c Merge pull request 'fix(migrations): revert migration 6 comment edit + pin immutability rule (LC-212)' (#255) from fix/LC-212-migration-6-revert-comment-edit into main
    c844bc8 fix(migrations): revert migration 6 comment edit + pin immutability rule (LC-212)
    64e4185 Merge pull request 'chore(security): redact SMTP credentials from compose.dev.yml.1 template (LC-211)' (#253) from chore/lc-211b-redact-smtp-creds-template into main
    875b743 chore(security): redact SMTP credentials from compose.dev.yml.1 template (LC-211)
    a27d152 Merge pull request 'fix(ci): clippy clean on rust 1.94 (LC-187)' (#254) from fix/lc-187-clippy-resolve-msg-author into main
    5b28d95 fix(ci): clippy clean on rust 1.94 (LC-187)
    cb23c60 Merge pull request 'fix(compose): SMTP_TLS template value "implicit" -> "tls" (LC-211)' (#252) from fix/lc-211-smtp-tls-template-value into main
    877cd3a fix(compose): SMTP_TLS template value "implicit" -> "tls" (LC-211)
    f75aca1 Merge pull request 'feat(ui): viewport-fit, safe-area helpers, smoother nav drawer (LC-199)' (#251) from feat/lc-199-responsive into main
    2d44ff2 fix(ui): #main uses 100dvh so iOS URL bar doesn't eat content (LC-199)
    77df44f feat(ui): viewport-fit, safe-area helpers, smoother nav drawer (LC-199)
    b882769 Merge pull request 'style: rustfmt the LC-78/LC-152 bridge files (LC-187)' (#250) from fix/lc-187-fmt-bridge-files into main
    428c548 Merge pull request 'feat(ui): tokenize presence dots + status/bot badges (LC-198)' (#249) from feat/lc-198-icons-avatars into main
    73f6b06 style: rustfmt the LC-78 / LC-152 bridge files (LC-187)
    f1426af fix(ui): bot badge stays visible on row hover (LC-198)
    53cfb33 feat(ui): tokenize presence dots + status/bot badges (LC-198)
    7457186 Merge pull request 'feat(a11y): skip link, message-list live region, composer + popup labels (LC-197)' (#248) from feat/lc-197-a11y into main
    8711c62 fix(a11y): honest semantics for status picker + reaction trigger (LC-197)
    7610726 feat(a11y): skip link, message-list live region, composer + popup labels (LC-197)
    b10c8a5 Merge pull request 'feat(ui): motion & micro-interactions, prefers-reduced-motion aware (LC-196)' (#247) from feat/lc-196-motion into main
    f04e662 fix(ui): .lc-anim-swap fade uses transition, not animation (LC-196)
    7d4aeb3 feat(ui): motion & micro-interactions, prefers-reduced-motion aware (LC-196)
    1c426d2 Merge pull request 'feat(ui): shared component vocabulary (LC-195)' (#241) from feat/lc-195-components into main
    4074068 Merge pull request 'fix(security): close Web Push SSRF + LC-152 TOCTOU via shared http_client' (#246) from feat/lc-152-shared-http-client-no-bypass into main
    80fdda1 killer pair + grep-ban + per-site error propagation
    aabe4cd elper + migrated sites for revie
    bd6887b migrate 5 outbound sites
    6753093 Merge pull request 'chore: rename SMTP env vars to LETS_CHAT_SMTP
    (LC-201)' (#244) from chore/lc-201-prefix-smtp-env-vars into main
    0cc10bb Merge branch 'main' into chore/lc-201-prefix-smtp-env-vars
    503055b helper + custom Resolve + OnceLock client
    a843a3a Merge pull request 'feat(bridges): foreign-avatar proxy (LC-78-AVATAR-PROXY, on by default)' (#245) from feat/lc-78-avatar-proxy into main
    40c4fdc docs: name the proxied-avatar threat model in v2
    fce69eb tests across the 6 surfaces
    446e326 flip POST endpoint + new GET proxy + render template
    504cd82 flip POST endpoint + new GET proxy + render template
    e77490a LC-152 audit + image-decoder spike + fetch module
    37f86a9 schema migration + db helpers
    66801a8 chore: rename SMTP env vars to LETS_CHAT_SMTP
    * (LC-201)
    36cf5f3 Merge pull request 'docs: bring README current with shipped features (LC-145)' (#242) from docs/lc-145-update-docs into main
    936cc35 Merge branch 'main' into docs/lc-145-update-docs
    2adb12b Merge pull request 'feat(bridges): per-message synthetic actor + admin UI (LC-78 v1)' (#243) from feat/lc-78-bridge-registration-surface into main
    65038ea operator docs + migration-list drift fix in tests
    ebafe43 admin UI for bridge registration + health + plain remove
    9f1460f loop-break actor field across all LC-75 events
    1e575c4 bridge role tier + isolation test
    e4ec15d bridges CRUD + heartbeat + sealed config
    4e3633b list_messages_paginated fork
    899a4af bridge-messages endpoint + bridge:post scope
    f71a6c5 schema + MessageActor::Bridge arm
    fa69add docs: bring README current with shipped features (LC-145)
    876d281 feat(ui): shared component vocabulary (buttons/inputs/cards/modals) (LC-195)
    28e9a36 Merge pull request 'feat(ui): density toggle + readability/compact polish (LC-194)' (#240) from feat/lc-194-density-polish into main
    b4f0e8c feat(ui): density toggle + readability/compact polish (LC-194)
    531af8d Merge pull request 'feat(ui): migrate templates to semantic color tokens (LC-193)' (#239) from feat/lc-193-token-migration into main
    bbcff9a feat(ui): migrate templates to semantic color tokens (LC-193)
    a24d3f6 Merge pull request 'feat(ui): high-contrast theme variants, WCAG AA/AAA (LC-192)' (#238) from feat/lc-192-high-contrast into main
    fad8d14 feat(ui): high-contrast theme variants, WCAG AA/AAA (LC-192)
    6cc252f Merge pull request 'feat(ui): light/dark/system theme switching + per-user pref (LC-191)' (#237) from feat/lc-191-theme-switching into main
    745a33e feat(ui): light/dark/system theme switching + per-user pref (LC-191)
    873cce2 Merge pull request 'feat(ui): design-token foundation + Tailwind theme wiring (LC-190)' (#236) from feat/lc-190-design-tokens into main
    07b3a94 feat(ui): semantic design-token foundation + Tailwind theme wiring (LC-190)
    5e2a33d Merge pull request 'i18n: externalize UI chrome + Spanish catalog (LC-188)' (#235) from feat/lc-188-i18n-externalize into main
    464a1e0 i18n: externalize UI chrome across templates + Spanish catalog (LC-188)
    b1c674d Merge pull request 'test(i18n): silence clippy single_element_loop in catalog coverage check' (#234) from feat/lc-100-i18n into main
    22c2771 test(i18n): silence clippy single_element_loop in catalog coverage check
    808a5cc Merge pull request 'feat(i18n): Fluent + Askama localization framework (LC-100)' (#233) from feat/lc-100-i18n into main
    30efeb8 feat(i18n): Fluent + Askama framework, locale middleware, settings picker (LC-100)
    3b93507 Merge pull request 'feat(client): per-room RSS/Atom + iCal feeds, token-gated (LC-102)' (#232) from feat/lc-102-room-feeds into main
    6cfc333 feat(client): per-room RSS/Atom + iCal feeds, token-gated (LC-102)
    f198ac2 Merge pull request 'style: rustfmt the LC-186 remote-control audit files (LC-187)' (#231) from fix/lc-187-fmt into main
    346cfb1 style: rustfmt the LC-186 remote-control audit files
    d117ef1 Merge pull request 'feat(realtime,desktop): remote-control safety envelope (LC-186)' (#230) from feat/lc-186-remote-control-safety into main
    381cd67 feat(realtime,desktop): remote-control safety envelope (LC-186)
    129fe1a Merge pull request 'feat(desktop): native OS input injection for remote control (LC-185, Windows first)' (#229) from feat/lc-185-native-input-injection into main
    3ffb3e9 fix(desktop): clear held input when arming a remote-control session
    c6201a5 feat(desktop): native OS input injection for remote control (LC-185, Windows first)
    dc4a6c1 Merge pull request 'feat(realtime): remote-control input capture + data-channel transport (LC-184, controller)' (#228) from feat/lc-184-remote-control-input-capture into main
    b255670 feat(realtime): remote-control input capture + data-channel transport (LC-184, controller)
    f63f686 Merge pull request 'feat(realtime): remote-control consent signaling + verified-email gate (LC-183 server)' (#227) from feat/lc-183-remote-control-handshake into main
    847152c feat(realtime): remote-control consent signaling + verified-email gate (LC-183, server)
    333a519 Merge pull request 'docs: remote-control design + threat model (LC-182)' (#226) from docs/lc-182-remote-control-design into main
    6413497 docs: address LC-182 design review - de-risk the subtask handoffs
    b4c8820 docs: remote-control design + threat model (LC-182)
    f165833 Merge pull request 'spike(LC-131): Windows installer from Linux via NSIS' (#225) from spike/lc-131-nsis-from-linux into main
    1732bff feat(desktop): build + publish the Windows installer from Linux (LC-131)
    05bf94b spike(LC-131): build the Windows installer from Linux with NSIS
    3914ebe Merge pull request 'feat(realtime): live refresh affordance for /inbox and /activity (LC-179)' (#224) from feat/lc-179-live-inbox-activity into main
    c73b4f6 docs: bring live-updates documentation current with the LC-156 epic (LC-179)
    44c8b15 feat(realtime): live refresh affordance for /inbox and /activity (LC-179)
    d749be0 Merge pull request 'feat(realtime): live /saved list on bookmark/unbookmark (LC-178, saved surface)' (#223) from feat/lc-178-live-saved into main
    e8e366d feat(realtime): live /saved list on bookmark/unbookmark (LC-178, saved surface)
    305b6d9 Merge pull request 'feat(realtime): live admin room list (LC-177)' (#222) from feat/lc-177-live-admin-rooms into main
    e7ece06 feat(realtime): live admin room list (archive/edit/invite/regenerate) (LC-177)
    bd0de88 Merge pull request 'feat(realtime): drop a user's enclave topic subscription on access loss (LC-176)' (#221) from feat/lc-176-topic-unsubscribe into main
    9e3457b feat(realtime): drop a user's enclave topic subscription on access loss (LC-176)
    9259fd4 Merge pull request 'feat(realtime): live admin user list (LC-175, admin-user surface)' (#220) from feat/lc-175-live-admin-lists into main
    d5a6a9f feat(realtime): live admin user list (ban/mute/role/quota/delete) (LC-175, admin-user surface)
    1a49795 Merge pull request 'feat(realtime): live sidebar room list on enclave room add/remove (LC-174)' (#219) from feat/lc-174-live-sidebar-rooms into main
    dddc6f3 feat(realtime): live sidebar room list on enclave room add/remove (LC-174)
    f335a59 Merge pull request 'feat(realtime): live own-profile refresh in the sidebar self block (LC-173 phases 1-2)' (#218) from feat/lc-173-live-own-profile into main
    3c52b03 feat(realtime): live own-profile refresh in the sidebar self block (LC-173 phases 1-2)
    d569cd1 Merge pull request 'feat(realtime): live enclave settings-page member list (LC-172)' (#217) from feat/lc-172-live-settings-members into main
    efd9037 feat(realtime): live enclave settings-page member list (LC-172)
    cd1b01d Merge pull request 'fix(composer): Enter defers to an open mention/slash combobox (LC-171)' (#216) from fix/lc-171-composer-enter-guard into main
    786b6e6 test(composer): make the LC-171 Enter-guard assertion reformat-tolerant
    1ca0806 fix(composer): Enter defers to an open mention/slash combobox (LC-171)
    559222c Merge pull request 'feat(realtime): live enclave member + room lists on the landing page (LC-170)' (#215) from feat/lc-170-live-enclave-lists into main
    4374071 fix(realtime): let non-member site admins subscribe to the enclave topic (LC-170 review)
    fa12548 feat(realtime): live enclave member + room lists on the landing page (LC-170)
    a3adcbb Merge pull request 'chore(ui): consolidate avatar renderer, auth form-errors, confirm-dialog guideline (LC-169)' (#214) from chore/lc-169-ui-consolidation into main
    0893fd0 chore(ui): consolidate avatar renderer, auth form-errors, confirm-dialog guideline (LC-169)
    6ac3409 Merge pull request 'feat(a11y): keyboard navigation for the slash-command popover (LC-168)' (#213) from feat/lc-168-slash-keyboard-nav into main
    bcf39e6 feat(a11y): keyboard navigation for the slash-command popover (LC-168)
    ca043a4 Merge pull request 'feat(realtime): live invitations page (LC-161, first surface)' (#212) from feat/lc-161-live-invitations into main
    d3fbd2a feat(realtime): live invitations page (LC-161, first surface)
    ec7c226 Merge pull request 'feat(realtime): typed WS topics (enclave/user/admin) + subscribe-time auth (LC-160)' (#211) from feat/lc-160-typed-ws-topics into main
    beb9728 feat(realtime): typed WS topics (enclave/user/admin) + subscribe-time auth (LC-160)
    90a66fb Merge pull request 'fix(a11y): reminder picker modal focus-trap parity (LC-158)' (#210) from chore/lc-158-reminder-modal-a11y into main
    5ea4113 refactor(a11y): dispose the reminder-picker trap on every path (LC-158)
    8eb46be fix(a11y): bring the reminder picker modal to focus-trap parity (LC-158)
    311fcd8 Merge pull request 'feat(search): shared keyboard navigation + ARIA for search bars (LC-157 phase 1)' (#209) from feat/lc-157-search-keyboard-nav into main
    d75cdc1 fix(search): namespace option ids so they are document-unique (LC-157)
    ddf8906 feat(search): shared keyboard navigation + ARIA for search bars (LC-157 phase 1)
    628a27b Merge pull request 'feat(email-ingress): optional dead-letter folder for dropped messages (LC-77-DEAD-LETTER)' (#208) from feat/lc-77-dead-letter into main
    556f8a1 feat(email-ingress): optional dead-letter IMAP folder for dropped messages (LC-77-DEAD-LETTER)
    653cd97 Merge pull request 'feat(email-ingress): exactly-once dedup via Message-ID hash (LC-77-MID-DEDUP)' (#207) from feat/lc-77-mid-dedup into main
    5bd6f87 feat(email-ingress): wire processed-Message-ID dedup into poll loop (LC-77-MID-DEDUP commit 2)
    2d0a21f feat(email-ingress): processed_message_ids dedup schema + db primitives (LC-77-MID-DEDUP commit 1)
    cd583bb Merge pull request 'feat(email-ingress): reply-by-email ingress (LC-77-REPLY stage 2)' (#206) from feat/lc-77-reply-stage2 into main
    6250aeb test(email-ingress): threat-model tests + docs for reply-by-email (LC-77-REPLY commit 2d)
    12cde6b feat(email-ingress): poll loop dispatches ReplyMatch to reply_actor (LC-77-REPLY commit 2c)
    2e61571 feat(email-ingress): reply-by-email actor + quote/signature strip (LC-77-REPLY commit 2b)
    1a3747a feat(email-ingress): namespace-forked resolver + reply-token primitives (LC-77-REPLY commit 2a)
    503f0ab Merge pull request 'feat(notify): per-mention/DM notification emails (LC-77-REPLY stage 1)' (#205) from feat/lc-77-reply-stage1 into main
    9646eb2 test(notify): end-to-end mention/DM dispatch tests + docs touch-up (LC-77-REPLY commit 1d)
    773a06c feat(notify): wire mention/DM email dispatch into the post path (LC-77-REPLY commit 1c)
    cee7699 feat(email): per-message mention/DM notification dispatcher + Reply-To (LC-77-REPLY commit 1b)
    47f51ea feat(db): reply_tokens schema + per-user notify_email_activity opt-in (LC-77-REPLY commit 1a)
    ecb892b Merge pull request 'refactor(admin): remove dead SMTP admin form + clean up stale rows (LC-77-SMTP-SEAL, #200)' (#204) from feat/lc-77-smtp-seal into main
    7d071e8 refactor(admin): remove dead SMTP admin form + clean up stale settings rows (LC-77-SMTP-SEAL)
    3c83c9c Merge pull request 'docs(email-ingress): operator guide + threat-model integration tests (LC-77)' (#199) from feat/lc-77-docs into main
    d242a9e docs(email-ingress): operator guide + threat-model integration tests (LC-77)
    bc94365 Merge pull request 'feat(email-ingress): MIME body + attachment upload pipeline (LC-77)' (#198) from feat/lc-77-mime-attachments into main
    b080653 feat(email-ingress): MIME body + attachment upload pipeline (LC-77)
    2fd425e Merge pull request 'feat(email-ingress): admin lifecycle UI (LC-77)' (#197) from feat/lc-77-admin-ui into main
    70a133f feat(email-ingress): admin settings UI for IMAP config (LC-77)
    f185a89 feat(email-ingress): per-room admin UI for email inboxes (LC-77)
    b2b24b0 Merge pull request 'feat(email-ingress): IMAP poll + resolution + synthetic-actor send (LC-77)' (#196) from feat/lc-77-imap-poll into main
    8891bbd style: cargo fmt sweep across the LC-77 surface + LC-59 carryover
    d2d2409 test(email-ingress): per-message pipeline integration tests (LC-77)
    71095ab feat(email-ingress): IMAP poll loop + spawn_email_poll (LC-77)
    eecbdf9 feat(email-ingress): email_ingress module core + finalize send path (LC-77)
    f3a0d4c feat(email-ingress): db layer + rate-limit kind (LC-77)
    2832602 refactor(messages): add EmailInbox actor variant + AuthorMeta.actor (LC-77)
    0de27cc Merge pull request 'feat(email-ingress): schema for IMAP config + email inboxes (LC-77)' (#195) from feat/lc-77-schema into main
    b590185 feat(email-ingress): schema for IMAP config + email inboxes (LC-77)
    b23e010 Merge pull request 'refactor(messages): MessageActor enum for render-time actor identity (LC-77)' (#194) from feat/lc-77-message-actor-enum into main
    1d9b210 refactor(messages): MessageActor enum for render-time actor identity (LC-77)
    0182bbc test(messages): pin webhook render output as pre-refactor fixture (LC-77)
    6eaaa1a Merge pull request 'feat/lc-59-math' (#193) from feat/lc-59-math into main
    469dbd8 feat(messages): wire LaTeX math into markdown pipeline + round-trip tests (LC-59)
    081543c feat(messages): server-side LaTeX -> MathML rendering module (LC-59)
    f305aa5 Merge pull request 'feat(realtime): declarative live-update subscription module (LC-156 phase 1)' (#192) from feat/lc-156-live-subscribe-foundation into main
    7b2605d fix(realtime): also re-subscribe on htmx:afterSettle, not just htmx:load (LC-156)
    ec3615c feat(realtime): declarative live-update subscription module (LC-156 phase 1)
    b4ff9cc Merge pull request 'fix(security): token CSPRNG + proxy-trust + og:image hardening (LC-155)' (#191) from feat/lc-155-token-csprng-hardening into main
    9b35a25 fix(unfurl): re-sanitize cached og:image on the cache-hit path (LC-155)
    b6735eb fix(security): token CSPRNG + proxy-header trust + og:image scheme hardening (LC-155)
    925b319 Merge pull request 'fix(security): allowlist markdown link/image schemes (LC-154)' (#189) from feat/lc-154-markdown-link-scheme into main
    3497de9 fix(security): also scheme-allowlist the login-body markdown renderer (LC-154)
    cd3d54e fix(security): allowlist markdown link/image schemes (LC-154)
    bf58ae3 Merge pull request 'fix(security): cap message body length (LC-153)' (#188) from feat/lc-153-message-length-cap into main
    f60c738 fix(security): cap message length on the JSON API v1 POST too (LC-153)
    bc48c01 fix(security): cap message body length (LC-153)
    c564162 Merge pull request 'fix(security): SSRF guard at webhook delivery time + shared predicate (LC-152)' (#186) from feat/lc-152-webhook-delivery-ssrf into main
    46aa6dc fix(security): SSRF guard at webhook delivery time + shared predicate (LC-152)
    0f930d6 Merge pull request 'fix(security): rate-limit login + 2FA challenge endpoints (LC-151)' (#184) from feat/lc-151-login-rate-limit into main
    ebdc879 fix(security): rate-limit login + 2FA challenge endpoints (LC-151)
    4aa8119 Merge pull request 'fix(security): re-validate every redirect hop in unfurl against SSRF guard (LC-150)' (#183) from feat/lc-150-unfurl-redirect-ssrf into main
    ed8e9fd fix(unfurl): bail on empty redirect Location instead of re-fetching self (LC-150)
    02f73c1 fix(security): re-validate every redirect hop in unfurl against SSRF guard (LC-150)
    fe03449 Merge pull request 'fix(security): enforce room access on reaction handlers (LC-149)' (#182) from feat/lc-149-reactions-authz into main
    d2473af fix(security): enforce room access on reaction handlers (LC-149)
    76513b2 Merge pull request 'docs(audit): codebase-wide review + live-update and search designs (LC-148)' (#181) from chore/lc-148-codebase-audit into main
    a38d55f docs(audit): codebase-wide review report + live-update and search design docs (LC-148)
    9fa401f Merge pull request 'feat(notifications): cap push subscriptions per user across channels (LC-147)' (#180) from feat/lc-147-cap-push-subscriptions into main
    995716f feat(notifications): cap push subscriptions per user across channels (LC-147)
    623d131 Merge pull request 'feat(notifications): mobile push foundation (APNs + FCM channels) (LC-91)' (#179) from feat/lc-91-mobile-push-foundation into main
    477370a feat(notifications): mobile push foundation (APNs + FCM channels) (LC-91)
    5c6cda5 Merge pull request 'test(notifications): close per-room notification-level audit gaps (LC-90)' (#178) from feat/lc-90-per-room-notify-audit into main
    0de703f test(notifications): assert private-room dropdown for a non-admin member (LC-90)
    b4c8315 test(notifications): close per-room notification-level audit gaps (LC-90)
    15ecf9c Merge pull request 'feat(notifications): per-user Do Not Disturb / quiet hours (LC-88)' (#177) from feat/lc-88-dnd-quiet-hours into main
    8eced21 feat(notifications): per-user Do Not Disturb / quiet hours (LC-88)
    6985228 Merge pull request 'workflow/check-secrets.yml' (#176) from workflow/check-secrets.yml into main
    57392b7 add .noseyparker-ignore.txt
    9720335 add .trufflehog-exclude.txt
    ef18903 add check-secrets.yml
    bdff2b1 Merge pull request 'feat/lc-64-message-drafts' (#175) from feat/lc-64-message-drafts into main
    89041e1 test(drafts): integration tests + query-plan pin (LC-64)
    a2fabdc feat(drafts): composer wiring + render-on-load with lazy cleanup (LC-64)
    5227ba4 feat(drafts): PUT handler + race guard + clear-on-send/schedule + purge (LC-64)
    1cf7a5f feat(drafts): scaffold message_drafts schema + db module (LC-64)
    21f6d27 Merge pull request 'feat/room-retention' (#174) from feat/room-retention into main
    c125d9b Merge branch 'main' into feat/room-retention
    3d6bdf8 Merge pull request 'docs: refresh README, FUTURE, and API docs for shipped features (LC-145)' (#173) from chore/lc-145-update-docs into main
    7f47cc5 docs: refresh README, FUTURE, and API docs for shipped features (LC-145)
    fd02934 feat(retention): admin UI + audit + env-var docs
    13a9bb7 feat(retention): wire spawn + MessagePurged broadcast
    efd2c5a feat(retention): sweep logic + FTS trigger guard (0046)
    98dcbc3 test(retention): verify cascade fires for every message FK
    e3cb693 docs(test-maintenance): correct stale migration-drift note
    8e98332 feat(retention): scaffold room retention schema and fix cascade gaps
    41681a4 Merge pull request 'feat(calls): select mic/camera/speaker instead of system default (LC-144)' (#172) from feat/lc-144-call-device-select into main
    eff7928 fix(calls): guard device picker against stale refresh + idle speaker re-route (LC-144)
    1dca2f1 feat(calls): select mic/camera/speaker instead of system default (LC-144)
    89084a1 Merge pull request 'feat(integration): outgoing webhooks / event subscriptions (LC-75)' (#171) from feat/lc-75-outgoing-webhooks into main
    69d5d62 fix(webhooks): SSRF guard + replay-resistant signature for outgoing webhooks (LC-75)
    a1dd501 feat(integration): outgoing webhooks / event subscriptions (LC-75)
    66da262 Merge pull request 'feat(integration): incoming webhooks (post-as URL) (LC-74)' (#170) from feat/lc-74-incoming-webhooks into main
    f229545 fix(webhooks): cap incoming webhook message length (LC-74)
    0837c39 feat(integration): incoming webhooks (post-as URL) (LC-74)
    cd894d7 Merge pull request 'feat(justfile): scaffold fj-driven create-release + group attrs (DEV-331)' (#169) from feat/justfile-fj-pr-create-DEV-331 into main
    a2f1b79 feat(justfile): scaffold fj-driven create-release + group attrs (DEV-331)
    ebd2d39 Merge pull request 'feat(integration): first-class bot identity (LC-73)' (#168) from feat/lc-73-bots into main
    9468118 fix(bots): roll back orphan bot row if token minting fails (LC-73)
    2c1e3c3 feat(integration): first-class bot identity (LC-73)
    67a3a36 Merge pull request 'feat(integration): scoped bearer API tokens + JSON API v1 (LC-72)' (#167) from feat/lc-72-api-tokens into main
    f5b2d21 fix(api): case-insensitive Bearer scheme; document maintenance bypass (LC-72)
    ff11216 feat(integration): scoped bearer API tokens + JSON API v1 (LC-72)
    89e5088 Merge pull request 'feat(navigation): clicking an enclave opens last/default room + settings gear (LC-143)' (#166) from feat/lc-143-enclave-last-room into main
    0a63c6c fix(navigation): pick enclave default room from the openable set (LC-143)
    21d0d88 feat(navigation): clicking an enclave opens last/default room; settings gear (LC-143)
    50a8c94 Merge pull request 'feat(integration): slash commands framework (LC-76)' (#165) from feat/lc-76-slash-commands into main
    cd181a3 fix(slash): SSRF guard on webhook command URLs; overflow-safe duration (LC-76)
    1d837f4 feat(integration): slash commands framework (LC-76)
    5a35d5b Merge pull request 'feat(messaging): polls / voting (LC-66)' (#164) from feat/lc-66-polls into main
    727a368 perf(polls): skip build_poll_view for non-poll messages; test non-member vote (LC-66)
    4f9fa6b feat(messaging): polls / voting (LC-66)
    cada393 Merge pull request 'feat(messaging): message reminders - remind me about this (LC-63)' (#163) from feat/lc-63-reminders into main
    8dcae88 fix(reminders): re-check room access at fire time (LC-63)
    53ab287 feat(messaging): "remind me about this message" reminders (LC-63)
    c26efe9 Merge pull request 'feat(branding): per-scope favicon, global-only v1 (LC-142)' (#162) from feat/lc-142-branding-favicon into main
    7c67283 fix(branding): sandbox served favicon SVG; consistent cache-bust (LC-142)
    7a50a65 feat(branding): per-scope favicon, global-only v1 (LC-142)
    b1267b5 Merge pull request 'feat(branding): render custom logo in the enclave switcher (LC-141)' (#161) from feat/lc-141-sidebar-logo into main
    efbac56 fix(branding): cache-bust switcher logo URLs with asset_version (LC-141)
    d082734 feat(branding): render custom logo in the enclave switcher (LC-141)
    3b90483 Merge pull request 'feat(pwa): installable PWA + offline message outbox (LC-98)' (#160) from feat/lc-98-pwa-offline-outbox into main
    2fdd311 feat(pwa): installable PWA + offline message outbox (LC-98)
    d25fe18 Merge pull request 'feat(admin): analytics dashboard (DAU/MAU/messages/rooms/signups) (LC-97)' (#159) from feat/lc-97-admin-analytics into main
    d6d3922 feat(admin): analytics dashboard with DAU/MAU/messages/rooms/signups + retention (LC-97)
    b24bb18 Merge pull request 'feat(admin): branding - custom logo, colors, login text (LC-96)' (#158) from feat/lc-96-branding into main
    7ed437b Merge remote-tracking branch 'origin/main' into feat/lc-96-branding
    1ae0221 fix(branding): code-review follow-ups (LC-96)
    27dfce2 feat(branding): custom logo, colors, login text (LC-96)
    6ae9e20 Merge pull request 'feat/lc-62-scheduled-send-pr-b' (#157) from feat/lc-62-scheduled-send-pr-b into main
    59ae590 fix(scheduled): label /scheduled timestamps as UTC (LC-62)
    61d2089 docs: README Features entry for scheduled-send (LC-62)
    817c0ec feat(scheduled): purge scheduled rows on account delete (LC-62)
    07a4d16 feat(scheduled): composer modal UI reusing Phase 25 dialog focus-trap (LC-62)
    aed7284 feat(scheduled): /scheduled routes + management view + shared validation (LC-62)
    1320497 feat(scheduled): background dispatcher with atomic claim + re-validation (LC-62)
    0449081 Merge pull request 'feat/lc-62-scheduled-send' (#156) from feat/lc-62-scheduled-send into main
    7c4d808 feat(scheduled): schema + db module + orphan-sweep guard (LC-62)
    f271353 refactor(routes): extract finalize_message_send from post_message (LC-62)
    e8c763f Merge pull request 'feat(admin): backup + restore archive (LC-95)' (#155) from feat/lc-95-backup-restore into main
    2f8e7c7 fix(backup): code-review follow-ups (LC-95)
    e0df85a feat(admin): backup + restore archive (LC-95)
    2f831a1 Merge pull request 'feat(anti-spam): rate limits + link filter + honeypot (LC-94)' (#154) from feat/lc-94-anti-spam into main
    017996e fix(anti-spam): code-review follow-ups (LC-94)
    b33e4ad feat(anti-spam): admin pages + integration tests (LC-94)
    228be41 feat(anti-spam): wire enforcement at messages, register, forgot (LC-94)
    cbf18fc feat(anti-spam): schema, rate-limit module, link helpers (LC-94)
    70f3713 Merge pull request 'feat(admin): per-user + per-enclave storage quotas (LC-93)' (#153) from feat/lc-93-storage-quotas into main
    9a2b3f3 fix(quotas): code-review follow-ups (LC-93)
    e4cb63c feat(admin): per-user + per-enclave storage quotas (LC-93)
    f689b78 Merge pull request 'feat(admin): maintenance-mode UI toggle + 503 gate (LC-92)' (#152) from feat/lc-92-maintenance-mode into main
    f63e929 fix(admin): exempt password-reset surface from maintenance gate
    2ba923c feat(admin): maintenance-mode UI toggle + 503 gate (LC-92)
    50b89d8 Merge pull request 'feat(rooms): per-room Files tab in room info (LC-87)' (#151) from feat/lc-87-room-files-tab into main
    319f250 feat(rooms): per-room Files tab in room info page (LC-87)
    7bb7adc Merge pull request 'feat(rooms): room info page with description + wiki (LC-86)' (#150) from feat/lc-86-room-docs-wiki into main
    712a472 feat(rooms): room info page with description + wiki (LC-86)
    2c9baf6 Merge pull request 'feat(rooms): read-only / moderators-only posting policy (LC-85)' (#149) from feat/lc-85-readonly-rooms into main
    02ba040 feat(rooms): read-only / moderators-only posting policy (LC-85)
    0c9a4de Merge pull request 'feat(rbac): per-room moderator overrides (LC-84)' (#148) from feat/lc-84-per-room-role-overrides into main
    e81d19f feat(rbac): room-header link to per-room moderators page
    82eaf80 feat(rbac): per-room moderator overrides (LC-84)
    98614bf Merge pull request 'fix(autoscroll): re-anchor on composer resize' (#147) from fix/mention-autocomplete-breaks-autoscroll into main
    807aae9 Merge pull request 'feat(mentions): user groups in @ autocomplete' (#146) from feat/lc-83-group-mention-popover into main
    e9a3b5a Merge pull request 'feat(enclave): typeahead UX for group Add member' (#145) from feat/lc-83-add-member-typeahead into main
    8911207 fix(autoscroll): scope teardown to #messages, not bubbling ancestor
    8e157a8 fix(autoscroll): drive wasAtBottom from scroll events only
    5724193 fix(autoscroll): re-anchor on composer resize, not just on htmx swap
    31e2dba feat(mentions): include user groups in @ autocomplete
    8e6cc6d feat(enclave): typeahead UX for group "Add member"
    6a816c0 Merge pull request 'feat(enclave): user-groups CRUD UI' (#144) from feat/lc-83-user-groups-ui into main
    a312908 Merge pull request 'feat(mentions): per-enclave user groups @group-name (LC-83)' (#143) from feat/lc-83-user-groups into main
    6497b02 feat(enclave): user-groups CRUD UI in enclave settings
    09979bd feat(mentions): per-enclave user groups (@group-name) - LC-83
    bcda3ee Merge pull request 'feat(activity): activity center at /activity (LC-82)' (#142) from feat/lc-82-activity into main
    b883ca4 feat(activity): per-user activity feed at /activity (LC-82)
    67ef16a Merge pull request 'fix(dm): send WS subscribe when page mounts on an already-open socket' (#141) from fix/dm-subscribe-on-open-socket into main
    204fe68 fix(dm): send WS subscribe when page mounts on an already-open socket
    922fe5a Merge pull request 'feat(sidebar): jump-to-unread + /inbox (LC-81) [stacked]' (#140) from feat/lc-81-jump-and-inbox into main
    250eb24 feat(sidebar): jump-to-unread keybind + /inbox view (LC-81)
    0c89bdc Merge pull request 'feat(sidebar): per-user starred rooms + DMs (LC-80) [stacked]' (#139) from feat/lc-80-starred-rooms into main
    40c6eca feat(sidebar): per-user starred rooms + DMs (LC-80)
    f01bc68 Merge pull request 'fix(sidebar): active-room highlight + drag-to-uncategorize (LC-79 follow-up)' (#138) from fix/sidebar-active-room-and-uncategorize into main
    740f8f9 fix(sidebar): active-room highlight + drag-to-uncategorize after LC-79 redesign
    483c4dc Merge pull request 'refactor(sidebar): per-enclave admin-managed room categories (LC-79 redesign)' (#137) from refactor/lc-79-enclave-scoped-categories into main
    7daad44 refactor(sidebar): make room categories per-enclave, admin-managed (LC-79 redesign)
    7929ca1 Merge pull request 'fix(sidebar): show room count on collapsed-category header' (#136) from fix/sidebar-collapsed-room-count into main
    67f664d fix(sidebar): show room count on collapsed-category header
    dcf7fbe Merge pull request 'fix(sidebar): make uncategorized rooms draggable into categories' (#135) from fix/sidebar-uncategorized-draggable into main
    f60a7ed fix(sidebar): make uncategorized room rows draggable into categories
    eae8471 Merge pull request 'fix(sidebar): keep room list visible when category mutations fire from an enclave page' (#134) from fix/sidebar-categories-respect-current-enclave into main
    92bbb91 fix(sidebar): derive current enclave from HX-Current-URL on category mutations
    684171a Merge pull request 'fix(sidebar): scrub categorization on room leave (LC-79 AC #5)' (#133) from fix/lc-79-ac5-forget-room-on-leave into main
    ce535a3 fix(sidebar): scrub category assignments when user leaves a room (LC-79 AC #5)
    15c626b Merge pull request 'feat(sidebar): collapsed aggregate + mobile tap target (LC-79 phase 3)' (#132) from feat/lc-79-phase3-collapsed-aggregate-mobile into main
    e55b912 feat(sidebar): collapsed-category aggregate badges + mobile tap target (LC-79 phase 3)
    d9fdddc Merge pull request 'feat(sidebar): drag-and-drop category + room reorder (LC-79 phase 2)' (#131) from feat/lc-79-phase2-drag-and-drop into main
    ba4a506 feat(sidebar): drag-and-drop category + room reorder (LC-79 phase 2)
    7a7bfd9 Merge pull request 'feat(sidebar): grouped category render + UI (LC-79 phase 1b)' (#130) from feat/lc-79-sidebar-categories-phase1b into main
    53e6012 feat(sidebar): grouped category render + UI affordances (LC-79 phase 1b)
    1857f8b Merge pull request 'feat(sidebar): per-user channel-category schema + CRUD (LC-79 phase 1a)' (#129) from feat/lc-79-sidebar-categories-phase1 into main
    9e2fa0c feat(sidebar): per-user channel-category schema + CRUD endpoints
    0d437d4 Merge pull request 'ci(desktop): publish Linux .deb + .AppImage bundles' (#128) from feat/lc-132-publish-linux-bundles into main
    dbf2c9a ci(desktop): publish Linux .deb + .AppImage bundles
    ba3364c Merge pull request 'feat(desktop): auto-grant getUserMedia on Linux + Windows' (#127) from feat/lc-129-getusermedia-permission-hooks into main
    231f106 feat(desktop): auto-grant getUserMedia on Linux + Windows
    3773c2b Merge pull request 'feat/screen-share' (#126) from feat/screen-share into main
    4f99a8a Merge remote-tracking branch 'origin/main' into feat/screen-share
    c31262c feat(voice): add screen share to enclave voice channels
    dd3e9d0 Merge pull request 'plan/phase26-edit-history' (#125) from plan/phase26-edit-history into main
    dad6052 style: cargo fmt cleanup across phase 26 work
    2732926 docs(claude): document test-harness 2FA and admin-promotion gotchas
    67caf27 feat(room): make (edited) label in thread reply open history drawer
    fb30860 test(message_editing): add edit-history db and route integration tests
    3c3a1e3 feat(room): add edit-history drawer for edited messages
    00d7b36 feat(db): add MessageEdit type and transactional edit history writes
    7fb5fc9 docs(plans): add phase 26 edit history implementation plan
    c09b6fc feat(db): add message_edits table for per-message edit history
    f8fb7ba Merge pull request 'feat(desktop): URL editor, tray, Linux bundles, cookie fix (LC-123)' (#124) from feat/desktop-clients into main
    0f8e400 feat(desktop): URL editor, tray, Linux bundles, cookie fix (LC-123)
    7f75065 Merge pull request 'chrone/accessibility-audit' (#123) from chrone/accessibility-audit into main
    6562809 feat(a11y): record axe baseline JSON and document Task 8 findings
    c174398 feat(a11y): implement combobox ARIA pattern for mention popover
    8376b2f feat(a11y): add focus trap and ARIA roles to call dialogs
    fa0675c feat(a11y): add HTMX afterSwap focus restoration with opt-out support
    24c1635 feat(a11y): add aria-expanded toggle to mobile nav button and update deferred list
    c8b1139 feat(a11y): add aria-labels and harden screen reader announcement text
    6fe1c08 feat(a11y): add aria-live regions and screen reader announcements
    6112b0d feat(a11y): add phase 25 accessibility plan and global :focus-visible rule
    dcb5ce9 fix(call): make screen share actually reach the peer
    5a06be9 feat(call): add screen share to 1:1 calls
    cf58930 Merge pull request 'feat(presence): add sticky manual "away" status distinct from auto-idle' (#122) from feat/sticky-away into main
    e7143c3 Merge pull request 'feat(presence): relabel statuses Online/Away, add aria-label and offline color' (#121) from feat/presence-polish into main
    bbb75aa feat(presence): add sticky manual "away" status distinct from auto-idle
    3d1ef08 feat(presence): relabel statuses Online/Away, add aria-label and offline color
    f6e254d Merge pull request 'feat/tauri2-desktop-migration' (#120) from feat/tauri2-desktop-migration into main
    26ee755 fix(dev-desktop): mount XAUTHORITY and grant xhost so the Tauri 2 window can open the X display
    c5bd8b6 ci(desktop): wire Tauri 2 build files into the workflow paths and Windows cross-compile
    3daba48 feat(desktop): migrate from Tao+Wry to Tauri 2
    d4cf6bd Merge pull request 'fix(auth): defer account creation until 2FA enrollment completes' (#119) from fix/2fa-before-registration into main
    bb78d41 fix(auth): defer account creation until 2FA enrollment completes
    1ebbfb4 Merge pull request 'fix(voice): self-video, DM-call takeover, and live participants preview' (#118) from fix/voice-call-bugs into main
    52ab2c9 fix(voice): self-video, DM-call takeover, and live participants preview
    7a2ff88 Merge pull request 'fix(call): deliver incoming-call popup from any page and resolve glare server-side' (#117) from fix/global-call-popup-and-glare into main
    3be65e4 fix(call): deliver incoming-call popup from any page and resolve glare server-side
    44eb986 Merge pull request 'refactor(dev): convert dev-* recipes to Docker Compose' (#115) from feat/dev-recipes-to-compose into main
    39a579b refactor(dev): convert dev-* recipes to Docker Compose
    f1526a9 Merge pull request 'feat(desktop): show a welcome page when the server is unreachable' (#114) from feat/desktop-welcome-page into main
    f96fc35 feat(desktop): show a welcome page when the server is unreachable
    c9c37af Merge pull request 'fix(ci): move FORGEJO_TOKEN to step-env so the secret reaches nu' (#113) from fix/forgejo-token-step-env-v2 into main
    f1ccc2b fix(ci): move FORGEJO_TOKEN to step-env so the secret reaches nu
    99352b4 Merge pull request 'fix(ci): use nu http delete/put for generic-packages uploads (yotun pattern)' (#112) from fix/generic-packages-use-nu-http into main
    76cb3fc fix(ci): use nu http delete/put for generic-packages uploads (yotun pattern)
    5f1a0a9 Merge pull request 'fix(ci): switch generic-packages upload auth to HTTP Basic with owner:token' (#111) from fix/generic-packages-basic-auth into main
    bff7fb4 fix(ci): switch generic-packages upload auth to HTTP Basic with owner:token
    71968bf Merge pull request 'fix(ci): publish desktop binaries to the private package registry' (#110) from fix/desktop-workflows-publish-to-packages into main
    9100e59 Merge branch 'main' into fix/desktop-workflows-publish-to-packages
    1602316 fix(ci): publish desktop binaries to the private package registry
    62371db Merge pull request 'fix(ci): build-oci-image pushes to the private org registry' (#109) from fix/build-oci-image-private-package-org into main
    820942f fix(ci): build-oci-image pushes to the private org registry
    455efe7 Merge pull request 'chore(dev): point dev/cargo wrappers at the shared org builder image' (#108) from chore/use-rust-builder-glibc-image into main
    04d58b9 chore(dev): point dev/cargo wrappers at the shared org builder image
    725535b Merge pull request 'chore(dev): align local clippy with CI (Rust 1.94 + -D warnings)' (#106) from chore/sync-local-clippy-with-ci into main
    5ee6ebe Merge branch 'main' into chore/sync-local-clippy-with-ci
    531591f Merge pull request 'fix(ci): publish lets-chat-desktop releases to the private package org' (#107) from fix/publish-release-private-package-org into main
    0b94fad Merge branch 'main' into fix/publish-release-private-package-org
    4cbbe26 Merge branch 'main' into chore/sync-local-clippy-with-ci
    12c6bd6 fix(ci): publish lets-chat-desktop releases to the private package org
    1af0380 chore(dev): align local clippy with CI (Rust 1.94 + -D warnings)
    d4f42ab Merge pull request 'chore: silence clippy 1.94 errors so CI -D warnings stays green' (#105) from chore/clippy-1.94-cleanup into main
    4c25156 Merge branch 'main' into chore/clippy-1.94-cleanup
    9f2f02f chore: silence clippy 1.94 errors so CI -D warnings stays green
    c07b5a9 Merge pull request 'fix(ci): drop save --force from publish-release manifest write' (#104) from fix/publish-release-no-save-force into main
    01c7dae fix(ci): drop save --force from publish-release manifest write
    3ba793e Merge pull request 'feat(desktop): self-update for the lets-chat-desktop binary' (#103) from feat/desktop-self-update into main
    c646927 feat(desktop): self-update for the lets-chat-desktop binary
    af963ac Merge pull request 'feat(ci): cross-compile lets-chat-desktop for Windows x86_64' (#102) from feat/desktop-windows-build into main
    e53038e Merge branch 'main' into feat/desktop-windows-build
    65dad3d Merge pull request 'chore(ci): drop redundant apt install from Dockerfile.desktop-linux' (#101) from chore/desktop-linux-dockerfile-dedupe into main
    aa3da4b Merge branch 'main' into chore/desktop-linux-dockerfile-dedupe
    ff485b0 Merge pull request 'style: apply cargo fmt to fix drifted formatting' (#100) from style/cargo-fmt-drift into main
    618b873 Merge branch 'main' into style/cargo-fmt-drift
    8f573b5 Merge pull request 'fix(dev): chown cargo volumes on first run so check works without root' (#99) from fix/dev-cargo-volume-perms into main
    dea41ab Merge branch 'main' into fix/dev-cargo-volume-perms
    0782818 Merge pull request 'chore: group just recipes for clearer --list output' (#98) from chore/group-just-recipes into main
    cb79c5f feat(ci): cross-compile lets-chat-desktop for Windows x86_64
    580c2ce chore(ci): drop redundant apt install from Dockerfile.desktop-linux
    27d7c55 style: apply cargo fmt to fix drifted formatting
    d389c29 fix(dev): chown cargo volumes on first run so check works without root
    35e05b7 chore: group just recipes for clearer --list output
    336b3a5 Merge pull request 'feat: Lets Chat screenshot' (#97) from feat/lets-chat-screenshot into main
    76dc89e feat: Lets Chat screenshot
    be627ca Merge pull request 'chore/test-debt-cleanup' (#95) from chore/test-debt-cleanup into main
    463e4aa Merge pull request 'feat(calls): WebRTC voice/video calls and enclave voice channels' (#96) from feat/voice-and-video-calls into main
    c7b6da5 feat(calls): WebRTC voice/video calls and enclave voice channels
    1e13cae chore(tests): remove duplicate migrations from db_dm setup_pools
    6aa1b0d docs(claude): document test-drift categories and add curl permission
    f1a3bd2 test(enclave): fix invite_then_accept_creates_membership contract drift
    2a9d4a3 chore(tests): fix migration drift and feature-gate drift across test suite
    91a2f4f Merge pull request 'fix(tests): make just test pass again' (#94) from fix/just-test-stale-migrations into main
    2e24b00 fix(tests): make just test pass again
    92743a5 Merge pull request 'feat(messaging): press Enter anywhere to send a message' (#93) from feat/enter-anywhere-send into main
    320e09e feat(messaging): press Enter anywhere to send a message
    2228e9b Merge pull request 'feat(messaging): voice messages with record + waveform' (#92) from feat/voice-messages into main
    bff8741 feat(messaging): voice messages with record + waveform
    f671240 Merge pull request 'feat/upload-hygiene' (#91) from feat/upload-hygiene into main
    b959eee chore(uploads): clippy + cargo fmt fixes for phase 23
    c95fb70 test(uploads): pipeline, sweep, dedup-GC, admin, preview round-trip
    65f9403 docs(uploads): admin help text + plan note on preview-only regen
    06990bd feat(uploads): admin regenerate-thumbnails, purge-orphans-now, disk-usage panel
    2eef769 feat(uploads): hourly orphan sweeper with dedup-aware file delete
    c09c3d2 feat(uploads): serve ?size=preview from /api/files/:id
    a05a24d feat(uploads): pipeline runs on image uploads (strip + thumbnail)
    00bbb81 docs(uploads): fix plan typo (GIF original preserves animation)
    e516bf9 feat(uploads): image pipeline (re-encode strips EXIF, 360px preview)
    478d27b feat(uploads): add image crate + uploads module skeleton
    122c09e docs(uploads): add Phase 23 upload hygiene implementation plan
    725468f Merge pull request 'fix(enclave): live typeahead for invite member' (#90) from fix/invite-member-search into main
    5b6c0c8 fix(enclave): enforce visibility/block/ban gate on invite POST
    1fb2c3b fix(enclave): replace invite-by-username form with live typeahead
    d4b1f91 Merge pull request 'feat(messaging): quote-reply with inline chip' (#89) from feat/quote-reply into main
    3db7928 feat(messaging): rename hover actions Quote/Reply to Reply/Thread
    c376369 feat(messaging): quote-reply with inline chip above body
    56e0fa6 Merge pull request 'fix(reconnect): wire WS manual-reconnect helper now that htmx is actually loaded' (#88) from fix/ws-reconnect-after-restart into main
    5ada89d fix(reconnect): wire WS manual-reconnect helper now that htmx is actually loaded
    dac7329 Merge pull request 'fix(mail): send verification + reset emails as multipart/alternative' (#87) from fix/email-spam-multipart into main
    4ef2489 fix(mail): send verification + reset emails as multipart/alternative
    cf37553 Merge pull request 'feat/login-alerts' (#86) from feat/login-alerts into main
    b55d2a5 chore(login-alerts): demote send and suppression logs to debug
    f73f15a feat(account): log every login-alert suppression and success
    8178e52 feat(account): email user on sign-in from a new device
    bbb5452 Merge pull request 'feat(account-delete): refuse when caller is sole admin' (#85) from feat/account-deletion into main
    4531575 feat(account-delete): refuse when caller is sole admin
    d0bb0af Merge pull request 'feat(account): add self-serve account deletion' (#84) from feat/account-deletion into main
    2334446 feat(account): add self-serve account deletion
    ef5663d Merge pull request 'feat/account-data-export' (#83) from feat/account-data-export into main
    14db568 fix(account-export): hash session ids instead of exporting raw tokens
    5ffe42f feat(account): add GDPR-style data export
    841e6ff Merge pull request 'fix/db-write-contention' (#82) from fix/db-write-contention into main
    72be514 chore: remove diagnostic instrumentation now that the deadlock is fixed
    630f585 fix(auth): drop DashMap Ref before re-acquiring shard write lock
    d76ab51 diag(auth): add outer watchdog and post-lookup tracing in inject_user
    279ab19 diag(auth): trace every entry, branch, and exit in enforce_2fa
    8f14709 diag: per-step tracing in get_settings and ws_handler
    775b8b7 fix(main): bump tokio worker pool to 32 to survive CPU bursts
    8f3d8b6 fix(ws): wrap message renders with render_template so block_in_place applies
    928b73c fix(views): cache markdown render to stop tokio worker pinning under broadcast load
    eee6a4b fix(views): render templates with block_in_place to free the tokio worker
    7b4fd8d diag(auth): tighten phase watchdog to 1s and log on completion
    d6f5c00 diag(auth): use tokio::select! for phase watchdogs (reliable fire on timeout)
    868d7dd diag(routes): distinguish stuck requests from cancelled requests
    5d8abe2 Merge pull request 'chore: remove smtp migration from vapid test setup, add cargo clean permission' (#81) from feat/email-digest into main
    73970b1 chore: remove smtp migration from vapid test setup, add cargo clean permission
    d9ce8fd Merge pull request 'feat/email-digest' (#80) from feat/email-digest into main
    654c0a6 Merge main into feat/email-digest
    0bba1d3 diag: log every entry to log_slow_requests and inject_user
    24ed994 diag(auth): per-phase watchdogs in inject_user
    cd83f1c diag(auth): time session lookup and downstream handler separately
    8c4cc85 diag(routes): watchdog log fires while a request is still in-flight
    11f0de1 fix(views): warm syntect at startup to stop tokio-worker starvation
    4e53006 fix(db): prewarm pool, log slow requests, sample pool stats
    f80bc11 fix(db): batch high-frequency touches through a single background writer
    7def438 Merge pull request 'feat/multi-device-sessions' (#79) from feat/multi-device-sessions into main
    6d63775 fix(auth): drop transaction and add debounce on touch_user_activity
    1ca7dfc fix(db): enable WAL + busy_timeout to stop SQLITE_BUSY under write contention
    9045f47 docs(readme): document email-digest setup, semantics, and upgrade path
    8ca8a1f feat(digest): user-facing email + opt-in UI + admin default-for-new-users toggle
    f6af786 feat(auth): broaden OS detection in session-list device labels
    5ae0aa9 test(digest): pin the "new offline session re-fires" half of the gate
    d58536b feat(digest): ship the digest tick - eligibility, dispatch, scheduler, base URL
    75f3b3c feat(auth): per-session device list with revoke in settings
    04171b9 feat(digest): add content primitives - snippet helper + Askama templates
    749495a Merge pull request 'feat(auth): email verification on registration' (#78) from feat/email-verification into main
    7955ddf fix(admin): clarify the SMTP "not active" banner leads with the restart case
    117a00f chore: remove SaaS mode docs from CLAUDE.md and reformat Rust sources
    46839b6 feat(auth): email verification on registration
    5af5c74 feat(digest): wire admin SMTP form to typed config + add test-email button
    408c7d1 feat(digest): add migration and DB helpers for email digest tracking
    c28f8fd Merge pull request 'feat(auth): email-based password reset + in-settings password change' (#77) from feat/password-reset into main
    d4c84a6 feat(digest): track WS-receive activity in users.last_ws_seen_at
    06ddf62 feat(auth): email-based password reset + in-settings password change
    4b283f4 docs(plans): add phase 22 email digest plan
    2bfeac8 Merge pull request 'feat/broadcast-mentions' (#76) from feat/broadcast-mentions into main
    9c7047a refactor(mentions): move push concurrency cap to per-send level in dispatch
    768f674 feat(mentions): show broadcast-count hint in composer as user types @here/@channel
    95ea09b feat(mentions): add broadcast-count probe endpoint for composer preview
    49fcdf0 feat(mentions): surface @here/@channel in mention autocomplete popover
    b85c3a0 feat(mentions): cap push fan-out concurrency with a semaphore
    270933e feat(mentions): wire broadcast tokens into post/patch_message resolution
    5486d42 feat(mentions): add @here/@channel resolver helpers and broadcast chip rendering
    f1a04a1 Merge pull request 'chore(todo): remove TODO.md after tickets created' (#75) from chore/remove-todo into main
    642be5f chore(todo): remove TODO.md after tickets created
    07c1d42 Merge pull request 'feat(messages): per-user saved-messages list' (#74) from feat/saved-messages into main
    c7814ca feat(messages): per-user saved-messages list
    85fbe2b Merge pull request 'feat(messages): render bodies as markdown with syntax-highlighted code' (#73) from feat/markdown-rendering into main
    289d86a feat(messages): render bodies as markdown with syntax-highlighted code
    082b0fb Merge pull request 'docs(todo): refresh TODO.md with feature backlog' (#72) from docs/todo-feature-backlog into main
    14912ca docs(todo): refresh TODO.md with feature backlog
    241a334 Merge pull request 'fix(reactions): cancel button collapses entire emoji picker' (#71) from fix/reaction-picker-cancel into main
    b2847a7 fix(reactions): cancel button collapses entire emoji picker
    0adc72b Merge pull request 'feat(emojis): enclave-scoped custom emojis with optional global sharing' (#70) from feat/custom-emojis into main
    f1ddb15 Merge branch 'main' into feat/custom-emojis
    f897b36 feat(emojis): enclave-scoped custom emojis with optional global sharing
    7de3864 Merge pull request 'fix/listener-accumulation' (#69) from fix/listener-accumulation into main
    ae5911b chore: allow echo exit-code command in settings and tidy test assertion
    8c968ec docs(CLAUDE.md): document inline script teardown pattern and persistent-shell exception
    d2b6afb fix(blocked): tear down document click listener and debounce timer on HTMX cleanup
    07aa8b1 docs(layout): add comment explaining persistent-shell script lifetime rationale
    db0a013 docs(layout): clarify persistent-shell script lifetime to explain no teardown needed
    3f72269 fix(ws): tear down wsOpen listener on room page cleanup to prevent accumulation
    ad49914 fix(notify): tear down document click listener on HTMX cleanup to prevent accumulation
    c28db9e fix(composer): tear down htmx:afterSwap body listener on HTMX cleanup
    9ca0dac fix(ws): tear down body event listeners on HTMX cleanup to prevent accumulation across soft-refreshes
    fc45ea2 docs(superpowers): expand phase 20 smoke test and rationale detail
    78779e3 docs(superpowers): add phase 20 plan for listener accumulation fix
    fedc130 Merge pull request 'feat(pinned): re-render bubble on pin/unpin so hover menu flips immediately' (#68) from feat/pin-message into main
    a1aa74e Merge branch 'main' into feat/pin-message
    e83827c feat(pinned): re-render bubble on pin/unpin so hover menu flips immediately
    ccc4c99 Merge pull request 'chore: add install-hooks + pre-commit recipes' (#67) from chore/pre-commit-hook into main
    6d89711 Merge branch 'main' into chore/pre-commit-hook
    42f2572 Merge pull request 'feat/pin-message' (#66) from feat/pin-message into main
    bda082d chore(settings): add allowed commands for check, verify, server-down, and gh auth
    53ed844 chore(pinned): apply rustfmt and add migration 0016 to test fixtures
    a8a5ae4 Merge pull request 'Fix: replace nonexistent server feature flag in check.yml' (#65) from fix/check-yml-features-flag into main
    0a7a3fb fix: replace nonexistent server feature flag in check.yml
    1fd02b7 chore: add install-hooks + pre-commit recipes
    f53671c test(pinned): add route integration tests for pin/unpin feature
    293e696 feat(pinned): add pin/unpin routes, strip UI, and pins list page
    2a81cf6 Merge pull request 'chore/rust-builder-1.94' (#64) from chore/rust-builder-1.94 into main
    0d8aedf Merge branch 'main' into chore/rust-builder-1.94
    e17ff86 feat(pinned): add MessagePinned and MessageUnpinned WebSocket events
    74b0426 feat(pinned): add DB layer for pinned messages
    4b986bc Merge pull request 'ci: drop rustup component add now that opensuse-base ships them' (#63) from chore/drop-rust-toolchain-install into main
    09cf4bb docs(pinned): add Phase 19 pinned messages implementation plan
    9a2986a ci: drop rustup component add now that opensuse-base ships them
    c83dca6 Merge pull request 'feat(reconnect): visible reconnect indicator with backoff and soft-refresh' (#62) from feat/reconnect-ui into main
    cbfee49 chore(reconnect): apply rustfmt to routes_reconnect test file
    55503a0 test(reconnect): cover banner partial rendering and soft-refresh target
    8cde6e5 feat(reconnect): add WS reconnect/banner state machine
    7845ebe feat(reconnect): mount connection-status banner and reserve hx-ext slot
    52bf149 feat(reconnect): add connection-status banner partial
    f7982c7 docs(reconnect): add phase 18 plan for connection-lost UI
    7857a9b docs(reconnect): add Phase 18 WebSocket reconnect UI implementation plan
    a705252 ci: bump runtime stage from bookworm-slim to trixie-slim
    5936556 ci: build from rust-builder-* (rust 1.94)
    a4fc2a6 Merge pull request 'chore/sync-from-yotun' (#61) from chore/sync-from-yotun into main
    7d37f40 Merge from main and resolve conflicts
    9cd9ab2 chore: Sync .gitignore with other repos
    159aabc Merge pull request 'feat/dm-mute' (#60) from feat/dm-mute into main
    9fd5fd5 chore(settings): allow just --list in Claude Code permissions
    175b4ee refactor(notifications): remove redundant .into() calls on Protocol errors
    ab92d1f test(notifications): add integration tests for POST /dm/{peer_id}/mute route
    f5b26ae feat(notifications): add POST /dm/{peer_id}/mute route handler
    ba77c71 feat(notifications): implement DM mute toggle UI and remove DM-kind bypass
    2490c75 feat(notifications): expose mute_mode on SidebarPeer for DM sidebar rendering
    3c8787b feat(notifications): add set_dm_mute and enforce DM/non-DM room kind checks
    e073f84 docs(plans): add phase 17 per-DM mute implementation plan
    7614ff4 ci: bump actions/checkout to v5
    310ba22 Merge pull request 'feat/web-push' (#59) from feat/web-push into main
    bbbf74b docs(readme): expand LETS_CHAT_SECRET_KEY documentation and add crates.io/GitHub API fetch permissions
    830fd71 refactor(push): drop _pem_ infix from VAPID keypair columns and clarify LETS_CHAT_SECRET_KEY docs
    1831796 ci: build from rust-builder base images
    5ebac41 ci: pin dioxus-cli to 0.7.7 in builders
    7679b5b ci: cache cargo registry + git via BuildKit cache mounts
    da919b0 ci: switch OCI cache to registry mode=max
    fe41c5a ci(check): cache Rust build artifacts via Swatinem/rust-cache
    5570e9e ci: add Check workflow (fmt + clippy + build + tests)
    d5aadd9 ci: cap cargo build jobs at nproc/2 per pipeline
    f75f9a2 chore(deps): bump dioxus to 0.7.7
    9e10edd Merge pull request 'feat/web-push' (#58) from feat/web-push into main
    400f621 test(push): wire new AppState fields into remaining test harnesses
    d65aaec test(push): add dispatch and VAPID keypair integration tests
    7e8e673 test(push): add integration tests for push_subscriptions DB layer
    7e50661 test(push): apply migration 0009 in all in-memory test pool setups
    5cc87fa feat(push): wire service-worker registration into the browser notification flow
    800128c feat(push): add HTTP routes, payload builder, and settings UI for push notifications
    a0cf752 feat(push): add DB layer, dispatch logic, and production push client
    22fe853 feat(push): add notify_push_enabled field to user queries and prefs
    f07e485 feat(push): wire VAPID keypair and push client into AppState
    678c628 feat(push): add migrations for push subscriptions and VAPID keypair
    97ee3cf feat(push): add service worker and notification icon assets
    a97c253 feat(push): add web-push-native dependency and p256/base64 support
    72fda45 docs(plans): add Phase 16 web push notifications plan
    dc0b8c1 Merge pull request 'feat/room-mute' (#57) from feat/room-mute into main
    2a79a6d Feature: Per-room mute / notification preferences
    ff5d774 docs(plans): add Phase 15 per-room mute implementation plan
    2c26430 Merge pull request 'chore/display-version' (#56) from chore/display-version into main
    b9d0b12 chore(version): show build metadata in admin nav
    dac9f16 chore(version): show build metadata on settings page
    9428f0a chore(version): bake build metadata into all binaries
    1395aae Merge pull request 'feat(build): split standalone vs saas build modes' (#55) from feat/split-build-saas-standalone into main
    b221e45 feat(build): split standalone vs saas build modes
    d78f6c6 Merge pull request 'feat(auth): require password confirmation on registration' (#54) from feat/confirm-password into main
    d46785d feat(auth): require password confirmation on registration
    35b4c8d Merge pull request 'feat/two-factor-auth' (#53) from feat/two-factor-auth into main
    c925c91 feat(auth): TOTP two-factor authentication (squashed)
    b579003 Merge pull request 'feat/mentions-notifications' (#52) from feat/mentions-notifications into main
    28219ee test(mentions): add integration tests for mention routes
    b74580d test(mentions): apply migrations 0007 and 0014 to all in-memory test pools
    38c6e0d feat(mentions): add client-side mention notifications and @mention autocomplete
    8ff99d1 feat(mentions): render @mention chips in messages and push live mention events
    c5e9ec6 feat(mentions): wire up mention extraction, persistence, and fan-out
    65ee8ed feat(db): add mentions table and notification settings migrations
    ead085b feat(assets): add favicon SVGs and notification sound
    edb3c6c docs: add Phase 14 mentions/notifications plan and mark Phase 13 done
    a6c7267 chore: gitignore local Claude settings and add regex dependency
    21fa4da Merge pull request 'fix/search-preview' (#51) from fix/search-preview into main
    027c631 fix(blocked): drive block popover with plain fetch, not HTMX
    2962ed6 fix(blocked): send q param to /users/search from block popover
    549a7c9 feat(blocked): live people-search popover under "Block by username"
    ec62695 fix(search): render search as sidebar popover instead of full page
    c2a7dab Merge pull request 'feat/user-blocking' (#50) from feat/user-blocking into main
    4542d1c fix(users): gate username block lookup behind shared-enclave membership
    e00cbdd feat(users): block by username so private profiles can be blocked too
    0d1220b fix(users): hide blocked users' messages in rooms, threads, search, and ws
    559619b feat(users): block other users to hide them and prevent DMs
    f54d18f Merge pull request 'feat/profile-privacy' (#49) from feat/profile-privacy into main
    535d382 fix(dm): show inline error bubble instead of 404 when peer is private
    42847d8 feat(users): profile privacy toggle hides users from search and new DMs
    785559e Merge pull request 'feat(users): profile search by username and display name' (#48) from feat/profile-search into main
    2060c4e feat(users): profile search by username and display name
    5c7b980 Merge pull request 'fix(layout): wrap static-page sections in a full-width scroll container' (#47) from fix/scroll-wrapper-not-section into main
    4d44524 Merge pull request 'fix(layout): scroll body content on static pages so long lists are reachable' (#46) from fix/scrollable-static-pages into main
    174e8ba fix(layout): wrap static-page sections in a full-width scroll container
    587a1d9 merge
    c3a03a9 Merge branch 'long-fix'
    320c1b8 fix(uploads): move file input outside form to prevent HTMX multipart
    e03612b fix(layout): scroll body content on static pages so long lists are reachable
    947b0bf Merge pull request 'feat(composer): paste, drag/drop, and inline image preview for uploads' (#44) from feat/composer-paste-drop-preview into main
    76240d3 Merge pull request 'fix(layout): collapse sidebar to a drawer below the md breakpoint' (#43) from fix/mobile-drawer into main
    2a160dd Merge pull request 'feat(search): broaden Home search beyond DMs to include accessible rooms' (#42) from fix/search-include-rooms into main
    ae3448d Merge pull request 'feat(composer): textarea + send button + retry on failure' (#41) from feat/composer-multiline into main
    6a4d548 Merge pull request 'feat(routes): render unknown routes inside the app shell as a 404 page' (#40) from fix/404-shell into main
    5a65144 Merge pull request 'feat(sidebar): active DM/room highlight + resolved enclave member names' (#39) from fix/sidebar-active-and-member-names into main
    bee12c9 Merge pull request 'fix(status): close picker on save + Esc/click-outside dismiss + counter' (#38) from fix/status-auto-close into main
    d98d0d0 feat(composer): paste, drag/drop, and inline image preview for uploads
    da93cc3 fix(layout): collapse sidebar to a drawer below the md breakpoint
    24b02ba feat(search): broaden Home search beyond DMs to include accessible rooms
    0104acb feat(composer): textarea + send button + retry on failure
    7384e63 feat(routes): render unknown routes inside the app shell as a 404 page
    3975cb0 Merge branch 'feat/uploads'
    da14de9 feat(sidebar): active DM/room highlight + resolved enclave member names
    0dd5e46 fix(status): close picker on save + Esc/click-outside dismiss + counter
    5812131 style(uploads): apply rustfmt to phase 13 sources and tests
    b4ea90b feat(uploads): integration tests for upload, serve, and send-with-attachment
    0c9c338 Merge pull request 'feat(threads): Slack-style thread panel for rooms and DMs' (#36) from feat/threads into main
    206b266 feat(previews): SSRF-hardened /api/unfurl + lazy preview cards
    3a5dbd0 feat(uploads): render attachments inline in message fragment
    6ebfa9c feat(uploads): composer paperclip + staged-attachment chip
    ccb94c7 feat(uploads): link uploaded files to messages on send
    d1111ec feat(uploads): POST /api/upload + GET /api/files/:id endpoints
    bb7efe9 feat(uploads): Attachment model + db layer + MessageView wiring
    eea89f4 feat(threads): Slack-style thread panel for rooms and DMs
    a3f6347 feat(uploads): chat schema for file_uploads + link_previews
    28dfef8 feat(deps): add dependencies for file uploads and link previews
    7877bcd docs(uploads): add Phase 13 implementation plan for file uploads and link previews
    12f6748 Merge pull request 'feat(typing): wire client typing frames + clear on send' (#35) from feat/typing-indicator into main
    99508d1 feat(typing): wire client typing frames + clear on send
    5081351 Merge pull request 'feat/user-status' (#34) from feat/user-status into main
    adfc992 feat(status): render custom status text inline + live-update via WS
    d740688 fix(status): wrap WS status script in OOB swap target so HTMX runs it
    a866ea5 feat(status): live cross-user status updates over WebSocket
    7c2127b feat(status): derive offline status from hub presence
    a9651c7 feat(status): user availability (active/idle/dnd) + custom status text
    a12eb53 Merge pull request 'feat(profiles): editable display name, bio, and avatar' (#33) from feat/profiles into main
    644342b feat(profiles): editable display name, bio, and avatar
    7cd16ac Merge pull request 'feat/enclaves' (#32) from feat/enclaves into main
    3c43be6 feat(enclaves): /admin/enclaves shows every enclave on the server
    6ce978d fix(enclaves): scope rooms.name uniqueness per enclave
    5f12743 fix(enclaves): flash banner shows the conflicting name
    5c1813f fix(enclaves): flash error uses opaque code, never user-controlled text
    9feaed6 fix(enclaves): show duplicate-name error as inline banner instead of error page
    92a91f7 fix(enclaves): clean 400 on duplicate name instead of 500
    edbe6ae fix(enclaves): Home switcher button bypasses last_visited redirect
    12e6c41 fix(enclaves): sidebar scopes by current_enclave (DMs in Home, rooms in enclave)
    377d7e1 feat(enclaves): remove legacy POST /admin/rooms; admin listing read-only
    856fa26 feat(enclaves): broadcast member/room/invitation events from handlers
    e337f8b feat(enclaves): add ChatEvent variants for membership, rooms, invitations
    10e8809 chore(enclaves): rebuild Tailwind output + sync test-file fmt
    725508e feat(enclaves): updated welcome copy and link to invitations
    24f3590 feat(enclaves): expanded discover page with three sections
    cd6a86f feat(enclaves): full settings template with role/kick/transfer controls
    2ad888d feat(enclaves): expand enclave landing with inline manage forms
    e34de30 feat(enclaves): two-column chrome with enclave switcher partial
    7f82512 feat(enclaves): switcher entries on every page struct
    319ea35 fix(enclaves): tighten post_message access + DM redirect + idempotent join
    5634287 feat(enclaves): /search scopes to enclave or DMs
    89f3f93 feat(enclaves): route guards use is_room_accessible
    cbeb3af feat(enclaves): last_visited cookie redirect on /
    d29f77e feat(enclaves): per-enclave room CRUD + private-room member management
    399e35a feat(enclaves): settings page + edit/transfer/delete/leave/role/kick handlers
    68f8d62 feat(enclaves): direct invite + accept/decline + /invitations page
    c846192 feat(enclaves): discovery, visibility toggle, invite-code endpoints
    38fc637 feat(enclaves): GET /enclave/{id} landing with member-only access
    fba7448 feat(enclaves): POST /enclaves creates and redirects to landing
    f5f824b feat(enclaves): minimal view models + templates for enclave routes
    fa96cc3 fix(enclaves): gate backfill on actual promotion + repair created_by sentinel
    89bc116 feat(enclaves): permission helpers with site-admin godmode
    6a50ec3 feat(enclaves): list_rooms_in_enclave honors enclave + private-membership rule
    b17ff2e feat(enclaves): is_room_accessible covers DM, public, private + site admin godmode
    3552908 feat(enclaves): create_room takes enclave_id; admin room create uses General
    ba9e4cf feat(enclaves): run backfill at startup and after first-user promotion
    de6aaa2 feat(enclaves): backfill_general_membership reads auth users
    58f5375 feat(enclaves): metadata, visibility, invite-code, cascade delete
    c29b74d feat(enclaves): invitations CRUD + atomic accept
    cc6c7a9 feat(enclaves): transfer_ownership (atomic demote+promote)
    b55687b feat(enclaves): add_member, remove_member, update_role
    4bce800 feat(enclaves): list_enclaves_for_user, list_public_enclaves, list_members
    2021484 feat(enclaves): get_enclave, get_enclave_by_invite_code, get_membership
    a60f10c feat(enclaves): add db::enclave::create_enclave with owner-membership tx
    63aa376 feat(enclaves): add Enclave, EnclaveRole, EnclaveMembership, EnclaveInvitation models
    2a37fc2 feat(enclaves): add chat-DB schema migration
    1411df0 docs(enclaves): add phase 3 (UI) and phase 4 (realtime + cleanup) plans
    e9c4d12 docs(enclaves): add phase 2 plan (routes)
    62f5e76 docs(enclaves): add master plan index and phase 1 (DB foundation)
    da38a04 docs(enclaves): split migration data step from startup backfill
    bc2e8a4 docs(enclaves): add design spec
    01f8639 Merge pull request 'chore(docker): apply app-prefixed container name convention to compose files' (#31) from long-convention-name into main
    9b3d732 chore(docker): apply app-prefixed container name convention to compose files
    fe8859b Merge pull request 'feat/message-grouping' (#30) from feat/message-grouping into main
    66cd2b6 fix(composer): clear input synchronously on submit so rapid typing isn't lost
    d6155c9 feat(unread): render an unread-messages divider above the first new message
    469842c feat(scroll): sticky-bottom auto-scroll for rooms and DMs
    f68ab93 fix(ws): advance last-read watermark when receiving a message in a subscribed room
    49182e9 fix(grouping): tighten vertical spacing between follow-up messages
    01848b5 docs(plan): add message-grouping plan; apply rustfmt to tests
    6dd66d3 feat(grouping): promote next message to header when deleting a grouped header
    3b156b9 feat(grouping): compute is_follow_up on WS new-message and edit broadcasts
    cbf1384 feat(grouping): hide header and tighten spacing on follow-up messages
    ef562c6 feat(grouping): compute is_follow_up on page load and add prior/next helpers
    519a6d6 feat(grouping): add is_follow_up field to MessageView (defaulted to false)
    9400d7e feat(grouping): add MESSAGE_GROUPING_WINDOW_SECONDS const and is_follow_up_of predicate
    ba1a956 docs(spec): add design for grouping consecutive messages
    0461f46 Merge pull request 'fix(ws): restore "Seen" caption and live sidebar unread badges' (#29) from fix/read-receipts-and-realtime-notifications into main
    d756eb0 fix(ws): restore "Seen" caption and live sidebar unread badges
    62b8760 Merge pull request 'fix(ci): repair Forgejo workflows after the axum rewrite' (#28) from fix/forgejo-workflows into main
    f5a83d7 fix(ci): repair Forgejo workflows after the axum rewrite
    14647b8 Merge pull request 'fix(desktop): forward DISPLAY/Wayland and use host network in cargo-desktop' (#27) from fix/desktop-display-forwarding into main
    2049214 fix(desktop): forward DISPLAY/Wayland and use host network in cargo-desktop
    346edd7 Merge pull request 'fix/axum-rewrite-gaps' (#26) from fix/axum-rewrite-gaps into main
    bf98767 feat(admin): port mute, role, delete, room create/edit/invite/regenerate
    046e99d fix(ws): live updates for edited messages, new messages, and DM creation
    99678c6 fix(ui): always show message actions, fix CSS cache busting, clearer DM link
    181ca42 fix(ui): restore missing features lost in axum rewrite
    8f12ba1 Merge pull request 'fix(dev): unbreak Docker dev environment' (#25) from fix/dev-docker-env into main
    d168460 fix(dev): unbreak Docker dev environment
    003cc2c Merge pull request 'feat/axum-htmx-rewrite' (#24) from feat/axum-htmx-rewrite into main
    864865c chore: drop dx, desktop docker, obsolete plans, update CLAUDE.md
    caa7d92 feat(desktop): native webview wrapper using tao + wry
    ee97633 feat(read-receipts): unread badges and mark-as-read on view
    90d50b9 feat(admin): port admin pages to Askama+HTMX
    a912e47 docs(plan): update resume notes for tasks 14-17
    b830011 feat(search): full-text message search via /search?q=...
    c79910a feat(routes): direct messages render via /dm/:peer_id
    b9b95fe feat(reactions): add and remove reactions with HTMX picker
    0741d24 feat(routes): edit and delete message endpoints
    eb1ea0a feat(routes): send messages via POST /room/:id/messages
    b72e7f1 fix(ws): use OptionalUser extractor and gate typing on subscribed rooms
    5061d23 feat(ws): port /ws upgrade and broadcast pre-rendered HTML fragments
    08b5d99 feat(routes): render room view with message history (read-only)
    bd1edb9 refactor(models): impl From for User to deduplicate projection
    522ddc2 feat(views): render rooms list and DM peers in sidebar
    512b109 fix(auth): render correct form on register failure; transactional admin promote
    2f4b5d5 feat(auth): wire login, register, and logout routes
    2c8375d feat(auth): add cookie middleware and AuthUser/AdminUser extractors
    266e226 docs(plan): add resume notes for tasks 4-17
    38fa3ed refactor(views): introduce Html wrapper helper; drop dead asset_url
    f313cea feat(views): add Askama base layout, sidebar shell, and welcome page
    7111716 docs(plan): note Hub-instance unification as pre-step in Task 8
    6d4f4a0 feat(server): replace Dioxus with empty Axum app
    7ec92f6 chore: move Cargo.lock to workspace root and update gitignore path
    d7ddac1 chore: convert to cargo workspace and vendor htmx assets
    db74bc1 chore(dev): add Docker-based cargo and bun wrappers
    e425157 docs(plan): implementation plan for Axum + HTMX rewrite
    4a483d3 docs(spec): add Axum + HTMX rewrite design
    417c521 Merge pull request 'fix(auth): show "Username taken" instead of generic "Registration failed"' (#23) from fix/register-username-taken-error into main
    95dcc1c fix(auth): show "Username taken" instead of generic "Registration failed"
    5adc3c6 Merge pull request 'fix(reactions): broadcast reaction updates to all room viewers' (#22) from fix/reactions-broadcast-to-peers into main
    fcfd3a3 fix(reactions): broadcast reaction updates to all room viewers
    0ae3d25 Merge pull request 'fix/dm-stable-state-on-send' (#21) from fix/dm-stable-state-on-send into main
    a6d9d20 fix(sidebar): switch reactive futures to use_resource so refetches don't suspend the root
    4015774 fix(ws): guard signal writes from forget()'d closures to avoid panic
    8dc7040 fix(dm): stabilize component state across re-renders to stop refresh on send
    99fa68f Merge pull request 'feat(chat): allow users to delete their own messages' (#20) from feat/user-delete-own-messages into main
    66bb7f1 feat(chat): allow users to delete their own messages
    36381ef Add LICENSE
    ab0f1b3 Merge pull request 'long-lc-5' (#19) from long-lc-5 into main
    26eba88 docs(search): add Phase 11 message search implementation plan
    8caf2c1 feat(search): add SearchResult model, search_messages server fn, and db tests
    e6ca857 docs(todo): mark Phase 11 — Message Search as Done
    29065b0 chore(test): add db_search to test suite
    0061708 feat(search): add message search UI and FTS5 query backend
    f1d32be feat(search): add FTS5 virtual table and sync triggers for message search
    4359d67 Merge pull request 'long-lc-5' (#18) from long-lc-5 into main
    85176ec chore(settings): add cargo build and test permissions to local config
    4350627 feat(reactions): load room reactions on mount with single bulk query
    84640e5 docs(todo): mark Phase 10 reactions as done, update migration numbers
    d44962b feat(reactions): add db_reactions integration test to just test recipe
    0d184a6 feat(reactions): wire ReactionBar into room and DM views with WS sync
    634ee58 fix(reactions): rename migration to 0007_reactions.sql
    2078bb1 feat(reactions): wire toggle_reaction server fn and WS events
    68f9382 feat(reactions): add ReactionBar component and reactions server fn module
    9b2f1c7 feat(reactions): add toggle_reaction and list_reactions db functions
    5dc0444 feat(reactions): add message_reactions table and Reaction model
    75ce266 docs(plan): add phase 10 emoji reactions implementation plan
    383cb7d Merge pull request 'feat/auto-scroll' (#17) from feat/auto-scroll into main
    b8f2222 fix(chat): always sticky-scroll for own messages
    2336d70 fix(chat): sticky-bottom scroll + guard stale signal in visibilitychange
    b2a34de fix(chat): use Signal.read() for struct-field access and wrap message group for keying
    3a96d37 feat(chat): integrate auto-scroll into DM view
    3ce27a7 feat(chat): integrate auto-scroll into room view
    a808741 feat(chat): auto-dismiss pill and advance last-seen on manual scroll
    8b2020d feat(chat): implement auto-scroll open + sticky-bottom logic
    0c7e2ac feat(chat): add DOM scroll primitives for auto-scroll hook
    7442b7d feat(chat): add localStorage last-seen helpers
    71eee96 feat(chat): scaffold use_auto_scroll hook
    d3ab596 docs(auto-scroll): implementation plan for chat auto-scroll
    09769b5 docs(auto-scroll): spec for chat auto-scroll behavior
    2295119 Merge pull request 'fix(docker): persist SQLite data across restarts in compose.yml' (#16) from fix/persist-messages into main
    40c7ea7 fix(docker): persist SQLite data across restarts in compose.yml
    c344701 Merge pull request 'fix(ui): strip ServerFnError wrapper from all user-facing error messages' (#15) from feat/short-user-errors into main
    f13c9eb fix(ui): strip ServerFnError wrapper from all user-facing error messages
    aa9676d Merge pull request 'fix(auth): scope blank-input grace window to page mount, not server boot' (#14) from fix/register-grace-per-page into main
    d0daf39 fix(auth): scope blank-input grace window to page mount, not server boot
    b8a5e3b Merge pull request 'fix/websocket-messages' (#13) from fix/websocket-messages into main
    2a3c422 fix(chat): update message list via WebSocket events instead of refetching
    2a92f17 Merge pull request 'fix(db): use sqlx migrator so migrations don't re-run on every startup' (#12) from fix/oneshot-cancelled into main
    ad299b9 fix(db): use sqlx migrator so migrations don't re-run on every startup
    0aba125 Merge pull request 'feat(auth): blank-input grace window + generic register/login errors' (#11) from fix/register-error-window into main
    8ee6218 fix(auth): strip ServerFnError wrapper from user-facing messages
    d4e5de3 docs: spec and plan for register/login blank-input grace window
    b4b735f feat(auth): generic login errors + blank-input grace window
    fd348aa feat(auth): generic register errors + blank-input grace window
    2fd3a21 fix(auth): eagerly initialize server uptime clock at boot
    1fa44a4 feat(auth): add startup grace window helpers
    170f078 Merge pull request 'feat/stack-rework' (#10) from feat/stack-rework into main
    bfa9f46 chore(docker): pass --features client explicitly for desktop build
    c9661b4 chore(justfile): add check-client, update dev-desktop for client feature
    91856f8 refactor(main): split server and client entry points
    049beb7 refactor: gate server-only modules on feature = server
    a4f851d chore: rename desktop feature to client and gate server deps
    001bc15 docs: add server/client build split design
    1ea1880 Merge pull request 'fix/register-delay' (#9) from fix/register-delay into main
    cb9a66f style: cargo fmt
    f4e2c95 chore(auth): remove diagnostic console logs
    2d1b701 diag(auth): remove hydrated gate, inline form to test hydration path
    2fcae65 debug(auth): use_future+yield to flip hydrated, with console logging
    50b5dec fix(auth): use onmounted to trigger post-hydration form render
    1cfd09f fix(auth): flip hydrated via use_effect instead of use_hook+spawn
    b63461d feat(auth): render login form only after hydration
    6bc08a7 feat(auth): render register form only after hydration
    4e25c77 revert(web): restore SSR router
    8facb6d refactor(auth): drop hydration guards from login page
    e73c732 refactor(auth): drop hydration guards from register page
    4d5ae8f refactor(web): serve CSR shell + server fns instead of SSR
    4a104ba docs(plan): record Dioxus CSR research findings
    6a646f3 docs(plan): add CSR migration plan for auth hydration bugs
    041ce6f fix(auth): apply locked styles unconditionally and guard handlers pre-hydration
    e36bad9 feat(auth): disable login/register submit until WASM hydration finishes
    9d5b073 fix(auth): read login/register inputs from DOM to survive SSR hydration race
    47c6ece fix(components): remove spawn wrapper from oninput handlers
    f99358b Merge pull request 'feat/read-receipts' (#8) from feat/read-receipts into main
    9910a4f fix(dm): persist Seen label across refresh
    c71d70a fix(dm): ignore own DmRead events in peer read tracker
    e5792f5 fix(dm): notify recipient sidebar of new messages
    c74ba95 feat(sidebar): add read-receipts toggle in user menu
    3bc45aa feat(sidebar): show DM unread count badges
    d2c1ec4 feat(dm): mark read on visibility and render Seen label
    0c481e2 feat(server_fns): add set_read_receipts_enabled
    32d6d80 feat(server_fns): add mark_dm_read, peer read state, and unread counts
    7926f98 feat(ws): add DmRead event
    a982fe1 feat(db): add dm read-state upsert and unread counts
    632a58a feat(auth): add read_receipts_enabled user column
    e421e16 feat(migrations): add dm_read_state for read receipts
    04f058e docs(plan): add read-receipts implementation plan
    ba22f22 docs(spec): add read-receipts design and update TODO
    280af8a Merge pull request 'feat: Phase 8 — Typing Indicators & Phase 9 — Private Rooms' (#7) from long-branch into main
    b514399 fix(components): wrap oninput handlers in spawn for login, register, and dm_view
    2765685 fix(components): wrap signal mutations in spawn for Dioxus 0.7 compatibility
    2273293 feat(components): fix room navigation reactivity and auto-add creator on room creation
    efd86f3 chore: mark phase 9 complete and update dev/test config
    9dce497 feat(server_fns): add join/leave room server fns and fix invite_code migration
    da70a9e feat(components): migrate user context to Signal<Option> and replace form submit with explicit handlers
    b92ffb7 feat(tests): add private rooms test suite and migrate existing tests to new signatures
    ae0951e feat(server_fns): register rooms module in mod.rs
    bbe7f60 feat(components): add room type selector and invite controls to admin rooms UI
    18f901f feat(server_fns): add room type, invite user, and regenerate invite code endpoints
    ce8945b feat(db): add room membership queries and private room visibility
    f57eefb feat(components): add InvitePage component for joining rooms via invite code
    a501086 feat(routes): wire Invite component to InvitePage
    a649a2c feat(routes): add /invite/:code route for private room invites
    14f7b9e feat(migrations): add invite_code column and index for private rooms
    fc2be19 feat(db): run migration 005 for private rooms on startup
    c6b5035 feat(server_fns): enforce private room access control on chat endpoints
    8ef9eb4 feat(models): add invite_code field to Room struct
    e3a4aac feat(ws): add RoomMemberAdded and RoomMemberRemoved chat events
    01c016d docs(plan): add phase 9 private rooms implementation plan
    57bcf95 docs(readme): rewrite with features, tech stack, and docker quickstart
    0f8a9e0 Merge pull request 'feat: message editing and typing indicators (Phase 7 & 8)' (#6) from long-branch into main
    0d27f83 chore(settings): expand allowed bash permissions for git and docker
    e295621 docs(plan): mark phase 8 heading as Done
    04a929d docs(plan): mark all phase 8 typing indicator tasks complete
    551805c feat(dm): add typing indicator UI to DM view
    029b949 feat(room): add typing indicator UI to room view
    9580a90 feat(ws): add send_typing helper to WsHandle
    1e59d54 feat(ws): add UserTyping events and Typing client control
    52cbf33 feat(ws): add typing indicator support to Hub
    ce5c174 docs(plans): add Phase 8 typing indicators implementation plan
    95a7420 docs(todo): mark Phase 7 Message Editing as done
    ef14e83 fix(ui): use peek() instead of read() for messages_version counter
    f2738a0 chore(claude): allow docker run in local permissions
    d2bf8f7 test(db): add message editing integration tests
    4920689 test(db): apply message editing migration in DM and moderation test setups
    d017fa2 feat(ws): add MessageEdited variant to ChatEvent enum
    db80f6b feat(server): implement edit_message server function with auth and WS broadcast
    d1b0627 feat(ui): add inline message editing to room and DM views
    2536a68 feat(db): add edited_at column to messages table
    e5a2f90 docs: add Phase 7 message editing implementation plan
    15c6c6e docs: add phased development roadmap for Phases 7–13
    2b7aba5 init
    529cabf Merge pull request 'fix(docker): add Bun and Tailwind CSS build to dev Dockerfile, remove TODO.md' (#5) from feat/css into main
    56b2bfa fix(docker): add Bun and Tailwind CSS build to dev Dockerfile, remove TODO.md
    f760d87 Merge pull request 'fix(auth): set session cookie client-side for Dioxus 0.7.5 compat' (#4) from fix/login into main
    b929710 fix(auth): set session cookie client-side for Dioxus 0.7.5 compat
    3476318 Merge pull request 'feat/just-dev-web-traefik' (#3) from feat/just-dev-web-traefik into main
    fc174ad fix: bind dx serve to 0.0.0.0:8080, rename domain to chat.a8n.run, fix HeaderValue parse
    4818b73 fix: update to dioxus-fullstack 0.7.5 API and fix compilation errors
    69f457e feat(dev): add dev-web-down and dev-web-clean just recipes
    160e73f fix(docker): mount migrations directory in dev compose files
    e8c43c5 fix(docker): update dx to 0.7.5 and set platform web in dev Dockerfile
    e146f66 feat(dev): add Traefik-based dev-web and split local into dev-web-local
    0291afc Merge pull request 'feat/admin-users-mods-chat' (#2) from feat/admin-users-mods-chat into main
    dd7614f chore: update Cargo.lock
    1f493db fix(ws): add is_dm field to filter sidebar refresh, add 30s ping for stale connection detection
    9545be6 docs: mark Phase 6 WebSockets complete, update TODO.md and add plan
    3447c51 fix(ws): handle broadcast lag gracefully, verify DM room membership on subscribe
    41ae3bc feat(ws): refresh sidebar DM list on WebSocket events
    c18c27c feat(ws): wire up WebSocket in auth layout, room view, and DM view
    c00bcc2 feat(ws): add use_websocket client hook with auto-reconnect
    dd9feae feat(ws): broadcast events from send_message, send_dm_message, and moderation actions
    c0585b8 feat(ws): register /ws route on Axum router
    23896a6 feat(ws): add /ws endpoint handler with auth and subscribe/unsubscribe
    86de2f0 feat(ws): add connection hub with room subscriptions and broadcast
    973377f feat(ws): add ChatEvent enum and ws module structure
    80f982d Merge pull request 'feat/admin-users-mods-chat' (#1) from feat/admin-users-mods-chat into main
    f8bb49b chore: update .gitignore and remove stale data files from tracking
    6bb6728 docs: expand TODO.md with project structure, patterns, and agent-friendly guidance
    2ad8531 docs: add TODO.md with project status and remaining work
    884d428 docs: add Phase 5 DM implementation plan
    72087fb feat: add DM view, route, sidebar DM section, and username DM links
    aeba5a5 test: add DM integration tests
    da80872 feat: add DM server functions (get_or_create_dm, list_my_dms, send_dm_message)
    a854bf1 feat: add DM migration, room_type field, and DM DB functions
    6956643 docs: add Phase 2 and Phase 4 implementation plans
    7f352ec feat: add message delete button and mute banner in room view
    9070d89 feat: add moderation actions UI on admin users page
    f257ba4 feat: add Mod Log page, moderator access to admin panel
    2ba161f test: add moderation DB tests (ban, mute, suspend, soft-delete, audit log)
    85f29d1 feat: add moderation server functions (ban, mute, suspend, kick, delete_message)
    f7e646a feat: add moderation migration, models, and DB functions
    1eb65b2 feat: add admin rooms page with create, edit, and delete
    0f891cb feat: add admin invite codes page with generation and revocation
    b1246da feat: add admin users page with role management and deletion
    c68631b feat: add admin settings page with grouped form cards
    59e667b feat: add admin layout with tabbed navigation and nested routes
    ea216f3 test: add settings and invite code DB tests
    d84268f feat: add admin server functions for Phase 3 admin panel
    10e7fb9 feat: add room management DB functions for admin panel
    c52c3df feat: add admin user management and invite code DB functions
    d88d8d9 feat: add settings database, pool, and SiteSettings model
    d495d41 test: add RBAC role hierarchy tests
    b2e971c feat: admin link in sidebar, visible only to admin users
    472762a refactor: use require_auth helper in chat server functions
    d5a614b feat: add require_auth and require_role server-side helpers
    b9a9bd3 feat: sidebar user info, chat uses authenticated user identity
    48cc30a feat: auth server functions, login/register pages, AuthLayout, route protection
    69a643e feat: auth DB layer with user CRUD, sessions, and tests
    b9c00a0 db: add auth pool initialization alongside chat pool
    d64dc4f models: add User, UserRecord, and Session structs
    15f66c1 db: add auth migration for users, sessions, invite_codes
    85a4b3d deps: add argon2, rand, axum-extra, time for auth
    9d121f6 docs: add Phase 1 (Auth) implementation plan
    16a111e docs: add Let's Chat application design spec and FUTURE.md
    ff64fec feat: Initial application

    Downloads