One presenter.
A thousand voices.
One reading.
- Stack
- Next.js 16 · Node 20 · HeliosDB 7.6.1
- Integrations
- 8 platforms + QR
- Tables
- 38 bv_*
- Tests
- 23 passing · CI on PR
- Live at
- bigvoice.foor.tech
BigVoice is a real-time asymmetric broadcast tool. One presenter speaks or streams; thousands of people reply across YouTube Live, Twitch, Kick, Discord, Slack, Facebook Live, Zoom, Restream, and the back row of an auditorium. Everything they say collapses into a single intelligible feed with a three-question reading the presenter can actually answer. The feed is produced by an LLM pipeline that runs entirely on FOOR infrastructure through HeliosDB v7.6.1. This page shows, precisely, how.
The stack at a glance
Four tiers. Messages flow from left to right, from the audience's mouths to the presenter's reading, and a second (outbound) pass sends replies back into the platforms they came from.
Fig. 1 · Request flow. Arrows show the direction of data.
Ingestion ingestion
Ten different ingestion paths, one normalised schema. Every incoming message — whether it's typed into a browser, streamed on a pusher channel, POSTed by a webhook, or transcribed from the presenter's microphone — lands in bv_audience_responses with a source tag and the platform's native external_id for dedup.
| Source | Mechanism | Worker / route | Where it lives |
|---|---|---|---|
| native | HTTPS POST + rate limit | /api/sessions/[id]/respond | bv_audience_responses |
| youtube | Polling · 1u/call · quota-gated | worker/youtube-poller.ts | bv_youtube_session_links |
| twitch | Persistent IRC WebSocket (IRCv3 tags) | worker/twitch-poller.ts | bv_twitch_session_links |
| kick | Webhook + RSA-SHA256 sig verify | /api/webhooks/kick | bv_kick_session_links |
| restream | Persistent WebSocket aggregator | worker/restream-poller.ts | bv_restream_session_links |
| discord | Single Gateway WS w/ MESSAGE_CONTENT | worker/discord-bot.ts | bv_discord_session_links |
| slack | Events API webhook + HMAC verify | /api/webhooks/slack | bv_slack_session_links |
| Graph API polling · Page token | worker/fb-poller.ts | bv_fb_session_links | |
| zoom | Webhook + URL-validation handshake | /api/webhooks/zoom | bv_zoom_session_links |
| captions | MediaRecorder → WebM/Opus → STT | /api/sessions/[id]/captions/chunk | bv_caption_segments + bv_audience_responses |
On bot tokens. OAuth refresh tokens are encrypted at rest with AES-256-GCM before they touch the DB. HeliosDB v7.6.1 now owns the LLM provider key centrally — BigVoice itself ships without an OPENAI_API_KEY. The only third-party secrets BigVoice holds are per-platform OAuth tokens; the model calls all go through foor-heliosdb-v743.
Storage storage
HeliosDB 7.6.1 speaks PostgreSQL-compatible SQL over POST /api/v1/query. All 38 BigVoice tables live there, prefixed bv_ to avoid collisions with sibling FOOR apps sharing the instance.
bv_broadcast_sessionssession row + org_idbv_broadcast_slidesslide content + positionbv_audience_responsesevery message, every sourcebv_ai_summariesconsolidated per cyclebv_source_summariesper-platform per cyclebv_caption_segmentsSTT chunks + timestamps
bv_usersbcrypt · email-verify · password-resetbv_password_resetssingle-use reset tokensbv_orgsworkspace + planbv_org_membersrole: owner | admin | presenter | viewerbv_org_invitesbcrypt-hashed invite tokensbv_subscriptionsStripe customer + status
bv_question_upvotesUNIQUE(response_id, audience_id)(bv_audience_responses)status · upvotes · answered_at
bv_youtube_connectionsOAuth + channel identitybv_twitch_connectionschat:read + user:write:chatbv_kick_connectionsPKCE OAuthbv_restream_connectionsaggregator OAuthbv_discord_installsper-guild install recordbv_slack_workspacesper-team bot tokenbv_fb_connections + bv_fb_pagespage tokensbv_zoom_connectionswebinar OAuth
bv_jobsqueue: pending · running · done · failedbv_export_artifactsrendered HTML minutes + sha256bv_session_webhooksoutbound subscriptionsbv_webhook_deliveriesqueue + exponential backoffbv_llm_usageprompt + completion tokens per callbv_audit_eventsappend-only actor → action → targetbv_account_deletionsGDPR purge queue (30d grace)
bv_youtube_session_linksper-session broadcast attachbv_twitch_session_links…bv_kick_session_links + sub id…bv_restream_session_links…bv_discord_session_links + channel…bv_slack_session_links + channel…bv_fb_session_links + live_video_id…bv_zoom_session_links + webinar_id…bv_youtube_quota_log1 unit/read · 50/send · 9500 hard stop
On schema evolution. BigVoice originally used side-tables (bv_question_status, bv_session_orgs) to emulate columns that HeliosDB v7.2.0 couldn't ALTER onto existing tables. Those are retired in v7.4.3 — the columns live on the main rows. See docs/heliosdb-v743-migration.md for the cleanup trail.
Intelligence pipeline intelligence
The summariser runs every ~10 seconds while a session has unprocessed responses. It fans out per source (each platform gets its own agent-memory scope in HeliosDB), then runs a consolidated cross-source cycle. Upvoted questions are repeated into the context with a weighted tag so the LLM knows what the audience wants to promote.
Two structural choices worth calling out. Per-source fan-out means the dashboard can show "What YouTube asks" distinctly from "What the in-room audience asks" — essential for political events where platform sub-audiences disagree loudly. Upvote-weighted prompts mean a question with 47 upvotes lands in the LLM's context three times, not once — the summariser's "top 3 unanswered questions" actually reflects audience consensus instead of randomly-chosen novelty.
HeliosDB endpoint inventory
Every HeliosDB endpoint BigVoice touches, with the HeliosDB release it landed in and the BigVoice consumer. Tenant quotas are enforced via the X-HeliosDB-Tenant header on every AI-path call.
| Method | Path | Shipped | Consumer |
|---|---|---|---|
| POST | /api/v1/query | 7.2.0 | lib/helios.ts → heliosExecute · heliosQuery (all DML + DDL) |
| POST | /api/v1/chat/completions | 7.5.0 | lib/llm.ts → chatHelios (summariser · Ask AI) |
| POST | /api/v1/vectors/stores | 7.5.0 | session-init.ts on session create |
| POST | /api/v1/vectors/stores/{s}/texts | 7.5.0 | ai-summariser.ts cycle · bundles embed + persist |
| POST | /api/v1/vectors/stores/{s}/search/hybrid | 7.5.0 | reserved · future retrieval-augmented Ask AI |
| POST | /api/v1/agents/memory | 7.6.0 | lib/helios.ts → findOrCreateAgentSession |
| GET | /api/v1/agents/memory | 7.6.0 | …restart recovery · LIST + filter by metadata.scope |
| POST | /api/v1/agents/memory/{id}/messages/batch | 7.6.0 | summariser cycle · feeds rolling context |
| GET | /api/v1/agents/memory/{id}/messages | 7.6.0 | summariser cycle · reads window before chat |
| DELETE | /api/v1/agents/memory/{id} | 7.6.0 | session close (future) |
| POST | /api/v1/audio/transcribe | 7.6.0 | lib/stt.ts · base64 Whisper passthrough |
Fig. 2 · 11 endpoints across 3 HeliosDB releases · 100% of AI traffic is intra-cluster
Egress egress
Three surfaces send data out of BigVoice, with different reliability profiles.
Server-sent events
Summaries, slide changes, captions. Push-only. Presenter and audience dashboards listen with exponential backoff. SSE cleanup on request-abort via AbortController.
Outbound webhooks
Presenter-configured per session. Events: session.opened · closed · summary.generated · question.upvoted_threshold. HMAC-SHA256 over `${ts}.${body}`. Exponential backoff 1s → 6h → dead-letter.
Email + PDF minutes
Session-archive HTML rendered by worker job, sha256 hashed, stored on volume, emailed as signed download link. Printable to PDF; tamper-evident for council minutes.
The unique wedge the wedge
Slido doesn't ingest streaming chat.
Slido owns the 'ask the speaker' web-form category. BigVoice's wedge is that it unifies Slido-shape in-room questions with YouTube Live, Twitch, Kick, Discord, Slack, Facebook Live, Zoom, and Restream. One feed, one reading, one reply surface.
Restream shows raw chat. We summarise it.
Restream aggregates platform chats into one panel. At scale a presenter cannot read 8,000 messages. BigVoice runs the aggregated stream through HeliosDB's LLM, returns three ranked questions the speaker can actually address.
Civic gov-tech is built for archival, not live.
Council meetings ship PDFs of minutes two weeks later. BigVoice renders minutes in seconds with a cryptographic hash, and the audience can upvote mid-session. WCAG-compliant live captions feed the same AI summary for accessibility.
Meeting AI is meeting-shaped.
Otter transcribes and Read scores — both assume a Zoom call. BigVoice is broadcast-shaped: one speaker, N audiences, M platforms, and the speaker needs intelligence about the audience, not a transcript of themselves.
The worker process the worker
A single Node.js process runs all long-lived subscriptions, pollers and scheduled jobs. Keeping them co-located means shared connection pools, one PG LISTEN line, and a single restart boundary.
[worker] starting summarisation + youtube poller [yt-poller] starting ← 2–5s polling, quota-gated [tw-poller] starting ← persistent IRC WebSocket [rs-poller] starting ← persistent WS aggregator [dc-bot] starting ← single Discord Gateway [fb-poller] starting ← 5s Graph polling [wh-sender] starting ← 2s outbound delivery loop [jobs] starting · export dir = /data/exports
Every subprocess exits its loop on SIGTERM cleanly. If an API key is absent — Discord, Facebook — the loop logs a disabled line at boot and returns, so partial configs don't crash the worker.
HeliosDB ↔ BigVoice timeline
Co-evolution. Twelve bugs filed while building BigVoice on HeliosDB 7.2.0 drove five upstream releases. Eleven of twelve are fixed upstream; the one remaining item is a consistency semantic, not a defect.
- 2026-04-14 · BigVoice 1.0 · first deploy on HeliosDB 7.2.0
Phases A–D ship to bigvoice.foor.tech. 12 HeliosDB bugs filed in the process: ALTER ADD COLUMN, projection, CURRENT_TIMESTAMP, missing AI routes, and more. BigVoice runs with workarounds.
- 2026-04-17 · HeliosDB 7.4.3 · 5 bugs fixed
ALTER ADD COLUMN · SELECT projection · CURRENT_TIMESTAMP evaluation · ISO-8601 timestamp comparison · information_schema dedup. BigVoice cutover retires 2 side tables, drops ~120 lines of workaround code.
- 2026-04-20 · HeliosDB 7.5.0 · Tier 1 AI routes
/chat/completions · /vectors/stores with BM25 + cosine RRF hybrid search. BigVoice drops OPENAI_API_KEY and runs 100% of its LLM traffic through foor-heliosdb-v743.
- 2026-04-20 · HeliosDB 7.6.0 · Tier 2 + Tier 3 + 5 cosmetic fixes
Agent memory (9 endpoints) · documents · embeddings · audio/transcribe Whisper · SSE streaming · per-tenant quota buckets. Plus bugs #5 (INTERVAL) · #7 (CREATE TRIGGER) · #8 (RENAME populated tables) · #9 (SHOW TABLES) · #11 (current_schema). BigVoice process-local agent buffer retired; STT moved onto HeliosDB; X-HeliosDB-Tenant header lights up per-app quota.
- 2026-04-20 · HeliosDB 7.6.1 · 2 remaining actually-broken items fixed
#13 UPDATE on pre-ALTER rows now pads catalog width across all three UPDATE paths (indexed/scan/tracking) — pre-ALTER rows persist writes instead of silently no-op'ing. #14 version constants replaced with env!(CARGO_PKG_VERSION); /health, /status, /, SELECT VERSION(), SHOW SERVER_VERSION now track the binary. BigVoice deletes COALESCE(col, default) defensive reads across upvote + queue + public routes.