Recall — Private
Coaching Platform
Edgewood High School Esports · Built independently
A fully self-hosted coaching platform built for a competitive Overwatch team. Six integrated modules — VOD library with HLS adaptive streaming, async strategy playbook, interactive slide-deck lessons, real-time collaborative whiteboard, competitive draft helper, and a central admin panel — all locked behind Google SSO with role-based access. No public routes. No third-party video hosting.
Overview
Built around
three constraints.
Private by Design
Every route requires an authenticated session. Google OAuth is the only entry point —
only @edgewoodhs.org addresses and individually whitelisted emails can
log in. New accounts land on a pending screen until the coach approves them. There
is no public-facing content anywhere on the platform.
Async-First Coaching
The coach prepares content once — VODs, playbook entries, lessons — and players consume it on their own schedule. Review tracking, unread badges, and comment threads keep the feedback loop intact without requiring everyone to be online at the same time.
Self-Hosted Infrastructure
Video files are stored in MinIO (S3-compatible object storage) and transcoded locally via FFmpeg into multi-quality HLS. No footage leaves the server. The entire platform — API, worker, web, database, storage — runs in Docker on private hardware.
Platform Modules
Six tools,
one platform.
Authentication & Roles
Google OAuth via openid-client. Sessions are issued as httpOnly
JWT cookies — 8-hour active tokens, 30-day refresh. Two roles: Coach (full
access) and Player (read-only consumer). The coach account is hardcoded;
players are approved individually through the admin panel.
Video-on-Demand
Recordings are organized in a collapsible Match → Map → POV hierarchy. Videos are uploaded through the admin panel, transcoded to HLS via a BullMQ background job, and served via adaptive streaming with HLS.js. The coach can lock individual videos to specific players, add timestamp bookmarks that appear as chapter markers, and toggle per-video visibility.
Strategy Distribution
Async strategy entries the coach publishes for players to review on their own time. Each entry supports text, images, and embedded video clips. Players can mark entries reviewed, post comments, and reply to coach feedback. Unread badges surface new replies. The coach tracks review completion per player and can draft entries before publishing.
Interactive Slide Decks
Structured learning modules built as fullscreen slide presentations. Eight slide
types: Title, Content (bullets + highlight box), Two-column, Three-column, Video
(YouTube / Google Drive / internal VOD), Activity, Takeaways, Stats. A
[[word]] syntax renders inline orange highlights throughout.
Lessons can be locked to specific players and toggled between draft and published.
Real-Time Collaborative Canvas
A live strategy drawing tool synced in real time via WebSocket — multiple users see the same board state simultaneously. The coach places and labels hero tokens, draws with an adjustable pen tool, and drops payload markers on a map background or plain canvas. Boards support named snapshots, a multi-frame timeline for building positioning sequences, and export to MP4 or GIF.
Competitive Draft Enforcement
Enforces Overwatch competitive ban rules across a multi-game series. The coach defines reusable Week Rotations (ordered game modes), then steps through map selection → Ban 1 → Ban 2 per game. Back-to-back ban enforcement grays out heroes banned in adjacent games. Sessions export as a printable PDF or a full JSON audit log with teams, maps, bans, roles, and timestamps.
Infrastructure
What runs
under the hood.
FFmpeg + BullMQ Pipeline
Uploaded video files are queued in BullMQ (backed by Redis) and processed by a
separate worker container. FFmpeg transcodes each file into a multi-quality HLS
stream with a .m3u8 manifest. The original file and all HLS segments
are stored in MinIO. The VOD entry is marked ready once transcoding completes.
Real-Time Sync
The whiteboard uses @fastify/websocket to broadcast canvas state
changes to all connected clients in real time. Hero token positions, pen strokes,
and timeline scrubs are synced across sessions without polling — each event is
emitted over the persistent WebSocket connection and applied immediately on all
connected clients.
JWT Cookie Auth
After Google OAuth completes, the server issues a signed JWT stored in an httpOnly cookie — inaccessible to JavaScript. Short-lived access tokens (8hr) are paired with long-lived refresh tokens (30 days). Role and identity claims are embedded in the token payload and verified on every request before any handler runs.
MinIO Object Storage
All binary assets — raw video uploads, HLS segments, map images, hero icons — are stored in MinIO, an S3-compatible self-hosted object store. Presigned URLs are generated per-request for secure, time-limited access. Nothing is served from the filesystem directly; all asset delivery goes through the MinIO API.
Stack
Built on
modern primitives.
Fastify
API server. Handles all routes, JWT verification, Google OAuth callback, file upload via multipart, and WebSocket connections for the real-time whiteboard.
Astro + Tailwind
Frontend. Server-rendered pages with Astro's island architecture. Tailwind for styling. Sessions are validated server-side on each page request before any HTML is returned.
Prisma + PostgreSQL
Database layer. Prisma ORM manages the schema and provides type-safe queries. PostgreSQL stores all structured data: users, roles, matches, entries, lessons, boards, drafts.
BullMQ + Redis
Background job queue for video transcoding. Upload requests are enqueued immediately; a dedicated worker container processes them asynchronously so the API stays responsive.
FFmpeg + HLS.js
FFmpeg runs in the worker container to transcode uploads into adaptive HLS streams. HLS.js handles playback in the browser, automatically selecting quality based on available bandwidth.
MinIO
S3-compatible self-hosted object storage for all binary assets. Videos, HLS segments, map images, and hero icons are stored and retrieved via presigned URLs — no direct filesystem exposure.
Google OAuth
The only login path. openid-client handles the OAuth 2.0 / OIDC flow. Domain-restricted to @edgewoodhs.org plus a coach-managed whitelist for external accounts.
Docker
The full platform — API, worker, web, PostgreSQL, Redis, MinIO — runs as a Docker Compose stack on private hardware. No cloud dependencies; the entire system is self-contained.
WebSocket
Persistent connections via @fastify/websocket power the real-time whiteboard. Canvas events — token moves, strokes, timeline scrubs — are broadcast to all connected clients instantly.