The project is a monorepo built using yarn workspaces and Lerna. It includes mainly 3 packages.
- React Native ( Expo ), to build Android & iOS & Web applications
- XState, handle logic inside state machines
- Dripsy, centralize style
- socket.io-client
- Jest + Testing Library + @xstate/test
- Adonis REST API
- Adonis, lucid/auth/session
- Japa + Sinon
- socket.io & socket.io-redis-adapter
- googleapis, Places/YouTube Data
- Redis instance
- PostgreSQL database
- Golang REST API, build above temporal
- Brainy (for creating state machines)
go test
+ testify- Temporal Go SDK
- Temporal Server
- PostgreSQL (used internally by Temporal Server)
We’re also end-to-end testing the application using Playwright.
Backend
When a user submits the configuration for a new MTV room, we start a Temporal workflow. The workflow waits for signals (play, pause, vote for a track, ...) which mutate its internal state. The workflow of an MTV room is a source of truth that can really be trusted: all signals sent to a workflow are processed sequentially, preventing concurrency issues.
See Temporal workflow for MTV rooms →
Frontend
A XState machine is used client-side to handle MTV rooms, from creation to playing state. The logic code is centralized, and only things defined in the machine can happen, preventing concurrency issues, such as the pause button being shown while the video does not play.
See machine orchestrating MTV room →
Backend
As for MTV rooms, when a user submits the configuration for a new MPE room, we start a Temporal workflow that waits for signals (change track up or down, remove track, add track...). The workflow mutates its own state depending on the operation it receives. Temporal allows to avoid a lot of edge cases: if two users change the order of the same track at the same time, the last operation received fails.
See Temporal workflow for MPE rooms →
Frontend
Client-side, the main difference between MTV rooms and MPE rooms management is that several MPE rooms can live at the same time for a single user. We use a XState machine that orchestrates MPE rooms and that can handle an infinite number of them. When a user joins or creates an MPE room, we spawn a child machine for it. XState promotes decoupling independent logic blocks by making use of the Actor model. Each MPE room is then an actor represented by a state machine communicating with its direct parent.
See machine orchestrating MPE rooms →
Adonis and Temporal both handle business logic. All microservices communicate with each other when operations on an MTV or an MPE room are performed.
When a user wants to pause an MTV room, the following sequence of actions is executed:
A basic MTV room operation, such as an MTV_PAUSE operation, will go through all the microservices before pausing the client music player.
In TypeScript microservices, we parse inputs with Zod, that allows to statically type variables at build time and to validate them at runtime with the same code.