Overview
Speechwave lets a speaker’s audience react to a talk in real time, with emojis that show up right on the slides. Under the hood, that experience comes from three actors talking to a Phoenix server.
The attendee opens a talk’s URL on their phone and gets a plain web page powered by Phoenix LiveView. The server takes each tap, checks it against a rate limit, stores it if a session is recording, and broadcasts it to everyone listening. The speaker runs a Chrome extension on their laptop that listens for those broadcasts and draws the emoji on top of Google Slides.
Two separate WebSocket connections carry that traffic, and it’s worth knowing them apart early, because later chapters refer back to this table constantly.
| Connection | Path | Protocol | Used by |
|---|---|---|---|
| LiveView socket | /live | Phoenix LiveView | The attendee's browser |
| Channel socket | /socket | Phoenix Channel | The Chrome extension |
The full chapter on this is WebSockets, but the short version: a single server-side broadcast reaches both kinds of listener without either side knowing the other exists.
Project structure
Here’s the shape of the codebase, trimmed to the parts these chapters actually walk through.
lib/speechwave/ core domain logic, no web concerns
application.ex supervision tree, see Supervision tree
talks.ex talks and talk sessions
reactions.ex emoji reactions and slide aggregation
accounts.ex users, tokens, identities
plans.ex plan tiers and limits
rate_limiter.ex per-connection cooldown
auth_throttle.ex magic-link send throttling
db_backup.ex scheduled snapshot uploads
lib/speechwave_web/
live/
talk_live.ex the attendee's page
dashboard_live.ex the speaker's talk list
session_analytics_live.ex post-talk engagement review
channels/
user_socket.ex the /socket entry point
reaction_channel.ex join checks, session and slide messages
endpoint.ex both socket mounts live here
router.ex routes and live_session scopes
chrome-extension/ separate repo, see Chrome extension
Each piece gets its own chapter. Start with talks.ex and reactions.ex in Data model if you want to see how the pieces are actually stored.