System Architecture
How the whole system fits together -the pieces, how they talk, and the rules that keep money safe.
Last updated Thu Jul 16 2026 00:00:00 GMT+0000 (Coordinated Universal Time)
TL;DR -Social Live is one backend server plus a mobile app, an admin website, and a couple of helper sites, all running on a single machine behind a web server. The backend is the boss: it holds the database, moves all the money, and relays live video. Apple and Google -not us -are the final word on whether a purchase really happened.
Who this is for -Executive, Product & Business: read "The big picture" for a plain mental model. Engineering, Backend, DevOps: keep going for the topology diagram, the three request paths, and the design invariants.
The big picture
Think of Social Live as a live-streaming app with a built-in economy. People open the mobile app, watch and host live rooms, chat, send virtual gifts, and buy and cash out virtual currency. Everything they do is coordinated by a single backend -the central program that stores data, enforces the rules, and connects people to each other in real time.
Around that backend sit a few smaller pieces:
- The mobile app (built with Flutter) is what users actually touch.
- The admin portal is an internal website staff use to review reports, users, and cash-outs. It never touches the database directly -it always asks the backend.
- A couple of helper sites: a live-room simulator for testing, and this docs portal you're reading now.
Two ideas are worth holding onto before the technical detail:
- The backend is the single source of truth. The app on your phone never decides how many coins you have. It asks the backend, and the backend's answer wins.
- Real money lives outside our walls. When someone buys coins, the purchase is verified with Apple or Google before we hand anything over. They are the authority on payments; we check with them every time.
Production topology
Everything runs on a single server (a VPS -a rented virtual machine)
behind nginx, a web server that handles secure connections and routes
each incoming request to the right internal service. The whole set of
services is started and wired together by Docker Compose
(docker-compose.prod.yml), a tool that runs each piece in its own
container.
The diagram below shows who talks to whom. Boxes are running services; arrows are connections, labelled with the port number or protocol they use.
Rendering diagram…
Key points:
- One backend container serves REST (
/api/*), Socket.IO gateways, and mediasoup media. WebRTC media bypasses nginx: UDP ports 40000–40100 are published straight from the container (SFU_ANNOUNCED_IPtells clients the public address). - The admin portal never talks to PostgreSQL. It proxies everything
through the backend's
/api/admin/*endpoints with an admin token. - External money truth lives outside. Apple and Google are the source of truth for purchases; the backend verifies against their APIs before any coins move, and they push refund notifications back in.
The three request paths
The app and backend talk over three separate channels, each suited to a different job. In plain terms: one for ordinary requests (like loading your profile), one for live real-time updates (like a gift animation appearing), and one for the actual audio and video of a live stream.
1. REST (request/response)
The everyday path: the app asks a question, the backend answers. Used for all the normal stuff -logging in, loading profiles, checking your wallet, browsing rooms.
Flutter ApiClient → nginx → NestJS controller → service → Prisma → PostgreSQL
All CRUD, auth, wallet, and discovery traffic. JSON over HTTPS with a JWT
bearer token. A global ValidationPipe (whitelist + forbid-non-whitelisted)
rejects unknown fields at the boundary.
2. Realtime (Socket.IO)
A always-on connection that lets the backend push updates the instant they happen, without the app having to keep asking. Socket.IO is the library that keeps this live channel open. Long-lived WebSocket per app session. Gateways:
- Live gateway -room join/leave, viewer counts, stage/guest flow, gift broadcast events, PK battle updates.
- Chat gateway -message delivery, typing indicators, read receipts.
See Realtime for event catalogs.
3. Media (WebRTC + mediasoup)
The heavy path: the actual live audio and video. WebRTC is the browser/phone technology for real-time media, and mediasoup is the media server on our side that relays one broadcaster's stream out to many viewers.
Offer/answer and transport negotiation ride over Socket.IO signaling; actual audio/video flows peer-to-SFU over UDP. See Media & SFU.
Design invariants worth knowing
These are the non-negotiable rules the system is built around. If you remember nothing else technical, remember these -most bugs that touch money come from breaking one of them.
- Server is the money authority. Clients never decide balances; every
coin/diamond movement is a
LedgerTransactionrow created inside a Prisma$transactionwith an idempotency key. - Idempotency everywhere money moves. "Idempotent" means doing the same operation twice has the same effect as doing it once. Gift sends, coin purchases, and refunds all carry unique keys so retries and replays can never double-apply.
- Lazy settlement. Pending diamonds mature into withdrawable balance on read (no cron), always inside a transaction.
- Dev-shaped fallbacks. Several client repositories fall back to local fixture data when the API is unreachable, keeping the app demoable offline. Production debugging should always check the backend logs, not just what the app displays.
Related pages
- Backend Module Map -every backend module and what it owns.
- Data Model -the database schema and the money-critical tables.
- Realtime (Socket.IO) -the live event channel.
- Media & SFU -how live audio/video flows.
- Push Notifications -the FCM/APNs delivery rail.
- The economy -coins, diamonds, and the money rules.