https://github.com/john0isaac/fastroom
Project demonstrating a modern realtime stack: authenticated rooms, chat, presence, typing indicators, and a clean separation of concerns between a FastAPI backend and a Vue 3 SPA frontend.
https://github.com/john0isaac/fastroom
fastapi postgres redis vue
Last synced: 3 months ago
JSON representation
Project demonstrating a modern realtime stack: authenticated rooms, chat, presence, typing indicators, and a clean separation of concerns between a FastAPI backend and a Vue 3 SPA frontend.
- Host: GitHub
- URL: https://github.com/john0isaac/fastroom
- Owner: john0isaac
- License: mit
- Created: 2025-08-17T00:27:24.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2025-10-20T10:24:17.000Z (8 months ago)
- Last Synced: 2025-10-25T03:35:01.316Z (8 months ago)
- Topics: fastapi, postgres, redis, vue
- Language: Python
- Homepage:
- Size: 220 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# FastRoom – Real-time Rooms (FastAPI + Vue + Redis + Postgres)
Project demonstrating a modern realtime stack: authenticated rooms, chat, presence, typing indicators, and a clean separation of concerns between a FastAPI backend and a Vue 3 SPA frontend.
## Stack Overview
- Backend: FastAPI (async), Uvicorn, SQLAlchemy (async), Alembic, Redis (pub/sub + presence), PostgreSQL
- Frontend: Vue 3, Vite, Pinia, vue-router, generated OpenAPI client (axios)
- Tooling: uv (Python packaging), ESLint (flat config), Prettier, Ruff, mypy, pytest
- Infra / Local Dev: Docker Compose (api, web, redis, postgres)
## Architecture
```mermaid
flowchart LR
subgraph Client
B["Browser
(Vue 3 SPA Vite + Pinia)"]
end
subgraph Backend
A["FastAPI App
(REST + WebSocket)"]
L[Auth & Tokens
JWT + Rotating Refresh]
end
R[(Redis
Pub/Sub + Presence)]:::cache
P[(PostgreSQL
Persistent Data)]:::db
B -->|REST /api| A
B <-->|WebSocket /ws| A
A -->|"SQLAlchemy (async)"| P
L -->|Store hashed refresh| P
A <-->|Pub/Sub fanout| R
A -->|Presence heartbeats| R
R -->|Diffs & state| A
L -->|Issue / verify JWT| B
classDef db fill:#0366d6,stroke:#044e9b,color:#fff;
classDef cache fill:#ff9900,stroke:#cc7a00,color:#000;
class P db;
class R cache;
```
Key points:
- Browser SPA talks to FastAPI via REST for CRUD/auth and a persistent WebSocket for realtime chat + presence.
- Redis handles fanout (multi‑process) and ephemeral presence (heartbeat keys -> diffs/state messages).
- PostgreSQL stores users, rooms, messages, membership, and hashed refresh tokens (rotation + revocation list semantics).
- Rotating refresh tokens reduce replay window; access tokens stay short‑lived.
## Key Features
- JWT access tokens + rotating refresh tokens (hashed persisted) with revocation
- Rooms CRUD, membership & moderation (mute, ban, promote/demote moderator)
- Persistent chat history with pagination, edit & delete (with WS fanout)
- Presence via Redis heartbeat keys (diff + full state messages)
- Typing indicators, backlog on join, incremental history loading
- Multi-process/WebSocket fanout via Redis pub/sub (srv tag to avoid echo)
- Cleanly generated TypeScript client from OpenAPI spec
## Repository Structure
```text
.
├── docker-compose.yml # Compose services: api, web, redis, postgres
├── .pre-commit-config.yaml # Python lint/type/format hooks
├── backend/
│ ├── Dockerfile.api # Multi-stage Python build (uv)
│ ├── pyproject.toml # Project + deps (prod/test/dev extras)
│ ├── alembic.ini # Alembic config
│ ├── migrations/ # Alembic migration scripts
│ └── src/fast_room_api/
│ ├── api/ # FastAPI app + routers
│ ├── models/ # Pydantic + ORM models + config
│ ├── logging_config.py
│ └── tests/ # pytest suites (unit + integration)
├── frontend/
│ ├── Dockerfile.web # Node build then nginx serve
│ ├── package.json
│ ├── vite.config.ts # Dev server + proxy (/api, /ws)
│ └── src/
│ ├── components/ # Shared UI pieces
│ ├── pages/ # Route-level views
│ ├── stores/ # Pinia state (auth etc.)
│ ├── utils/ # WebSocket & helpers
│ ├── plugins/ # App plugins (auth client)
│ └── generated/openapiclient/ # AUTO-GENERATED: do not edit
└── README.md # (this file)
```
See `backend/README.md` and `frontend/README.md` for deeper service-specific details.
## Quick Start
### 1. Local (no Docker)
Backend:
```bash
cd backend
uv venv
source .venv/bin/activate
uv sync
uv run src/fast_room_api/api/main.py
```
Frontend:
```bash
cd frontend
yarn
yarn dev
```
Navigate to (API on by default).
### 2. Docker Compose
From repo root:
```bash
docker compose up --build
```
Services:
- API:
- Frontend:
- Redis: localhost:6379
- Postgres: localhost:5433 (db `fastroom`, user/pass `postgres`)
### 3. Regenerate OpenAPI Client
Start backend, then:
```bash
cd frontend
yarn generate:client
```
## Environment Variables (Summary)
Backend (see `backend/README.md` for full list):
- `FASTROOM_SECRET` – JWT signing secret (change in prod)
- `DATABASE_URL` – async DB URL
- `WS_HEARTBEAT_INTERVAL` / `WS_HEARTBEAT_TTL_MS` – presence timings
- `SERVER_ID` – optional override for process id tag
Frontend:
- `VITE_WS_URL` – WebSocket endpoint (defaults to `ws://localhost:8000/ws`)
Compose sets Postgres and DB URL automatically for the API container.
## Testing
Backend tests:
```bash
cd backend
uv run pytest -q
```
(Frontend tests not yet implemented – roadmap includes Vitest + Playwright.)
## Lint & Format
Backend (pre-commit can automate on commit):
```bash
pre-commit run --all-files
```
Frontend:
```bash
cd frontend
yarn lint
yarn format:check
```
## WebSocket Protocol (High-Level)
Inbound: `join`, `leave`, `chat`, `history_more`, `typing`, `ping`.
Outbound: `system`, `joined`, `presence_state`, `presence_diff`, `chat`, `history`, `history_more`, `typing`, `pong`, `error`.
Presence: heartbeat keys `presence:hb:{room}:{username}:{connId}` refreshed every interval; first key triggers diff `join`, deletion triggers `leave` diff.
For exhaustive details see backend README section “WebSocket Protocol”.
## Data Flow (Simplified)
1. User registers & logs in -> gets access + refresh tokens.
2. SPA stores tokens (refresh token secure storage recommendation) and opens WS with access token.
3. Join room -> server ensures membership, sends backlog + presence state.
4. Chat messages persist to Postgres, fanned out locally + via Redis to all processes.
5. Presence maintained by heartbeat; disconnect triggers immediate presence diff.
6. Refresh flow rotates refresh tokens (old revoked) for long-lived sessions.
## Code Generation & Types
OpenAPI spec at `/openapi.json` drives TypeScript client generation (axios wrapper) to keep frontend strongly typed for REST calls. WebSocket message types will later be unified into a shared schema.
## Contributing
Contributions are welcome! Please follow the guidelines in [`CONTRIBUTING.md`](./CONTRIBUTING.md).
## Security Notes
- Always override `FASTROOM_SECRET` outside local dev.
- Rotate secrets and revoke outstanding refresh tokens upon compromise.
## License
This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.
---
Additional deep-dive docs live in: [`backend/README.md`](./backend/README.md) and [`frontend/README.md`](./frontend/README.md).