- Single unified flow: phone → SMS code → (if new: enter name)
- POST /api/auth/complete — verifies OTP, logs in or registers
- Removed password from login/register completely
- New users get random password_hash (not used for auth)
- Removed password change section from ProfileModal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- All users are equal — no is_admin superuser
- Removed AdminPanel, Shield button from sidebar
- isOwnerOrAdmin checks only by chat role (owner/admin)
- Removed auto-seed of admin user on startup
- DB already cleared on server
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Registration form on login page (tab toggle login/register)
- POST /api/auth/register — creates account with phone+name+password
- Phone mask +7 (XXX) XXX-XX-XX on login and profile pages
- Username now editable in profile (latin/digits/_, 3-30 chars)
- PUT /api/auth/me now accepts username with uniqueness validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add swipe-to-reveal in mobile chat list (right=pin, left=mute/leave)
- Pin/mute API endpoints with is_pinned DB column migration
- Show pin icon on pinned chats, mute icon on muted chats
- Pinned chats sort to top of list
- Fix push notifications sent to message sender (filter uid)
- Remove debug console.log from WS handler
- Fix chat rename not updating in sidebar without reload
- Fix emoji picker z-index and positioning on mobile (z-50, bottom-full)
- Add last seen time in chat header for private chats
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Track when others read messages via messages_read WS event
- Show Check (single) for sent, CheckCheck (double) only when read
- Send push to all recipients, SW suppresses if app is focused
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@fastify/websocket v8 passes Duplex stream as first arg, not ws.WebSocket directly.
socket.on('message') never fired because Duplex streams don't emit 'message' events.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MessageInput: HTTP fallback when WebSocket not OPEN (prevents silent failures)
- WsClient: add trySend() returning bool to detect WS availability
- Backend: POST /api/messages/chat/:chatId endpoint for HTTP message send
- openOrCreatePrivate: use openChat() for consistency after refreshing chat list
- iOS fix: inputs get font-size:16px on mobile to prevent Safari auto-zoom
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- openOrCreatePrivate: load chat by ID directly (skip stale list lookup)
- GET /api/chats/🆔 resolve title/avatar/privateUserId for private chats
(was returning null title, causing chat area to behave unexpectedly)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Login: by phone number instead of username
- Position field: shown as badge next to name in members list, search, admin panel
- Logout: moved from sidebar to profile modal settings
- Sidebar search: global — shows matching users with one-click private chat
- Admin panel: new Чаты tab showing all chats with delete, position/phone in user form
- Backend: /api/admin/chats endpoint, position column migration, phone login support
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>