Scroll handler now checks !hasMore to avoid calling fetchOlderMessages
when all messages are loaded. Previously the handler would fire on every
scroll event (since scrollTop stayed < 100), creating a .then() callback
loop that adjusted scroll position repeatedly, causing 'stuck' scrolling.
SameSite=None requires Secure=true or modern browsers silently reject
the Set-Cookie header. Since the site is served over HTTPS via Caddy,
this was causing login to succeed (200) but the session cookie to be
dropped, making the subsequent /auth/me call fail with 401.
SameSite=Lax is the correct setting for same-origin session cookies.
- fetchMe() no longer surfaces 401 as a user-facing error (it just
means 'no session', not a failure)
- API client auto-clears auth state on 401 mid-session so the user
gets redirected to login instead of seeing 'ERR: Request failed: 401'
- Session middleware now accepts Authorization: Bearer <token> header
as fallback when no cookie is present (for Tauri/native clients)
- Login, register, and WebAuthn endpoints expose X-Session-Token header
so non-browser clients can capture the token
- usePermissions ORs current user roles + @everyone only (not all server roles)
- cache myRolesByServer; load on active server; refresh after self role edit
- gate/notify @everyone and @channel; plain @username push; special mention UI
- refresh FEATURE_PARITY (DMs exist; drop stale critical gaps)
- README production deploy notes dumpster.service
- unit tests for permission bits and broadcast mention tokens
Members API appends server bots (is_bot). Sidebar groups ONLINE / OFFLINE / BOTS.
Bots get green BOT badge, no kick menu or profile. Mentions and DMs skip bots.
Root cause of "not anonymous":
1. Confess deleted via raw SQL with no MESSAGE_DELETE broadcast
2. Frontend extractIds only accepted message_id, but deletes send id
so live clients never removed deleted messages without refresh
Fix:
- Intercept /confess at message create: never store or broadcast the
original; post only the anonymous bot message
- Accept both id and message_id on MESSAGE_DELETE in the WS store
- Include both fields on delete broadcasts
Root cause: makeSender requires bot_servers membership, but create
flow never auto-added bots when users only picked a channel.
- Start() resolves config.channel_id → server and upserts bot_servers
- Confess cursor uses (created_at,id) so deletes don't stall polling
- MobileBottomNav: [SERVERS] [CHAT] [MEMBERS] tab bar, always visible
- Servers tab opens sidebar overlay, chat/members switch views
- Removed hamburger + members toggle from mobile top bar
- Top bar compact on mobile (no redundant buttons)
- safe-area-inset-bottom on nav, clean inset on frame
- Desktop status bar hidden on mobile, preserved on desktop
- Dead MobileNav/MobileDrawer left in place (unused, can prune later)