{"id":30349708,"url":"https://github.com/john0isaac/fastroom","last_synced_at":"2026-04-11T04:32:35.545Z","repository":{"id":310281008,"uuid":"1039317726","full_name":"john0isaac/fastroom","owner":"john0isaac","description":"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.","archived":false,"fork":false,"pushed_at":"2025-10-20T10:24:17.000Z","size":225,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-25T03:35:01.316Z","etag":null,"topics":["fastapi","postgres","redis","vue"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/john0isaac.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-17T00:27:24.000Z","updated_at":"2025-09-12T16:32:35.000Z","dependencies_parsed_at":"2025-08-17T02:38:31.038Z","dependency_job_id":null,"html_url":"https://github.com/john0isaac/fastroom","commit_stats":null,"previous_names":["john0isaac/fastroom"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/john0isaac/fastroom","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/john0isaac%2Ffastroom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/john0isaac%2Ffastroom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/john0isaac%2Ffastroom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/john0isaac%2Ffastroom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/john0isaac","download_url":"https://codeload.github.com/john0isaac/fastroom/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/john0isaac%2Ffastroom/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31669114,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T17:19:37.612Z","status":"online","status_checked_at":"2026-04-11T02:00:05.776Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastapi","postgres","redis","vue"],"created_at":"2025-08-18T20:08:48.632Z","updated_at":"2026-04-11T04:32:35.520Z","avatar_url":"https://github.com/john0isaac.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FastRoom – Real-time Rooms (FastAPI + Vue + Redis + Postgres)\n\nProject 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.\n\n## Stack Overview\n\n- Backend: FastAPI (async), Uvicorn, SQLAlchemy (async), Alembic, Redis (pub/sub + presence), PostgreSQL\n- Frontend: Vue 3, Vite, Pinia, vue-router, generated OpenAPI client (axios)\n- Tooling: uv (Python packaging), ESLint (flat config), Prettier, Ruff, mypy, pytest\n- Infra / Local Dev: Docker Compose (api, web, redis, postgres)\n\n## Architecture\n\n```mermaid\nflowchart LR\n    subgraph Client\n        B[\"Browser\u003cbr/\u003e(Vue 3 SPA Vite + Pinia)\"]\n    end\n\n    subgraph Backend\n        A[\"FastAPI App\u003cbr/\u003e(REST + WebSocket)\"]\n        L[Auth \u0026 Tokens\u003cbr/\u003eJWT + Rotating Refresh]\n    end\n\n    R[(Redis\u003cbr/\u003ePub/Sub + Presence)]:::cache\n    P[(PostgreSQL\u003cbr/\u003ePersistent Data)]:::db\n\n    B --\u003e|REST /api| A\n    B \u003c--\u003e|WebSocket /ws| A\n    A --\u003e|\"SQLAlchemy (async)\"| P\n    L --\u003e|Store hashed refresh| P\n    A \u003c--\u003e|Pub/Sub fanout| R\n    A --\u003e|Presence heartbeats| R\n    R --\u003e|Diffs \u0026 state| A\n    L --\u003e|Issue / verify JWT| B\n\n    classDef db fill:#0366d6,stroke:#044e9b,color:#fff;\n    classDef cache fill:#ff9900,stroke:#cc7a00,color:#000;\n    class P db;\n    class R cache;\n```\n\nKey points:\n\n- Browser SPA talks to FastAPI via REST for CRUD/auth and a persistent WebSocket for realtime chat + presence.\n- Redis handles fanout (multi‑process) and ephemeral presence (heartbeat keys -\u003e diffs/state messages).\n- PostgreSQL stores users, rooms, messages, membership, and hashed refresh tokens (rotation + revocation list semantics).\n- Rotating refresh tokens reduce replay window; access tokens stay short‑lived.\n\n## Key Features\n\n- JWT access tokens + rotating refresh tokens (hashed persisted) with revocation\n- Rooms CRUD, membership \u0026 moderation (mute, ban, promote/demote moderator)\n- Persistent chat history with pagination, edit \u0026 delete (with WS fanout)\n- Presence via Redis heartbeat keys (diff + full state messages)\n- Typing indicators, backlog on join, incremental history loading\n- Multi-process/WebSocket fanout via Redis pub/sub (srv tag to avoid echo)\n- Cleanly generated TypeScript client from OpenAPI spec\n\n## Repository Structure\n\n```text\n.\n├── docker-compose.yml          # Compose services: api, web, redis, postgres\n├── .pre-commit-config.yaml     # Python lint/type/format hooks\n├── backend/\n│   ├── Dockerfile.api          # Multi-stage Python build (uv)\n│   ├── pyproject.toml          # Project + deps (prod/test/dev extras)\n│   ├── alembic.ini             # Alembic config\n│   ├── migrations/             # Alembic migration scripts\n│   └── src/fast_room_api/\n│       ├── api/                # FastAPI app + routers\n│       ├── models/             # Pydantic + ORM models + config\n│       ├── logging_config.py\n│       └── tests/              # pytest suites (unit + integration)\n├── frontend/\n│   ├── Dockerfile.web          # Node build then nginx serve\n│   ├── package.json\n│   ├── vite.config.ts          # Dev server + proxy (/api, /ws)\n│   └── src/\n│       ├── components/         # Shared UI pieces\n│       ├── pages/              # Route-level views\n│       ├── stores/             # Pinia state (auth etc.)\n│       ├── utils/              # WebSocket \u0026 helpers\n│       ├── plugins/            # App plugins (auth client)\n│       └── generated/openapiclient/  # AUTO-GENERATED: do not edit\n└── README.md                   # (this file)\n```\n\nSee `backend/README.md` and `frontend/README.md` for deeper service-specific details.\n\n## Quick Start\n\n### 1. Local (no Docker)\n\nBackend:\n\n```bash\ncd backend\nuv venv\nsource .venv/bin/activate\nuv sync\nuv run src/fast_room_api/api/main.py\n```\n\nFrontend:\n\n```bash\ncd frontend\nyarn\nyarn dev\n```\n\nNavigate to \u003chttp://localhost:5173\u003e (API on \u003chttp://127.0.0.1:8000\u003e by default).\n\n### 2. Docker Compose\n\nFrom repo root:\n\n```bash\ndocker compose up --build\n```\n\nServices:\n\n- API: \u003chttp://localhost:8000\u003e\n- Frontend: \u003chttp://localhost:5173\u003e\n- Redis: localhost:6379\n- Postgres: localhost:5433 (db `fastroom`, user/pass `postgres`)\n\n### 3. Regenerate OpenAPI Client\n\nStart backend, then:\n\n```bash\ncd frontend\nyarn generate:client\n```\n\n## Environment Variables (Summary)\n\nBackend (see `backend/README.md` for full list):\n\n- `FASTROOM_SECRET` – JWT signing secret (change in prod)\n- `DATABASE_URL` – async DB URL\n- `WS_HEARTBEAT_INTERVAL` / `WS_HEARTBEAT_TTL_MS` – presence timings\n- `SERVER_ID` – optional override for process id tag\n\nFrontend:\n\n- `VITE_WS_URL` – WebSocket endpoint (defaults to `ws://localhost:8000/ws`)\n\nCompose sets Postgres and DB URL automatically for the API container.\n\n## Testing\n\nBackend tests:\n\n```bash\ncd backend\nuv run pytest -q\n```\n\n(Frontend tests not yet implemented – roadmap includes Vitest + Playwright.)\n\n## Lint \u0026 Format\n\nBackend (pre-commit can automate on commit):\n\n```bash\npre-commit run --all-files\n```\n\nFrontend:\n\n```bash\ncd frontend\nyarn lint\nyarn format:check\n```\n\n## WebSocket Protocol (High-Level)\n\nInbound: `join`, `leave`, `chat`, `history_more`, `typing`, `ping`.\n\nOutbound: `system`, `joined`, `presence_state`, `presence_diff`, `chat`, `history`, `history_more`, `typing`, `pong`, `error`.\n\nPresence: heartbeat keys `presence:hb:{room}:{username}:{connId}` refreshed every interval; first key triggers diff `join`, deletion triggers `leave` diff.\n\nFor exhaustive details see backend README section “WebSocket Protocol”.\n\n## Data Flow (Simplified)\n\n1. User registers \u0026 logs in -\u003e gets access + refresh tokens.\n2. SPA stores tokens (refresh token secure storage recommendation) and opens WS with access token.\n3. Join room -\u003e server ensures membership, sends backlog + presence state.\n4. Chat messages persist to Postgres, fanned out locally + via Redis to all processes.\n5. Presence maintained by heartbeat; disconnect triggers immediate presence diff.\n6. Refresh flow rotates refresh tokens (old revoked) for long-lived sessions.\n\n## Code Generation \u0026 Types\n\nOpenAPI 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.\n\n## Contributing\n\nContributions are welcome! Please follow the guidelines in [`CONTRIBUTING.md`](./CONTRIBUTING.md).\n\n## Security Notes\n\n- Always override `FASTROOM_SECRET` outside local dev.\n- Rotate secrets and revoke outstanding refresh tokens upon compromise.\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.\n\n---\nAdditional deep-dive docs live in: [`backend/README.md`](./backend/README.md) and [`frontend/README.md`](./frontend/README.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohn0isaac%2Ffastroom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohn0isaac%2Ffastroom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohn0isaac%2Ffastroom/lists"}