LiveChat¶
A real-time chat application with WebSocket messaging, Redis Pub/Sub for cross-instance broadcast, and persistent message history in PostgreSQL. Dark-themed Discord/Slack-inspired UI.
Source: git@gitlab.com:appmecca-sample-apps/livechat.git
What This App Demonstrates¶
- WebSocket through the platform router -- real-time messaging via a single WebSocket connection per client
- Redis Pub/Sub -- cross-instance message broadcast, enabling horizontal scaling
- Multi-container build -- FastAPI backend and React frontend as separate services
- Database + Cache together -- PostgreSQL for messages and users, Redis for real-time event distribution
- SPA runtime config --
type: spawith${service:api}for API URL injection - JWT auth via query param -- WebSocket connections authenticated via
?token=query parameter
appmecca.yaml¶
containers:
- name: api
dockerfile: backend/Dockerfile
context: backend/
- name: frontend
dockerfile: frontend/Dockerfile
context: frontend/
deploy:
- name: api
container: api
port: 8000
path: /api
path: /api
health_check:
path: /health
- name: frontend
container: frontend
type: spa
command: 'nginx -g "daemon off;"' # serves the built bundle from a container
spa_root: /usr/share/nginx/html
port: 80
health_check:
path: /health
environment:
PUBLIC_API_URL: "${service:api}"
PUBLIC_WS_URL: "${service:api}"
database:
enabled: true
redis:
enabled: true
There are four things to understand here:
1. WebSocket routing through the platform router¶
The API service exposes a WebSocket endpoint at /ws?token={jwt}. When deployed on AppMecca, the HTTPS router automatically handles the HTTP-to-WebSocket upgrade. No special configuration is needed -- any service with a port gets WebSocket support by default.
2. Redis Pub/Sub for horizontal scaling¶
When a chat message arrives, the API persists it to PostgreSQL and publishes it to a Redis Pub/Sub channel (chat:room:{id}). Every API instance subscribes to these channels and broadcasts messages to its locally connected WebSocket clients. This means you can run multiple API replicas and messages still reach all connected users.
User A ──WebSocket──▶ API Instance 1 ──publish──▶ Redis Pub/Sub
│
User B ──WebSocket──▶ API Instance 2 ◀──subscribe───────┘
The top-level cache.enabled: true flag provisions the managed Redis cache and injects the REDIS_URL environment variable.
3. SPA runtime config injection¶
The frontend uses type: spa with spa_root, which tells AppMecca to write a small __appmecca_config.js file at deploy time and mount it read-only at {spa_root}/__appmecca_config.js. Load it from your index.html before your bundle:
It sets window.__APPMECCA_CONFIG__. Only variables prefixed PUBLIC_, VITE_, NEXT_PUBLIC_ or REACT_APP_ are included — everything else is filtered out so secrets can never reach the browser. The React app reads PUBLIC_API_URL and PUBLIC_WS_URL from this config:
// In the frontend code
const apiUrl = window.__APPMECCA_CONFIG__?.PUBLIC_API_URL || import.meta.env.VITE_API_URL;
The ${service:api} template resolves to the API's public HTTPS URL (e.g., https://livechat-api.dev.yourdomain.io). The frontend JavaScript converts https:// to wss:// for WebSocket connections.
4. JWT in WebSocket query parameter¶
Browsers don't support custom headers for WebSocket connections, so the JWT token is passed as a query parameter: /ws?token={jwt}. The backend validates the token on connection and associates the WebSocket with a user.
Running locally¶
Open http://localhost:5173 in your browser. Register an account, then open a second browser tab or incognito window to register another user and chat in real time.
Deploying to AppMecca¶
mecca register git@gitlab.com:appmecca-sample-apps/livechat.git -e dev
mecca build trigger -e dev -g git@gitlab.com:appmecca-sample-apps/livechat.git
mecca app deploy -e dev livechat
After deployment:
- API:
https://livechat-api.dev.yourdomain.io - Frontend:
https://livechat-frontend.dev.yourdomain.io
The frontend's PUBLIC_API_URL is automatically set to the API's public URL via ${service:api}.