TASK 5 items 1-3: reusable stream, health banner, docs refresh

- Reusable stream: GetOrCreateReusableStreamAsync, cached via LayoutStore, bound at broadcast insert
- Health monitoring: GetStreamHealthAsync polls liveStreams.status, report-by-exception banner
- Go-live order: ensure stream → create broadcast → then start pump (URL must exist first)
- Full broadcast form scoped (TASK 5 items 6-7) in TASKS.md + ai.md
- TASK 23 trimmed to technical scope, TASK 26 added (marcom/launch kit)
- Confidential files: MONETIZATION.md + MARCOM.md (gitignored, not committed)
- .gitignore updated for confidential business files
- HANDOFF.md updated with session state and next steps
This commit is contained in:
2026-08-16 17:48:37 -07:00
parent 92f1471ab4
commit 0fac1e6a5a
16 changed files with 810 additions and 140 deletions
+37 -45
View File
@@ -562,13 +562,15 @@ the validator → persisted), compositor bar overlay (top/bottom + above-flash),
**Goal:** Create/bind broadcasts, monitor YouTube-side stream health — the v3 way.
### Status: ⏳ Not started — runs AFTER the TASK 24 polish batch (creator's pick, 2026-08-15); `_currentBroadcastId` is already stashed from TASK 4 for its bind/transition work
### Status: ⏳ In progress — items 1–3 SHIPPED (reusable stream 2026-08-16; report-by-exception health 2026-08-16); items 4–7 still open (each its own branch/PR)
1. ☐ Broadcast creation — title/description/privacy/scheduledStartTime via API, with the v3 flags above
2. ☐ Reusable stream — create once, cache + reuse; bind to broadcast
3. ☐ Health monitoring — poll `liveStreams.list` `healthStatus` + `configurationIssues[]`, surface banner only on warning/error
1. ☑ **Broadcast creation** — title/description/privacy/scheduledStartTime via API, with the v3 flags above (SHIPPED: `CreateBroadcast` sends `enableAutoStart/Stop`, `enableMonitorStream=false`, `latencyPreference=low`, `selfDeclaredMadeForKids=false`)
2. ☑ **Reusable stream** — create once, cache + reuse; bind to broadcast (SHIPPED: `GetOrCreateReusableStreamAsync` lists-then-inserts the `variable`/`isReusable` stream, cached via `LayoutStore` Settings, bound at broadcast insert via `boundStreamId`; `_rtmpUrlProvider` yields the ingest URL so go-live actually encodes + pushes)
3. ☑ **Health monitoring** — poll `liveStreams.list` `healthStatus` + `configurationIssues[]`, surface banner only on warning/error (SHIPPED: `GetStreamHealthAsync(streamId)` 30s while live; pure `StreamHealthReporter.BannerFor` = report-by-exception; banner strip under the top bar, amber warning / dark-red error, via `HealthIssueBanner`/`HealthIssueBackground`; poll failures log-only; ONE integration test `GetStreamHealthAsync_Report_By_Exception_Banner_Only_On_Warning_Or_Error`)
4. ☐ Live chat — poll `liveChat/messages`, render in right panel, support Super Chat + membership badges
5. ☐ Error handling — the YouTube error codes: `errorStreamInactive`, `invalidTransition`, `redundantTransition`, `liveStreamDeletionNotAllowed`, `liveStreamModificationNotAllowed`, `liveBroadcastBindingNotAllowed`
6. ☐ **Visibility picker** — remove temporary "always Private" enforcement (shipped as test-only; now unlocked for v1). User picks Private/Unlisted/Public from the go-live dialog. Trivial: remove the hardcoded override in `YouTubeStreamService.CreateBroadcast` (currently `privacyStatus = "private"` regardless of dialog selection)
7. ☐ **Full broadcast form** — expose all YouTube API-supported fields in the go-live dialog. Core tab: title, description, visibility, made-for-kids, schedule (start + optional end). Advanced tab (expandable, sane defaults): latency (Normal/Low/Ultra-Low), DVR, embed, record-from-start, projection (rectangular/360°), closed captions, auto-start, auto-stop, monitor stream, region restrictions. Monetization via `liveBroadcasts.update` (insert-only on that resource) — separate step after broadcast creation. Remove unsupported `categoryId` (not a `liveBroadcast` field, silently ignored)
### Design decisions (v3)
@@ -587,51 +589,24 @@ the validator → persisted), compositor bar overlay (top/bottom + above-flash),
3. **Health monitoring** — poll `liveStreams.list` `healthStatus` + `configurationIssues[]`, surface banner only on warning/error
4. **Live chat** — poll `liveChat/messages`, render in right panel, support Super Chat + membership badges
5. **Error handling** — the YouTube error codes: `errorStreamInactive`, `invalidTransition`, `redundantTransition`, `liveStreamDeletionNotAllowed`, `liveStreamModificationNotAllowed`, `liveBroadcastBindingNotAllowed`
6. **Visibility picker** — Private/Unlisted/Public from the go-live dialog
7. **Full broadcast form** — Core + Advanced tabs with all API-supported fields
---
## TASK 23 — Monetization: subscription billing + in-app unlock + support (2026-08-14, scoped)
## TASK 23 — Monetization: subscription billing + in-app unlock + support
**Goal:** turn the settled monetization policy (see `ai.md` → Monetization) into a paying product line:
annual subscription billing, an in-app unlock seam, and the in-app bug-report → git-issues support loop.
**Goal:** annual subscription billing, in-app unlock seam, and in-app bug-report → git-issues support loop.
**Decisions already locked (2026-08-14, creator):** one paid line = **annual subscription** (early
access **$49.99/yr** → **$99/yr list at GA**; grandfather-while-subscribed, lapse → list on renewal;
no escalation matrix). Free tier unchanged (branding flash + no Alerts; the flash is the free tier's
billboard — distribution, not compromise). Billing **not locked to itch.io** (hunted fact: itch.io has
no native subscription billing); candidates **Gumroad** (native affiliates = tiebreaker) and **Lemon
Squeezy**. Support = in-app bug-report → git issues; "when I get around to it" cadence + emergency
patches. Unlock outcome: flash removal flips `BrandFlashEnabled` off + **Alerts** on.
**Business details (pricing, billing research, revenue projections) in `MONETIZATION.md` (gitignored).**
### Status: 🔶 Scoped — nothing built; this entry records the plan + decisions
### Status: 🔶 Scoped — nothing built
1. ☐ **Billing provider decision** — Gumroad vs Lemon Squeezy (annual subs + license-key verification
APIs; Gumroad's native affiliate program is the tiebreaker if the TASK 23 affiliate line-item matters)
2. ☐ **Unlock mechanism** — license-key entry + online/offline verification + persisted entitlement
(extends `LayoutStore`, schema bump) + renewal/lapse handling (**lapse → branding flash returns** —
the flash is the enforcement and the billboard)
3. ☐ **In-app bug-report → git issues** — a built-in report control that files an issue (title/body/
log attachment) into the creator's git repo; the support loop, per the settled support model
4. ☐ **"Unlock Premium" seam** — the About hub's greyed button (TASK 21; `PremiumUrl` is the tabled
billing URL) lights up and routes to the billing page / unlock dialog
5. ☐ **Alerts gating** — the Super Chat pop-ins (TASK 3 item 18 / minimal source set item 7) are the
one paid feature; subscription state gates them
6. **Line-item pointers (their own big tasks — do NOT start here):**
- ☐ **Early-access strategy** — the 90-day funnel (founder window $49.99 → GA $99), waitlist,
testimonials/QA, clips → Shorts. Separate planning effort.
- ☐ **Affiliate & ads (phase 2)** — own-channel gear affiliates from day one (organic), a
ytLlive referral program gated behind GA + happy users, YPP as the channel's ad revenue, paid
ads deferred.
- ☐ **Channel revival (the prequel to both)** — **resume streaming**: pair-programming dev
streams via **OBS** (ytLlive can't go live yet — private-only + `_rtmpUrlProvider` null) +
**The Division 2** gaming streams under the **"gramps/GOAT"** persona (67, gaming since 1981).
3D-printing content retired (printer hard down, novelty gone). **Dogfood switch** — once TASK 5 +
go-live capability land, stream *with* ytLlive; Division 2 (loud game + voice) is the demo for the
ducking/voice-filter story. The flash billboard + the grandfather promise are the monetization
hooks this line-item feeds.
**Out of scope (TASK 23):** the early-access strategy itself, the affiliate program, channel content
planning — those are separate line-item tasks. TASK 23 owns billing + unlock + support + gating only.
1. ☐ **Billing provider decision** — Gumroad vs Lemon Squeezy (see MONETIZATION.md for comparison)
2. ☐ **Unlock mechanism** — license-key entry + online/offline verification + persisted entitlement (extends `LayoutStore`, schema bump) + renewal/lapse handling
3. ☐ **In-app bug-report → git issues** — built-in report control; good error codes first, optional log attachment with transparency about what's being sent
4. ☐ **"Unlock Premium" seam** — the About hub's greyed button (`PremiumUrl`) lights up and routes to billing/unlock
5. ☐ **Alerts gating** — Super Chat pop-ins gated behind subscription state
---
@@ -791,9 +766,26 @@ No changes to `MusicPlayer`, the 0.20 cap, the ducker, or the meter zones. Build
---
## TASK 26 — Social media launch kit
**Goal:** marcom/social media assets and strategy for v1 launch.
**Business details (positioning, messaging, platform strategy, launch assets) in `MARCOM.md` (gitignored).**
### Status: 🔶 Scoped — nothing built; queued after all v1 features ship
1. ☐ Product positioning & messaging (one-liner, elevator pitch, competitive positioning)
2. ☐ Social media swipe files (pre-written posts for supporters)
3. ☐ Launch day assets (demo video, screenshots, GIFs, social graphics, press kit)
4. ☐ Platform strategy (YouTube, Reddit, indie dev communities, Product Hunt)
5. ☐ Founder story (67-year-old dev building his own streaming app)
6. ☐ Email announcement templates
7. ☐ "Build in public" livestream angle (stream the coding of ytLlive with ytLlive)
---
## Backlog (future versions)
1. v0.2 — Recording to local file (recordings carry the branding flash — see TASK 3 / `ai.md` Monetization)
2. v0.3 — Stream scheduling
3. v0.4 — Multi-destination restreaming
4. v0.5 — Stream clipping
2. v0.4 — Multi-destination restreaming (if needed; casual streamers may outgrow ytLlive first — "congrats, you're ready for OBS")
3. v0.5 — Stream clipping