This document translates docs/overview/SPEC.md into interaction scenarios (SC-) and test cases (TC-). It does not invent behavior beyond those sources.
References: README.md, CONTEXT.md, AGENTS.md, docs/overview/SPEC.md, docs/overview/ROADMAP.md, docs/reference/UI_SPEC.md (hub) and docs/components/twitch-extension/UI_SPEC.md / docs/components/desktop/UI_SPEC.md / docs/components/wow-addon/UI_SPEC.md, docs/reference/WORKFLOWS.md, docs/overview/MVP_PRODUCT_SUMMARY.md, component ReadME.md files under docs/components/*/.
End-to-end narrative: WORKFLOWS.md · product digest: MVP_PRODUCT_SUMMARY.md.
Implementation scope (roadmap phases): Treat docs/overview/SPEC.md as the only normative contract for what to build. Scenarios in this file marked future / not MVP, placeholder, or open (e.g. SC-020 pause/resume, SC-022 retry-token speculation) must not be implemented — no speculative endpoints (retry tokens, pause APIs, etc.) unless/until docs/overview/SPEC.md adds them. Each roadmap step should follow the mandatory checklist the owner supplies (SPEC § references, TC ids, no endpoints outside SPEC).
docs/overview/SPEC.md and related docs. They are not bound to existing automated tests until those suites exist.dotnet test src/MimironsGoldOMatic.slnx — Unit project: MimironsGoldOMatic.Backend.UnitTests, --filter Category=Unit (no Docker). Integration project: src/Tests/MimironsGoldOMatic.Backend.IntegrationTests, --filter Category=Integration (Testcontainers / Docker). Full solution run executes both. Extension UI and WoW/Desktop flows remain Manual unless a harness is added; see Automated E2E Scenarios (MVP-6).docs/overview/SPEC.md requires real Twitch-issued Extension JWTs (Dev Rig and production). Tests must not rely on a long-term “mock JWT” bypass unless explicitly labeled as temporary harness and called out in test code.Overall status: Manual (target: Automated in CI/CD).
This section maps the intended full product pipe — Twitch chat message → Backend processing → WoW addon / Desktop behavior → Helix API outcome — to how it is verified today vs what automation would add. It does not change docs/overview/SPEC.md behavior. Roadmap alignment: docs/overview/ROADMAP.md MVP-6; matrix: docs/reference/IMPLEMENTATION_READINESS.md (MVP-6 verification status).
| Step | Flow segment | Manual verification (today) | Target automated check (CI/CD) | Prerequisites / notes |
|---|---|---|---|---|
| 1 | Twitch chat enrollment (!twgold) → Backend pool |
Execute SC-005 (live EventSub) or Dev Rig / operator sends chat; confirm pool via GET /api/pool/me or DB. Optional: POST /api/payouts/claim for Extension-shaped enrollment in dev. |
Integration tests already exercise Backend HTTP + persistence (not live Twitch). A future CI job could add signed EventSub fixture posts or keep relying on HTTP enrollment tests. | Running Backend + Postgres; Twitch credentials for Manual path. |
| 2 | Backend spin / verify-candidate / payout lifecycle |
Operator aligns clock with spin grid; Desktop submits [MGM_WHO] payload via POST /api/roulette/verify-candidate; observe Pending and Extension state. |
dotnet test Category=Integration (PostClaimRulesIntegrationTests, RouletteVerifyCandidateIntegrationTests, etc.). |
Docker for Testcontainers. |
| 3 | WoW addon UI / mail queue + WoWChatLog.txt tags + Desktop WinAPI |
SC-001, SC-003, SC-004: real WoW 3.3.5a, [MGM_WHO], [MGM_ACCEPT], [MGM_CONFIRM], inject /run, mail send. |
No automated test in repo (would require client harness or simulator). | Stable WoW + log path; streamer Desktop ApiKey. |
| 4 | Helix chat announcement (§11) after Sent |
After PATCH → Sent, confirm chat line (Russian copy per SPEC) or inspect logs. |
CI could mock Helix or use a test double; not implemented today. | Twitch app scopes + tokens for live check; Backend Twitch:* config. |
For details on the automation approach, see E2E Automation Plan.
docs/overview/ROADMAP.md MVP-6 Next steps and E2E Automation Progress.Related narrative: SC-001 (full end-to-end). Next steps for automation are listed under docs/overview/ROADMAP.md MVP-6 — Next steps.
Trigger: Viewer is a subscriber, sends !twgold Norinn in broadcast chat, and later roulette selects them as online-verified winner; they !twgold in WoW (whisper reply) to consent and receive mail.
Actor: Viewer (Twitch + WoW), Streamer (WoW + Desktop), System (Backend chat + spin/schedule)
Preconditions: Backend reachable; chat ingestion active; viewer subscribed; CharacterName unique in pool; pool has ≥1 participant; Extension authorized for status UI (MVP: Dev Rig posture); Desktop eventually online with correct ApiKey; WoW 3.3.5a running (foreground for MVP).
Flow:
[Viewer] → [Twitch Chat]: !twgold Norinn |
[ChatIngest] → [Backend]: enroll subscriber with unique name |
Pending payout yet (docs/overview/SPEC.md §5)currentSpinCycleId issued (docs/overview/SPEC.md §5.1)[WoWAddon] → WoW Client: run /who Norinn; parse 3.3.5a result → DEFAULT_CHAT_FRAME:AddMessage [MGM_WHO]{...json} → Logs\WoWChatLog.txt (docs/overview/SPEC.md §8) |
Desktop tails log → POST /api/roulette/verify-candidate (X-MGM-ApiKey) |
online: true, create payout Pending; else no winner this cycle (no re-draw); expose state for Extension when Pending exists (winner notification)!twgold (docs/overview/SPEC.md §11)/run NotifyWinnerWhisper("<payoutId>","Norinn") (docs/overview/SPEC.md §8–9) → [WoWAddon] sends winner notification whisper (/whisper Norinn … Russian text per §9; addon-only typing)!twgold (case-insensitive)[WoWAddon] → [WoW Chat Log]: print [MGM_ACCEPT:<uuid>] → Desktop tails WoWChatLog.txt |
Desktop → [Backend]: POST /api/payouts/{id}/confirm-acceptance |
GET /api/payouts/pending → streamer Sync/InjectPATCH /api/payouts/{id}/status { "status": "InProgress" }/run ReceiveGold("<chunked payload>") <255 chars per line (docs/overview/SPEC.md §8)ReceiveGold(dataString); queue MAIL_SHOW UX; streamer sends mail on MGM-armed path (1000g = 10000000 copper)MAIL_SEND_SUCCESS → print [MGM_CONFIRM:<uuid>] → Logs\WoWChatLog.txt; whisper winner Награда отправлена тебе на почту, проверяй ящик! (docs/overview/SPEC.md §9). Manual send without arm → no tag / no completion whisper.PATCH /api/payouts/{id}/status { "status": "Sent" } → remove winner from poolНаграда отправлена персонажу <Winner> на почту, проверяй ящик! (docs/overview/SPEC.md §11)Postconditions: Payout Sent; winner removed from participant pool; pool row may be re-added later via !twgold <CharacterName>; viewer sees status in Extension; winner received in-game completion whisper; stream chat may show §11 announcement.
Failure exits: enrollment rejected (not subscribed, duplicate character name in pool, cap, invalid name); offline at /who (no winner this cycle — no re-draw); missing WoW whisper !twgold consent; injection or mail failure; log never shows MGM_CONFIRM; API down at any HTTP step.
Trigger: Streamer starts Desktop and connects to Backend.
Actor: Streamer
Preconditions: Backend configured with expected X-MGM-ApiKey; Desktop stores same secret.
Flow:
Desktop → [Backend]: first privileged call e.g. GET /api/payouts/pending |
headers: X-MGM-ApiKey: <secret> |
[Backend] → Desktop: 200 OK + JSON list (may be empty) |
or error if key invalid |
Postconditions: Desktop can poll/patch payout APIs.
Failure exits: wrong/missing key → 403 forbidden_apikey (per docs/overview/SPEC.md §5 error model); network failure.
Trigger: Streamer launches Desktop with WoW already running (MVP: foreground WoW.exe).
Actor: Streamer
Preconditions: WoW.exe process present; Desktop has permission to use Win32 APIs.
Flow:
FindWindow, GetForegroundWindow, process name WoW.exe)/run ... or /who ... text path; SendInput if fallback selectedPostconditions: Desktop can inject chat commands reliably enough for MVP (docs/overview/SPEC.md §8).
Failure exits: WoW not running; wrong window focused; anti-cheat blocking PostMessage; injection timing/focus failure.
Trigger: Streamer completes Send Mail in UI after ReceiveGold populated fields (MGM-armed send path).
Actor: Streamer (in-game)
Preconditions: Mailbox open; addon queued payout; recipient accepted per product flow (!twgold already processed); gold available; send is armed for MGM (not a unrelated manual compose).
Flow:
SendMailNameEditBox, subject, MoneyInputFrame_SetCopper (3.3.5a)MAIL_SEND_SUCCESS (MGM-armed only): [WoWAddon] → [Chat / WoWChatLog]: [MGM_CONFIRM:<payoutGuid>] (required for automated Sent); [WoWAddon] → [Winner]: whisper Награда отправлена тебе на почту, проверяй ящик! (docs/overview/SPEC.md §9)PATCH → SentPostconditions: Backend Sent; audit log shows mail-send confirmation path; winner got completion whisper.
Failure exits: mailbox closed; insufficient gold; invalid recipient; MAIL_FAILED (no tag / no completion whisper); manual send without MGM arm (no tag); Desktop misses log rotation.
Trigger: A subscriber (badge on channel.chat.message) types !twgold Norinn in broadcast chat; Twitch POSTs an EventSub notification to the EBS.
Actor: Viewer, System (Twitch → EBS)
Preconditions: EventSub subscription channel.chat.message is enabled; callback URL reaches POST /api/twitch/eventsub; Twitch:EventSubSecret matches (or empty for local dev only); ConnectionStrings:PostgreSQL available.
Flow:
POST /api/twitch/eventsub with signed headers and JSON body (subscription.type = channel.chat.message, event contains message_id, chatter_user_id, message.text, badges).!twgold <CharacterName>; if not subscriber per badges → log / ignore; else dedupe by message_id, validate name, update pool (replace same TwitchUserId row per docs/overview/SPEC.md §5).Postconditions: Pool row exists for viewer; no Pending payout until a spin + verify-candidate path succeeds.
Failure exits: wrong signature → 401; malformed payload → ignored or minimal response; duplicate message_id → no-op; name taken by another user → silent reject (no pool change); active payout / lifetime cap → silent reject.
Trigger: Viewers enroll; Backend creates Pending winner payout; Desktop not running.
Actor: System / Viewer
Preconditions: Backend up; Desktop down or not polling.
Flow:
Pending payout exists on EBS (Extension may only poll for status — not required to create the payout).Postconditions: Payouts stay Pending until Desktop polls or hourly job may later Expired if >24h (docs/overview/SPEC.md §7).
Failure exits: streamer cannot inject until Desktop online; viewer stuck waiting past UX expectations (product issue, not separate error code in spec).
Trigger: Streamer clicks Sync/Inject or /who automation runs without WoW.
Actor: Streamer
Preconditions: Desktop authenticated; no WoW.exe / no target window.
Flow:
PostMessagePostconditions: No injection; payout remains Pending (Desktop must not PATCH to InProgress until WoW is detected — docs/overview/SPEC.md §3).
Failure exits: user never launches WoW; wrong client build.
Resolution (product): Desktop must not transition
Pending→InProgressuntil the WoW client target is found (docs/overview/SPEC.md§3).
Trigger: Viewer enrolls with a name that is not a real character on the streamer’s realm/faction context (format-valid).
Actor: Viewer
Preconditions: Backend validates format only (shared CharacterNameRules). MVP does not call external realm/Armory APIs.
Flow:
!twgold <Name> (primary path) or [TwitchExtension] → [Backend]: POST /api/payouts/claim (optional; requires Mgm:DevSkipSubscriberCheck for local Dev Rig while Helix subscriber check on claim is unimplemented — see docs/overview/SPEC.md §5).docs/overview/SPEC.md §4, §5)./who <Name> in-game is the online / presence check (docs/overview/SPEC.md glossary). A non-existent or offline name yields no Pending payout that cycle (no re-draw). If a payout still reaches mail UX incorrectly, streamer may use manual Failed.Postconditions: Possible enrollment stored; payout delivery may hit Failed in Desktop or streamer correction.
Failure exits: mail cannot be delivered to non-existent toon; addon/mail API errors.
Resolution (product): No separate “realm database” lookup in MVP. In-game
/whois the normative check when a candidate winner is evaluated; enrollment remains format + pool rules only.
Trigger: Same viewer repeats enroll submit or rapid duplicate HTTP calls before rate limit window elapses.
Actor: Viewer / network retry
Preconditions: Existing enrollment for same EnrollmentRequestId or active payout per user.
Flow (idempotent enroll): [TwitchExtension] → [Backend]: duplicate enrollmentRequestId → 200 OK same enrollment (docs/overview/SPEC.md §4).
Flow (rate limit): burst of requests → 429 or server rate-limit response (ASP.NET Core rate limiter ~5/min per SPEC).
Flow (active payout): second winner payout while one active → 409-style error body e.g. active_payout_exists (docs/overview/SPEC.md §5).
Postconditions: No double-spend via same enrollment request id; abuse bounded by rate limit.
Failure exits: client mishandles idempotent 200 vs 201.
Trigger: Extension calls Backend with missing/invalid/expired Twitch JWT.
Actor: Viewer
Preconditions: Backend validates real Twitch-issued Extension JWTs (Dev Rig and deploy — docs/overview/SPEC.md deployment scope).
Flow:
POST /api/payouts/claim with bad Authorization: Bearer …[Backend] → [TwitchExtension]: 401 unauthorized |
body: { "code": "unauthorized", … } (recommended shape §5) |
Postconditions: No pool write.
Failure exits: clock skew; wrong extension secret; Dev Rig misconfiguration.
Trigger: Stream triggers mail send while mailbox closed, bad recipient, or insufficient gold.
Actor: Streamer
Preconditions: Payout InProgress; addon queue has entry.
Flow:
MGM_CONFIRM linedocs/overview/SPEC.md transitions allow Failed)Postconditions: Payout Failed or remains InProgress until operator acts.
Failure exits: silent addon bug; duplicate send attempts (state machine should prevent per WoWAddon ReadME).
Trigger: Many Extensions or bots hit API above configured limits.
Actor: External clients
Preconditions: Rate limiter / server max concurrency configured.
Flow:
429 Too Many Requests or server-defined throttling (ASP.NET rate limiting per SPEC ~5 req/min per IP/user)Postconditions: No unbounded queue assumed in docs—reject or delay per implementation.
Failure exits: DDoS beyond app layer; DB overload not detailed in MVP docs.
Resolution: Global saturation may yield 503; Extension backoff + Retry per docs/overview/SPEC.md §5 error model and §5.1. Per-user 429 remains ~5 req/min target.
Trigger: Network drop during poll, PATCH, or confirm calls.
Actor: System
Preconditions: Desktop mid-flow (e.g. after addon signaled !twgold locally).
Flow:
GET /api/payouts/pending → IOException / timeoutPostconditions: Eventually consistent if retries succeed; operator may use overrides.
Failure exits: prolonged outage → stale InProgress; missed MGM_CONFIRM sync until back online.
Status: Placeholder scenario — documents a possible future control; do not implement or test as current product behavior. docs/overview/SPEC.md — pause/resume is not in MVP.
Trigger: Streamer wants to temporarily stop processing payouts.
Actor: Streamer
Preconditions: None defined in SPEC for a pause flag.
Flow:
Resolved for MVP: no pause flag; streamer stops processing only by operational means (e.g. not running Desktop, not confirming mail, or cancelling payouts per other scenarios).
Postconditions (conceptual): A later spec may add a pause flag; until then, operator-only workarounds.
Failure exits: N/A until specified.
Trigger: Streamer chooses cancel in Desktop for a Pending (or allowed state) payout.
Actor: Streamer
Preconditions: Payout in Pending (or as allowed by transition table §3).
Flow:
PATCH /api/payouts/{id}/status { "status": "Cancelled" } + X-MGM-ApiKeyPostconditions: Payout Cancelled (terminal for operator purpose per lifecycle).
Failure exits: illegal transition → terminal_status_change_not_allowed; wrong id → 404.
Trigger: First injection or mail attempt failed; streamer retries.
Actor: Streamer / Desktop
Preconditions: Payout InProgress or returned to operable state per policy.
Flow:
/run ReceiveGold("...") after fixing root cause or streamer completes mail manually with addon still emitting MGM_CONFIRMPostconditions: MGM_CONFIRM observed → Sent.
Failure exits: double payout if state machine buggy (mitigated by single active payout rule).
MVP (locked): Do not implement retry tokens, retry endpoints, or other speculative Backend APIs for this scenario. Recovery is operator-driven re-inject / same payout id (idempotent client behavior per
docs/overview/SPEC.md). A future spec may add machinery; until then, ignore this scenario for new API surface.
Covers: SC-001
Component under test: E2E (TwitchExtension + Backend + Desktop + WoWAddon)
Type: E2E
Preconditions:
ApiKey; Dev Rig JWT or mocks; WoW test client with addon; Desktop test build; clearing known payout rows for test Twitch user.Input:
| Field | Value |
|---|---|
| characterName | Norinn |
| enrollmentRequestId | 550e8400-e29b-41d4-a716-446655440000 |
| twitchUserId | 90001337 |
| goldAmount (winner payout) | 1000g (10000000 copper) |
Steps:
!twgold Norinn → pool enroll or Extension POST /api/payouts/claim → 201/who success (test hook or scripted Desktop)Pending payout for Norinn!twgold → Desktop confirm-acceptance → successPATCH InProgress, inject ReceiveGold, complete mail in-gameWoWChatLog.txt contains [MGM_CONFIRM:<id>]PATCH SentExpected Result:
| Assertion | Expected Value |
|---|---|
| Final GET payout status | Sent |
| HTTP PATCH last call | 200 |
| confirm-acceptance | 200; WinnerAcceptedWillingToReceiveAt set in read model (if exposed) |
Expected Side Effects:
Notes: 3.3.5a MAIL_SHOW / whisper event names must match addon; E2E may be split into stubs for /who parsing.
/who (failure)Covers: SC-001
Component under test: Backend + Desktop (roulette orchestration)
Type: Integration
Preconditions: Pool with one character known offline in test harness.
Input:
| Field | Value |
|---|---|
| characterName | Offlinebob |
Simulated /who result |
not found / offline |
Steps:
/who Offlinebob; mock parser returns offlineExpected Result:
| Assertion | Expected Value |
|---|---|
Pending payout for this spin |
not created (or spin re-issues per policy) |
| Extension | no “You won” for loser of invalid draw |
Expected Side Effects:
Pending payout created for this spin cycle; pool unchanged until next scheduled spin.Notes: docs/overview/SPEC.md — no re-draw in the same 5-minute cycle; no second candidate pick.
Covers: SC-002
Component under test: Backend
Type: Integration
Preconditions: Known good API key in config.
Input:
| Field | Value |
|---|---|
| Header X-MGM-ApiKey | <configured-secret> |
Steps:
GET /api/payouts/pending with headerExpected Result:
| Assertion | Expected Value |
|---|---|
| HTTP status | 200 |
| Body | JSON array (possibly empty) |
Expected Side Effects: None beyond auth logging.
Notes: None.
Covers: SC-002
Component under test: Backend
Type: Integration
Preconditions: Same as TC-003 but wrong key.
Input:
| Field | Value |
|---|---|
| Header X-MGM-ApiKey | wrong-key |
Steps:
GET /api/payouts/pendingExpected Result:
| Assertion | Expected Value |
|---|---|
| HTTP status | 403 |
| body.code | forbidden_apikey |
Expected Side Effects: None.
Notes: Align with docs/overview/SPEC.md §5 error model.
Covers: SC-003
Component under test: Desktop
Type: Integration
Preconditions: WoW running; test window focus.
Input:
| Field | Value |
|---|---|
| Command line (example) | /run ReceiveGold("…") <255 chars |
Steps:
Expected Result:
| Assertion | Expected Value |
|---|---|
| WoW chat box / addon | command executed |
Expected Side Effects: WinAPI PostMessage to game window message queue.
Notes: Timing/focus documented for 3.3.5a compatibility per project rules.
Covers: SC-011
Preconditions: No WoW.exe; Desktop running.
Input: N/A
Steps:
FindWindow / process scanExpected Result:
| Assertion | Expected Value |
|---|---|
| UI / error | “WoW not found”; no inject |
Expected Side Effects: Optional telemetry.
Notes: MVP targets foreground WoW.exe only (docs/overview/SPEC.md §8).
Covers: SC-003
Component under test: Desktop
Type: Integration
Preconditions: WoW running but HWND wrong or injection test double returns failure.
Input:
| Field | Value |
|---|---|
| Strategy | PostMessage (primary) |
Steps:
Expected Result:
| Assertion | Expected Value |
|---|---|
| First attempt | no addon ReceiveGold observed OR error surfaced |
| Fallback (if enabled) | may succeed per strategy pattern |
Expected Side Effects: Logged Win32 error codes.
Notes: Align with IWoWInputStrategy (docs/components/desktop/ReadME.md).
Covers: SC-011
Component under test: Desktop
Type: Integration
Preconditions: Start with no WoW; then user starts WoW.exe.
Steps:
Expected Result:
| Assertion | Expected Value |
|---|---|
| After launch | process found; UI Ready to Inject (or equivalent) |
Expected Side Effects: Subsequent PostMessage allowed.
Notes: Recovery path for streamer workflow.
Covers: SC-004
Component under test: WoWAddon
Type: Integration (in-client or harness)
Preconditions: Mail compose filled for payout a1b2c3d-1111-2222-3333-444444444444; mailbox open; send MGM-armed.
Input:
| Field | Value |
|---|---|
| payoutId | a1b2c3d-1111-2222-3333-444444444444 |
Steps:
MAIL_SEND_SUCCESSWoWChatLog.txt and verify winner whisper (in-client)MAIL_SEND_SUCCESS must not emit [MGM_CONFIRM:…]Expected Result:
| Assertion | Expected Value |
|---|---|
| MGM path log line | [MGM_CONFIRM:a1b2c3d-1111-2222-3333-444444444444] |
| Winner whisper body | Награда отправлена тебе на почту, проверяй ящик! |
| Manual send | no [MGM_CONFIRM] |
Expected Side Effects: Lua prints tag; completion whisper via SendChatMessage; no HTTP from Lua.
Notes: docs/overview/SPEC.md §9 (MAIL_SEND_SUCCESS / MAIL_FAILED).
Covers: SC-004
Component under test: WoWAddon
Type: Unit / Integration
Preconditions: Mailbox closed or validation fails in wrapper.
Steps:
Expected Result:
| Assertion | Expected Value |
|---|---|
| MGM_CONFIRM | absent |
| Queue state | remains PROCESSING or READY per state machine |
Expected Side Effects: None on Backend until operator fails payout.
Notes: SendMail frame names must match 3.3.5a.
Covers: SC-010
Component under test: Backend
Type: Integration
Preconditions: Create Pending payout via test API; no Desktop polls.
Steps:
Pending rowPATCH from Desktop)Expected Result:
| Assertion | Expected Value |
|---|---|
| Status | remains Pending until Desktop or expiration job |
Expected Side Effects: Hourly job may set Expired after 24h.
Notes: None.
Covers: SC-010
Component under test: Desktop + Backend
Type: Integration
Preconditions: Pending exists; Desktop starts.
Steps:
GET /api/payouts/pendingExpected Result:
| Assertion | Expected Value |
|---|---|
| HTTP status | 200 |
| Body | includes Pending payout id |
Expected Side Effects: None.
Notes: Verifies recovery from SC-010 scenario.
Covers: SC-012
Component under test: Backend
Type: Unit / Integration
Input:
| Field | Value |
|---|---|
| characterName | Bad:Name |
Steps:
POST /api/payouts/claimExpected Result:
| Assertion | Expected Value |
|---|---|
| HTTP status | 400 (or domain equivalent) |
| body.code | invalid_character_name |
Expected Side Effects: No pool row.
Notes: Realm existence check not in MVP spec—see SC-012 open question.
Covers: SC-012
Component under test: Desktop + Backend
Type: E2E (manual)
Preconditions: Enrolled name Ghostcow never created on realm.
Steps:
PATCH { "status": "Failed" }Expected Result:
| Assertion | Expected Value |
|---|---|
| Final status | Failed |
Expected Side Effects: Event Failed in store.
Notes: Documents operator escape hatch; not automatic API validation.
Covers: SC-013
Component under test: Backend
Type: Integration
Input:
| Field | Value |
|---|---|
| enrollmentRequestId | 550e8400-e29b-41d4-a716-446655440001 |
Steps:
POST /api/payouts/claim → 201200Expected Result:
| Assertion | Expected Value |
|---|---|
| Second response | 200 OK; same logical enrollment |
| DB unique constraint | no duplicate row for id |
Expected Side Effects: None.
Notes: Per docs/overview/SPEC.md §4.
Covers: SC-013 / SC-016
Component under test: Backend
Type: Integration
Preconditions: Configure low rate limit for test.
Steps:
Expected Result:
| Assertion | Expected Value |
|---|---|
| HTTP status | 429 (or 403 per host policy) |
Expected Side Effects: No unbounded queue assumed.
Notes: docs/overview/SPEC.md §2 / §5.
Covers: SC-013
Component under test: Backend
Type: Integration
Preconditions: Test user already has Pending or InProgress payout.
Steps:
Expected Result:
| Assertion | Expected Value |
|---|---|
| body.code | active_payout_exists |
Expected Side Effects: None.
Notes: Exact trigger route may be spin finalize API when added.
Covers: SC-014
Component under test: Backend
Type: Integration
Preconditions: JWT validation strict mode ON.
Steps:
POST /api/payouts/claim without valid BearerExpected Result:
| Assertion | Expected Value |
|---|---|
| HTTP status | 401 |
| body.code | unauthorized |
Expected Side Effects: None.
Notes: Dev Rig may bypass—label test environment.
Covers: SC-014
Component under test: Backend + TwitchExtension
Type: Integration
Preconditions: Dev Rig (or deployed Extension) session with a real Twitch-issued Extension JWT, as required by docs/overview/SPEC.md (MVP deployment scope).
Steps:
POST /api/payouts/claim when implemented) with valid Authorization: Bearer <token>.Expected Result:
| Assertion | Expected Value |
|---|---|
| HTTP status | 201 or 200 (or other success per endpoint contract) |
Expected Side Effects: Enrollment or read succeeds per docs/overview/SPEC.md.
Notes: Stricter production JWT rotation and issuer checks are a roadmap hardening item; MVP still uses validated real tokens, not a permanent mock bypass.
Covers: SC-015
Component under test: WoWAddon
Type: Integration
Steps:
MAIL_SHOWExpected Result:
| Assertion | Expected Value |
|---|---|
| No MGM_CONFIRM | true |
Expected Side Effects: Streamer uses Fail in Desktop.
Notes: 3.3.5a FrameXML.
Covers: SC-015
Component under test: Backend
Type: Integration
Steps:
PATCH /api/payouts/{id}/status { "status": "Failed" } from InProgressExpected Result:
| Assertion | Expected Value |
|---|---|
| HTTP status | 200 |
| Read model status | Failed |
Expected Side Effects: Terminal for manual resolution.
Notes: Transition table docs/overview/SPEC.md §3.
Covers: SC-016
Component under test: Backend
Type: Load / Integration
Steps:
POST from N virtual usersExpected Result:
| Assertion | Expected Value |
|---|---|
| p99 latency / errors | bounded; 429 under overload |
Expected Side Effects: None.
Notes: 503 / global saturation — docs/overview/SPEC.md §5 error model + §5.1 Extension backoff.
Covers: SC-016
Component under test: Backend
Type: Integration
Steps:
Expected Result:
| Assertion | Expected Value |
|---|---|
| Responses | 2xx for valid bodies |
Expected Side Effects: None.
Notes: Tune limiter constants to SPEC.
Covers: SC-017
Component under test: Desktop
Type: Integration (chaos)
Preconditions: Wiremock drops first N requests.
Steps:
GET /api/payouts/pendingExpected Result:
| Assertion | Expected Value |
|---|---|
| Outcome after retries | success or surfaced failure |
Expected Side Effects: Polly backoff (Desktop ReadME).
Notes: Avoid infinite retry loops.
Covers: SC-017
Component under test: Desktop
Type: Integration
Preconditions: Backend down prolonged.
Steps:
Expected Result:
| Assertion | Expected Value |
|---|---|
| UI | error state; queue not updated |
Expected Side Effects: None on server.
Notes: Operator restarts when network returns.
Covers: SC-020
Component under test: Backend / Desktop
Type: N/A
Preconditions: None.
Steps: Document only until spec adds pause.
Expected Result:
| Assertion | Expected Value |
|---|---|
| Test | skipped / pending requirements |
Expected Side Effects: None.
Notes: Align with SC-020 (future / not MVP) — no pause in spec until added.
Covers: SC-020
Component under test: Backend
Type: Unit (future)
Steps: Placeholder.
Expected Result: N/A
Expected Side Effects: N/A
Notes: Reserved ID; implement when feature exists.
Covers: SC-021
Component under test: Backend
Type: Integration
Preconditions: Payout Pending.
Steps:
PATCH /api/payouts/{id}/status { "status": "Cancelled" } + ApiKeyExpected Result:
| Assertion | Expected Value |
|---|---|
| HTTP status | 200 |
| status | Cancelled |
Expected Side Effects: Event stored.
Notes: None.
Covers: SC-021
Component under test: Backend
Type: Integration
Preconditions: Payout already Sent.
Steps:
PATCH { "status": "Cancelled" }Expected Result:
| Assertion | Expected Value |
|---|---|
| HTTP status | 400 / 409 |
| body.code | terminal_status_change_not_allowed |
Expected Side Effects: None.
Notes: §3 transitions.
Covers: SC-022
Component under test: Desktop
Type: Integration
Steps:
Expected Result:
| Assertion | Expected Value |
|---|---|
| Addon receives | payload once (no duplicate queue entries if idempotent) |
Expected Side Effects: Second WinAPI PostMessage.
Notes: Backend should reject illegal transitions; duplicate MGM_CONFIRM → idempotent PATCH or stable error (docs/overview/SPEC.md §3).
Covers: SC-022
Component under test: Desktop + Backend
Type: Integration
Preconditions: Payout already Sent.
Steps:
[MGM_CONFIRM:uuid] line in logExpected Result:
| Assertion | Expected Value |
|---|---|
| Backend | no invalid double transition (idempotent PATCH or reject) |
Expected Side Effects: Logged warning optional.
Notes: Align with terminal state rules.
Summary of documented boundaries. Pool/spin polling routes are defined in docs/overview/SPEC.md §5.1.
MVP boundary: Twitch Extension and WPF Desktop have no direct integration (no shared socket, no peer channel). Viewers use the Extension plus broadcast chat; the streamer uses Desktop plus WoW; both sides coordinate through HTTP to the EBS / Desktop paths (Twitch Extension JWT vs X-MGM-ApiKey, docs/overview/SPEC.md), and mail completion uses the WoW chat log bridge per docs/overview/SPEC.md §8–10.
| Direction | Message/Endpoint | Payload shape | Success response | Failure response |
|---|---|---|---|---|
| Extension → API | POST /api/payouts/claim (optional) |
{ "characterName": string, "enrollmentRequestId": string } + Twitch JWT (subscriber verified server-side) |
201 Created (new enroll) or 200 OK (idempotent) |
400 invalid_character_name; 401 unauthorized; 403/400 if not subscribed; 409/400 character_name_taken_in_pool; 429 rate limit; cap errors e.g. lifetime_cap_reached |
| Chat → EBS (Backend) | Twitch EventSub transport → channel.chat.message |
Enrollment text !twgold <CharacterName> parsed from event payload (docs/overview/SPEC.md §5; EBS / EventSub in SPEC) |
pool enroll / replace per docs/overview/SPEC.md §5 |
domain errors per docs/overview/SPEC.md §5 |
| Extension → API | GET /api/payouts/my-last |
Twitch Extension JWT (Bearer) | 200 + PayoutDto |
404 when no winner payout |
| Extension → API | GET /api/roulette/state |
Twitch Extension JWT | 200 + schedule + spinPhase enum + optional currentSpinCycleId (docs/overview/SPEC.md §5.1) |
401, 429, domain errors |
| Extension → API | GET /api/pool/me |
Twitch Extension JWT | 200 + enrollment hint |
401, 429 |
| API → Extension | (pull only in MVP) | — | Extension polls for winner notification / status | Error boundary UI per TwitchExtension ReadME |
Normative copy and Helix delivery: docs/overview/SPEC.md §11 (reward-sent announcement when a payout becomes Sent; EBS-owned credentials).
| Direction | Message/Endpoint | Payload shape | Success response | Failure response |
|---|---|---|---|---|
| EBS → Chat | Twitch Helix Send Chat Message immediately on transition to Sent (MVP locked) |
One line: Награда отправлена персонажу <WINNER_NAME> на почту, проверяй ящик! (WINNER_NAME = enrolled CharacterName) |
Message visible in broadcast chat | Helix/auth errors (401/403), rate limits; must not depend on WoW addon |
Note: The chat line is not a return path into Desktop or WoW; it is broadcast-only viewer notice aligned with Extension hardcoded copy.
| Direction | Message/Endpoint | Payload shape | Success response | Failure response |
|---|---|---|---|---|
| API ← Desktop | GET /api/payouts/pending |
header X-MGM-ApiKey |
200 JSON list of winner payouts (Pending primary) |
403 forbidden_apikey |
| API ← Desktop | POST /api/roulette/verify-candidate |
JSON from [MGM_WHO] line + X-MGM-ApiKey (docs/overview/SPEC.md §5, §8) |
200 (may create Pending) |
400; 403 |
| API ← Desktop | PATCH /api/payouts/{id}/status |
{ "status": "…" } — allowed: Pending/InProgress/Sent/Failed/Cancelled per docs/overview/SPEC.md §3 (includes InProgress → Pending escape hatch) |
200 |
400 terminal_status_change_not_allowed; 403; 404 not_found |
| API ← Desktop | POST /api/payouts/{id}/confirm-acceptance |
{ "characterName": string } (required) |
200 (acceptance recorded; not Sent) |
403; 404 |
| API ← Desktop | Mail-send path | Desktop derives from log → PATCH → Sent |
200 |
same as PATCH |
Desktop does not consume a Backend push channel in MVP docs; polling is implied.
| Direction | Message/Endpoint | Payload shape | Success response | Failure response |
|---|---|---|---|---|
| Desktop → WoW | Win32 focus + PostMessage (primary) | Window handle + chat/input messages carrying /run NotifyWinnerWhisper("uuid","Name"), /run ReceiveGold("…"), or /who Name text |
Game executes; addon/Lua runs | Wrong HWND; focus timing; anti-cheat block |
| Desktop → WoW | SendInput (fallback) | OS input synthesize | Same | User-configured fallback failures |
| WoW → Desktop | (no direct callback) | — | — | — |
| Direction | Message/Endpoint | Payload shape | Success response | Failure response |
|---|---|---|---|---|
| Client → Addon | Global NotifyWinnerWhisper(payoutId, characterName) |
via /run from Desktop (docs/overview/SPEC.md §8–9) |
§9 /whisper sent by addon |
Bad args; WoW limits |
| Client → Addon | Global ReceiveGold(dataString) |
semicolon entries: UUID:CharacterName:GoldCopper; |
Queued mail prep | Parse error; invalid delimiters |
| Client → Addon | MAIL_SHOW (event) | (FrameXML) | Side panel + queue UX | Events not fired if wrong hook |
| Client → Addon | Whisper events | sender + text matching !twgold (case-insensitive) |
Print [MGM_ACCEPT:UUID] to chat |
Wrong event registration on 3.3.5a |
| Addon → Client | Chat print [MGM_WHO] + JSON / [MGM_ACCEPT:UUID] / [MGM_CONFIRM:UUID] |
string | lines in WoWChatLog.txt |
Wrong tag; mail not sent → no CONFIRM |
| Addon → Chat log | [MGM_WHO] + JSON (docs/overview/SPEC.md §8) |
/who parse result |
Desktop tail WoWChatLog.txt → POST /api/roulette/verify-candidate |
Line missing; parse failure |
| Direction | Message/Endpoint | Payload shape | Success response | Failure response |
|---|---|---|---|---|
| Addon → Desktop | [MGM_WHO] in Logs\WoWChatLog.txt (docs/overview/SPEC.md §8) |
/who result for verify-candidate |
Desktop POST /api/roulette/verify-candidate |
Log path wrong; stale spinCycleId |
| Addon → Desktop | [MGM_ACCEPT:UUID] in Logs\WoWChatLog.txt |
addon prints after Lua whisper match | Desktop confirm-acceptance | Log path wrong; tag missing |
| Desktop → API | POST /api/payouts/{id}/confirm-acceptance |
JSON body + ApiKey | 200 |
403, 404, validation |
| Desktop → API | PATCH /api/payouts/{id}/status Sent |
after [MGM_CONFIRM:UUID] in Logs\WoWChatLog.txt |
200 |
transition errors |
| Desktop | Manual Mark as Sent | operator override | same PATCH path | audit note |
Document maintenance: If [MGM_ACCEPT] / [MGM_CONFIRM] log formats change, update regexes in Desktop and docs/overview/SPEC.md §10. Pool/spin routes: docs/overview/SPEC.md §5.1 (GET /api/roulette/state, GET /api/pool/me).