ksmithandClaude Sonnet 5 85dc83f4e5 Fix presence showing offline on non-chat pages, and a room-join bug it exposed
The WebSocket connection lived entirely inside ChatShellPage, so
navigating to /admin (which never opens its own connection) unmounted
it -- the server correctly marked the user offline since the
connection genuinely closed, even though they were still logged in
and using the app. New ChatSocketContext.tsx hoists the connection to
App.tsx, shared across every authenticated route via a single
provider (keyed by user id, so a logout/login as a different account
gets a clean reconnect rather than an old connection lingering under
a new identity) instead of living inside whichever page happens to be
mounted.

Verifying that fix surfaced a second, independent bug: #31's
visibility handling had gated the *explicit* joinRoom/leaveRoom calls
(fired when a room actually mounts/unmounts in the UI) on the same
isVisibleRef check meant for automatic background/foreground
transitions. That's wrong -- a room can only be opened by a real user
interaction, which can't happen on a genuinely backgrounded tab, so
gating it too meant a stale or momentarily-wrong visibility reading
at mount time could silently skip the join with nothing to ever retry
it. joinRoom/leaveRoom now always send immediately; only the
automatic hide/show transitions and the reconnect replay stay gated
on visibility, which is what #31 actually needed.

Verified both end-to-end in the browser: navigating to /admin via
real in-app navigation (not a reload) keeps the presence dot online,
confirmed via direct Redis inspection and the /api/users/online
endpoint; opening a room and sending a message works immediately
afterward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-16 16:37:40 -06:00

DS Chat

A web-based team chat service (Mattermost-style, no threaded conversations), invite-only. See ARCHITECTURE.md for the full system design and phased build plan.

Phase 1: auth, open-room CRUD, and single-instance WebSocket chat, backend

  • a minimal frontend. Phase 2: private rooms, room roles (owner/admin/ member), and room invites — backend only, see below. Later phases (push notifications, Redis fan-out, the admin portal, the bot/extension system, and production deployment) are tracked as issues in the repo's issue tracker, prioritized.

Structure

  • backend/ — FastAPI + SQLAlchemy 2.0 (async) + PostgreSQL. See backend/README.md for local setup, migrations, how to create a user (site registration is invite-only — no public sign-up endpoint), and the Phase 2 room-roles/invites API.
  • frontend/ — React + Vite PWA (login, room list, chat view). Still Phase-1-only: it doesn't yet call any of the Phase 2 endpoints. A UI redesign is happening separately; frontend work resumes once that lands.

Quickstart

# 1. Postgres (see backend/README.md for details)
docker run -d --name ds-chat-postgres \
  -e POSTGRES_USER=ds_chat -e POSTGRES_PASSWORD=ds_chat -e POSTGRES_DB=ds_chat \
  -p 5432:5432 postgres:16-alpine

# 2. Backend
cd backend
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
cp .env.example .env   # then set SESSION_SECRET
.venv/bin/alembic upgrade head
.venv/bin/python -m app.cli create-user alice alice@example.com "some-password"
.venv/bin/uvicorn app.main:app --reload &

# 3. Frontend (in another shell)
cd frontend
npm install
npm run dev

Then open http://localhost:5173 and log in with the account created above. The Vite dev server proxies /api and /ws to the backend on :8000, so no CORS configuration is needed in development.

Deployment

See DEPLOYMENT.md for the full production runbook — two Debian 13 servers, no containers, matching ARCHITECTURE.md §9.

S
Description
No description provided
Readme AGPL-3.0
4.1 MiB
v2026.9.4
Latest
2026-09-04 21:38:08 -06:00
Languages
Python 54%
TypeScript 39.6%
CSS 5.9%
Shell 0.4%