diff --git a/TechnicalOverview.md b/TechnicalOverview.md index 743e5cd5..d9aa99ba 100644 --- a/TechnicalOverview.md +++ b/TechnicalOverview.md @@ -126,6 +126,98 @@ Secrets management uses Doppler, and injects into every Docker build on the fly. ![image](https://user-images.githubusercontent.com/1036968/235396718-f4cb5929-01f2-4937-ab7c-d7695fb931b6.png) +## YouTube integration implementation plan + +### Objectives and success criteria + +- Deliver feature parity (or clear MVP subset) for streamers who broadcast on YouTube Live in addition to Twitch. +- Keep the existing Twitch stack stable by isolating changes behind a provider abstraction. +- Preserve latency-sensitive flows (game events → chat/output) with <5s added delay, accounting for YouTube chat polling intervals. +- Track adoption via number of linked YouTube channels, active live chats, and command success/error rates. + +### Scope and phased rollout + +1. **Foundation (P0)**: OAuth + channel linkage, data model readiness, secrets/infra wiring, basic health checks. +2. **Chat + stream lifecycle (P1)**: Bidirectional chat bridge (commands/responses), live/offline detection, moderation/error handling. +3. **Feature parity (P2)**: Dota-driven automations (predictions/polls, overlays, auto-messages), localization, moderator controls. +4. **Hardening & rollout (P3)**: Observability, rate-limit tuning, canary rollout to a small cohort, documentation and support. + +### Architecture approach + +- **Provider abstraction**: Introduce a `StreamingProvider` interface in `shared-utils` to unify auth tokens, chat send/receive, and stream status checks (e.g., `authenticate/refresh`, `getLiveState`, `subscribeToChat`, `sendMessage`, `disconnect`, `mapRoles`). Keep Twitch implementations intact and add a YouTube implementation that plugs into the same sockets used by `packages/twitch-chat`. +- **New packages/services**: + - `packages/youtube-chat`: Mirrors `twitch-chat` but uses YouTube LiveChat APIs for ingest and message dispatch; reuses shared command handlers where possible. + - `packages/youtube-events`: Mirrors `twitch-events` for stream lifecycle and channel updates (using `liveBroadcasts`, `videos`, `subscriptions` APIs). Emits the same internal events consumed by downstream services. +- **Sockets and API surface**: Extend existing socket events to include `provider` metadata so frontends and other services can route messages to the correct transport without duplicating handlers. Default provider to `twitch` when omitted and version new events if payload shapes change to keep existing consumers working. +- **Deployment**: Add Docker targets and compose entries mirroring Twitch services; gate startup on presence of Google credentials to avoid breaking existing environments. + +### Authentication and permissions + +- Create a Google Cloud project + OAuth client (web app) and store credentials via Doppler alongside Twitch secrets. +- Scopes: `https://www.googleapis.com/auth/youtube.readonly` (live metadata), `https://www.googleapis.com/auth/youtube` for chat read/write (Google currently flags `.../youtube.force-ssl` as deprecated), `https://www.googleapis.com/auth/youtube.channel-memberships.creator` if membership-specific features are needed. Re-evaluate if a narrower live-stream scope (e.g., `youtube.liveBroadcast`) is sufficient before requesting broader access. +- Flow: front-end initiates Google OAuth; Supabase `accounts` table already supports generic providers—store `provider: 'youtube'` with `refresh_token`, `access_token`, `expires_at`, `scope`, and channel metadata to disambiguate from any other Google-linked features. +- Token refresh: implement Google OAuth refresh logic in `shared-utils` alongside existing Twitch token helpers; add retry/backoff and revocation detection. + +### Data model and configuration + +- Users table already has a `youtube` field (channel id/url). Enforce population during linkage; validate channel ownership by comparing OAuth channel id. +- Add configuration fields (Supabase) for YouTube-specific toggles: chat language fallback, poll enablement, command prefixes, rate-limit ceilings. +- Add tables/rows for live chat state if needed (e.g., `youtube_live_chats` storing `liveChatId`, `nextPageToken`, `pollIntervalMs`, last seen message timestamp) to avoid duplicate processing. + +### Chat ingestion and command handling (P1) + +- Use `liveBroadcasts.list` to find the active broadcast and obtain `liveChatId`. +- Poll `liveChatMessages.list` respecting `pollingIntervalMillis` and page tokens; store `messageId`/timestamp with a short TTL (24–48h) to prevent replays without unbounded growth. +- Normalize inbound messages into the existing command bus (user id, channel id, roles, message text). Map YouTube roles to Twitch equivalents (owner → broadcaster, moderator → moderator, member → sub, none → viewer). +- Outbound messages: use `liveChatMessages.insert`; centralize rate limiting against YouTube Data API quota units (default 10,000/day). As of Jan 2026 docs: `liveChatMessages.list` ~5 units, `liveChatMessages.insert` ~50 units, `liveBroadcasts.list` ~1 unit per call—update if Google revises quotas. Fall back to compact messaging when near limits. +- Moderation: handle errors for slow mode, members-only, or chat disabled; surface disable reasons through the same cache/telemetry used in Twitch (`disable_notifications` equivalents). + +### Stream lifecycle and events (P1/P2) + +- Detect live/offline via `liveBroadcasts.list` and `videos.list` status; emit internal `stream.online`/`stream.offline` events matching the payload shape from `twitch-events`. +- Track title/category changes via `videos.update` or polling; propagate to overlays and chat announcements. +- Implement health checks (cron) similar to Twitch subscription health: verify token validity, channel linkage, and active liveChatId presence; auto-heal by re-fetching live broadcast. + +### Feature parity mapping (P2) + +- **Predictions/bets**: Verify whether YouTube exposes poll creation via `liveChatMessages.insert` variants; if unsupported or unreliable, fall back to a manual-prompt flow (announce options in chat and parse reactions/keywords under a feature flag) or disable the feature for YouTube. Keep Supabase `advanced_bets` logic but flag provider to avoid mixing metrics. +- **Auto chat commands**: Reuse existing handlers (MMR, notable players, items) with provider-aware transport. +- **Overlays and sockets**: Ensure socket payloads include provider/channel identifiers so overlays work cross-platform without duplicating UI logic. +- **Localization**: Reuse existing i18n files; add YouTube-specific system messages (errors, rate-limit notices). + +### Observability, reliability, and limits (P3) + +- Metrics: poll latency, messages processed/sent, error codes per API, rate-limit headroom, per-channel disable events. +- Logging: standardize Winston context fields (`provider`, `channelId`, `liveChatId`, `error.code`). +- Alerts: trigger when polling falls behind (timestamp gap), repeated auth failures, or message send failures > threshold. +- Quotas: track Google API quotas; add circuit breakers to pause non-essential features when nearing limits. + +### Rollout plan + +- Internal dogfood on a test channel; record flows and log volumes. +- Beta allowlist (Supabase flag) to enable YouTube per user without affecting Twitch users. +- Gradually expand cohort; monitor metrics and support channels. +- Documentation: add setup guide (creating Google credentials, linking account), update README and dashboard onboarding once stable. + +### Risks and mitigations + +- **Higher latency from polling**: keep Dota-triggered messages concise, allow configurable batching, and preemptively refresh `liveChatId` on reconnect. +- **Quota exhaustion**: cache broadcast/channel metadata aggressively; avoid redundant `liveChatMessages.insert` retries. +- **Token revocation**: health checks plus UI banner; disable features gracefully and request re-auth. +- **Feature gaps vs. Twitch**: define MVP (chat commands + stream status) and stage advanced features after stability metrics are green. + +## Kick integration implementation plan + +- **Objectives & scope**: Deliver Kick chat/stream parity for core Twitch-dependent features: bets open/close, online/offline detection, automatic username change detection, poll/bets overlay, W/L tracking beyond 12h without manual `!resetwl`, plus the existing chat commands. +- **Architecture**: Reuse the `StreamingProvider` contract and provider-aware sockets (default to Twitch when missing) to plug in a Kick transport; add `packages/kick-chat` and `packages/kick-events` mirrors if separation is needed. +- **Authentication**: Follow the same provider auth pattern: front-end starts Kick OAuth, exchange auth code for access/refresh, request chat read/write + profile scopes (to confirm against Kick docs), and persist `provider: 'kick'` with channel metadata in Supabase `accounts`. Refresh at 50–70% of token lifetime, detect `invalid_grant`/revocation, surface re-auth UI, and target live-status endpoints (e.g., `https://kick.com/api/v2/channels/{channel}` placeholder—**must be replaced with confirmed endpoints before implementation**) plus chat send/receive APIs. +- **Data model/config**: Store Kick channel id/username and feature toggles (bets/polls enabled, overlay hooks, W/L auto-reset) and any chat state needed to dedupe messages (with TTL). +- **Chat + commands**: Map existing chat command handlers to Kick transport; normalize roles (channel owner → broadcaster, moderator → moderator, subscriber/supporter → subscriber) and tune rate limits to Kick chat caps (**BLOCKER before rollout: replace provisional ~10 msgs/30s with documented limits after reviewing Kick API rate guidance**). +- **Bets/Polls**: If Kick exposes programmatic bet/poll APIs, call them; otherwise, use a feature-flagged chat-driven fallback: announce options as numbered keywords (`1`/`2`), accept votes for a fixed window (e.g., 60–120s), dedupe by user to one vote (store per-voter choice in memory/Redis with TTL), tally at window close, and emit results to chat/overlay only when data is present (disable overlay triggers when unsupported). +- **Online/offline + username changes**: Poll/subscribe to Kick stream status and profile updates; emit `stream.online/offline` equivalents and detect display-name changes to refresh caches and overlays. +- **W/L tracking**: Bound W/L windows using Kick live sessions; auto-reset at session start to remove manual `!resetwl` and allow accurate last-session stats. +- **Observability & rollout**: Add provider-tagged metrics/logs for Kick transport/auth/command success; health checks for channel linkage and live-status detection; gate rollout behind a Kick beta allowlist before broad enablement. + ## Technical Overview ### Internal microservices