Verifluence — Implemented Use Cases
Documents the currently working use cases derived from API handlers, DB schema, and frontend pages. Last updated: March 2026.
Actors
| Actor | Description |
|---|---|
| Public | Unauthenticated visitor |
| Streamer | Authenticated content creator |
| Operator | Authenticated casino / sportsbook company |
| Admin | Platform administrator (managed via separate admin app + impersonation tokens) |
UC-1 · Operator Onboarding
UC-1.1 · Register via Invitation
Actor: Operator Preconditions: Admin has created an Invitation record and emailed the code to the operator.
Flow:
- Operator opens
/entry?invitation=CODE. - System validates the invitation code (status =
pending). - Operator enters display name; slug is auto-generated from the name.
- Operator accepts T&C consent.
- System creates an
operatorsrow (status =prepared) and marks the invitationused. - Operator is redirected to
/operator/account.
Postconditions: Operator account exists with status prepared. Admin must change status to published to grant full access.
| Test | Assertion |
|---|---|
| — | not yet automated — requires admin-seeded invitations row |
UC-1.2 · Connect Operator Wallet
Actor: Operator Preconditions: Operator is authenticated. MetaMask or compatible EVM wallet installed in browser.
Flow:
- Operator opens
/operator/wallet. - Operator clicks "Connect Wallet"; MetaMask prompts for signature.
- System records
operator_walletsrow with wallet address and current consent version. - Multiple wallets can be connected; each is stored independently.
Postconditions: Wallet address available for on-chain campaign funding.
| Test | Assertion |
|---|---|
| — | not yet automated — on-chain / MetaMask, not API-testable |
UC-1.3 · Operator Sign In
Actor: Operator Preconditions: Operator account exists.
Flow:
- Operator visits any
/operator/*page. - If not authenticated, system redirects to
/signin2. - Operator enters registered email; system sends a 4-digit PIN via email.
- Operator enters PIN; session cookie is set.
- Operator is redirected to original destination or
/operator/account.
| Test | Assertion |
|---|---|
| TC-AUTH-01 | Happy path — PIN sent and verified, session established |
→ Product Guide: Registration & Onboarding · Wallet
UC-2 · Campaign Management (Operator)
UC-2.1 · Create Campaign
Actor: Operator Preconditions: Operator authenticated and account status published.
Flow:
- Operator opens
/operator/campaignsand clicks "New Campaign". - Multi-step form collects:
- Name, category (
casino/sportbook), description - Dates, timezone, schedule type + time slots
- Budget cap (USDC), max payout per stream
- Minimum follower, viewer, and monthly hours requirements
- Platforms, GEOs, languages
- Payout model (fixed / fixed+rs), payout brackets, CPA/RS rates
- Brief summary, deliverables, brand dos/don'ts
- Contract length, termination clause, application deadline
- Name, category (
- System creates a
campaignsrow with status =preparedand settings JSONB.
Postconditions: Campaign in Draft state. Not visible to streamers.
| Test | Assertion |
|---|---|
| — | not yet automated |
UC-2.2 · Edit Campaign
Actor: Operator Preconditions: Campaign exists with status prepared.
Flow:
- Operator selects campaign in the list; clicks "Edit".
- Form is pre-populated with existing data.
- Operator modifies any allowed fields and saves.
- System issues
PUT /api/campaigns/:id.
Constraints: Edit is allowed only for Draft campaigns. Once funded, edits are not available through the UI.
| Test | Assertion |
|---|---|
| — | not yet automated |
UC-2.3 · Delete Campaign
Actor: Operator Preconditions: Campaign status is prepared.
Flow:
- Operator clicks "Remove" in the campaign detail panel.
- System issues
DELETE /api/campaigns/:id. - Campaign row is hard-deleted.
Constraints: Only prepared campaigns can be deleted (API enforced).
| Test | Assertion |
|---|---|
| — | not yet automated |
UC-2.4 · Fund Campaign (On-chain Escrow Deposit)
Actor: Operator Preconditions: Campaign is prepared. Operator has a connected wallet with sufficient USDC balance.
Flow:
- Operator opens campaign detail panel on
/operator/campaigns. FundCampaignPaneldisplays escrow deposit form (amount, network, timelock).- Operator approves USDC spend in MetaMask, then confirms the deposit transaction.
- System detects on-chain confirmation; updates campaign
escrow_id,network_id,funding_address, and status tofunded.
Postconditions: Campaign is visible to streamers. Funds locked in HTLC contract.
| Test | Assertion |
|---|---|
| — | not yet automated — on-chain / MetaMask, not API-testable |
→ Product Guide: Campaign Creation · Fund Deposit
UC-3 · Campaign Discovery & Application (Streamer)
UC-3.1 · Browse Campaigns
Actor: Public / Streamer Preconditions: None (public access).
Flow:
- User opens
/campaigns. - System fetches campaigns with status
fundedorin_progressfrom the API. - User can filter by tag (Beginner friendly, High budget, Closing soon) and sort (Featured, Highest budget, Newest).
- Campaign cards show operator name, category, platforms, budget, dates, min requirements.
Constraint — Streamer isolation: Authenticated streamers must never see other streamers' profiles, usernames, pricing, or deal terms. /streamers and /s/:username routes return 403 for streamer-role sessions.
| Test | Assertion |
|---|---|
| — | not yet automated — read-only list endpoint |
UC-3.2 · View Campaign Detail
Actor: Public / Streamer
Flow:
- User opens
/campaign/:id. - System fetches campaign details.
- Unauthenticated users see full public info with a sign-in CTA.
- Authenticated streamers see an application card (apply / already applied / approved).
- Tabbed sections: Overview, Requirements, Reward.
| Test | Assertion |
|---|---|
| — | not yet automated — read-only endpoint |
UC-3.3 · Submit an Offer (Streamer-initiated)
Actor: Streamer Preconditions: Streamer authenticated with status active (not suspended/archived). Campaign status funded or in_progress. No active (pending or accepted) offer already exists for this streamer on this campaign.
Flow:
- Streamer clicks "Apply" on the campaign detail page or card.
- Offer form shows five deal term fields pre-filled from the campaign's
minimal_terms. - Streamer adjusts values and optionally adds a pitch message.
- System validates all starting terms are ≥ campaign floor values.
- System creates an
offersrow withinitiated_by = 'streamer',status = 'pending', and no expiry (streamer offers do not expire). - Operator receives a notification.
Postconditions: Offer visible in /profile/offers (streamer) and the campaign's Offers panel (operator).
Constraints:
- Suspended and archived streamer accounts are blocked (403).
- Values below campaign floor → per-field validation error.
- Duplicate active offer → 409 (one per streamer per campaign at a time).
| Test | Assertion |
|---|---|
| TC-OFFER-01 ⚠️ | POST /api/campaigns/:id/offers → 201; test uses initiated_by = "operator" — streamer-initiated path not yet separately asserted |
→ Product Guide: Applying to Campaigns
UC-3.4 · Withdraw Offer
Actor: Streamer Preconditions: Offer status is pending. Streamer is the initiating party.
Flow:
- Streamer opens
/profile/offers. - Clicks "Withdraw" on a pending offer.
- System issues
PATCH /api/offers/:idwithaction = 'withdraw'.
| Test | Assertion |
|---|---|
| TC-OFFER-04 | revoke_decline blocked by uq_offer_active when conflict exists → 409 |
| TC-OFFER-05 | revoke_decline succeeds when no conflict → offer returns to pending |
UC-4 · Offer Review (Operator)
UC-4.1 · View Campaign Offers
Actor: Operator Preconditions: Operator has funded campaigns.
Flow:
- Operator opens
/operator/activeand selects a campaign. - System fetches
offersfor the campaign viaGET /api/campaigns/:id/offers. - Offers listed with streamer username, Trust Score, starting terms, and current status.
| Test | Assertion |
|---|---|
| — | not yet automated — read-only list endpoint |
UC-4.2 · Accept Offer → Open Negotiation
Actor: Operator Preconditions: Offer status pending, initiated by streamer (or operator is the streamer receiving the offer back). Campaign status funded or in_progress.
Flow:
- Operator selects a pending offer and clicks "Accept".
- System issues
PATCH /api/offers/:idwithaction = 'accept'. - API transitions offer status to
accepted. - API auto-creates a
negotiationsrow seeded from the offer'sstarting_terms, withoffer_idset and initialturn='operator'(since streamer proposed). - Both parties are notified.
Postconditions: Negotiation exists with status in_progress.
| Test | Assertion |
|---|---|
| TC-OFFER-02 | Duplicate accept is idempotent or returns 409 — offer never left in inconsistent state |
UC-4.3 · Decline Offer
Actor: Operator
Flow:
- Operator clicks "Decline" on a pending offer.
- System issues
PATCH /api/offers/:idwithaction = 'decline'. - Offer transitions to
declined. Streamer can re-apply.
| Test | Assertion |
|---|---|
| TC-OFFER-03 | action = decline → offer status declined |
UC-4.4 · Send Offer to Streamer (Operator-initiated)
Actor: Operator Preconditions: Operator has at least one funded/in-progress campaign (Tier 2 directory access). Streamer has no active offer on this campaign.
Flow:
- Operator opens a streamer's public profile at
/s/:username. - Clicks "Send Offer" and selects a campaign.
- Offer form shows five deal term fields pre-filled from
campaign.minimal_terms. - Operator adjusts values, adds an optional message, and sets an expiry date (default: 7 days).
- System validates starting terms ≥ campaign floors.
- System creates
offersrow withinitiated_by = 'operator',status = 'pending',expires_atset. - Streamer receives a notification.
Postconditions: Offer visible to both parties. Streamer can accept, decline, or let it expire.
Rate limit: 20 operator-initiated offers per 24-hour window.
| Test | Assertion |
|---|---|
| TC-OFFER-01 ⚠️ | POST /api/campaigns/:id/offers with initiated_by = "operator" → 201 |
| — | Expiry enforcement and rate-limit (20/24h) not yet automated |
→ Product Guide: Offer Review & Deal Negotiation · Budget Allocation
UC-4B · Deal Negotiation
UC-4B.1 · Propose or Approve a Term
Actor: Operator or Streamer Preconditions: Negotiation status = in_progress. It is this actor's turn.
Flow:
- Actor opens the negotiation panel and sees all five terms with current proposed values and approval states.
- Approve — Actor clicks "Approve" on a term they agree with.
- System sets
op_okorstr_ok=trueon that term.
- System sets
- Propose — Actor enters a new value for a term.
- System updates
valueandproposed_by. - Resets the other party's
okflag tofalseon that term.
- System updates
- After either action, the system checks whether all five terms have both
op_ok = trueandstr_ok = true. - If all agreed → negotiation status transitions to
agreed;agreed_atis recorded. - Otherwise →
turnadvances to the other party.
Constraints: Values must remain ≥ campaign floor values throughout negotiation.
| Test | Assertion |
|---|---|
| TC-NEG-01 | Streamer approves all 5 terms → status = agreed, agreed_at set, turn = NULL |
UC-4B.2 · Cancel Negotiation
Actor: Operator or Streamer Preconditions: Negotiation status = in_progress.
Flow:
- Actor clicks "Cancel Negotiation".
- System issues
POST /api/negotiations/:id/cancel. - Negotiation transitions to
cancelled. A new offer can be created to restart.
| Test | Assertion |
|---|---|
| — | not yet automated |
UC-4B.3 · Fund Deal
Actor: Operator Preconditions: Negotiation status = agreed.
Flow:
- Operator opens the agreed negotiation and clicks "Fund Deal".
- System confirms the negotiation is
agreedand the operator is the correct party. - Operator supplies on-chain parameters (escrow ID, network, funding address, allocation ID and amount).
- Operator signs the HTLC allocation transaction in MetaMask.
- System creates a
dealsrow with:negotiation_idFKagreed_terms— immutable JSONB snapshot of the five negotiated values- On-chain fields (
escrow_id,network_id,funding_address,allocation_id,allocation_amount) status = 'active'
- Both parties notified. Streamer's delivery panel becomes active.
Postconditions: Deal exists and is active. Agreed terms are permanently frozen.
| Test | Assertion |
|---|---|
| TC-NEG-02 | allocation_amount exceeds budget cap → 409 |
| TC-NEG-03 | allocation_amount within budget cap → 201, status = active |
| TC-NEG-04 | wallet_address snapshotted from streamer_addresses at funding time |
→ Product Guide: Offer Review & Deal Negotiation
UC-5 · Stream Delivery (Streamer)
UC-5.1 · Submit Stream Session Proof
Actor: Streamer Preconditions: Application status approved. Streamer has a slot_index to submit for.
Flow:
- Streamer opens
/profile/campaigns. - Selects approved campaign and an available slot.
- Pastes stream/VOD URL.
- Optionally selects a tracked Kick session from the dropdown.
- Clicks "Submit".
- System creates
session_submissionsrow (status =pending_review).
Constraints: One submission per slot index (DB UNIQUE constraint). URL is currently required (tracked-session-only path is a known gap — F-4).
| Test | Assertion |
|---|---|
| TC-DEL-01 | slot_index outside allocation range → 400, error lists valid indices |
| TC-DEL-02 | Valid slot_index → 201, status = pending_review, attempt = 1 |
| TC-DEL-03 | Slot already confirmed → resubmission blocked with 409 |
→ Product Guide: Delivery & Submission
UC-6 · Delivery Review & Payout (Operator)
UC-6.1 · Review Submission
Actor: Operator Preconditions: session_submissions row with status pending_review.
Flow:
- Operator opens
/operator/active. - Submission listed under the relevant application.
- Operator reviews stream URL and any notes.
- Operator clicks "Confirm" or "Reject".
| Test | Assertion |
|---|---|
| — | not yet automated — read-only list view |
UC-6.2 · Confirm Submission → Release Payout
Actor: Operator Preconditions: Submission pending_review. Streamer KYC status = approved (API enforced — F-1).
Flow:
- Operator confirms submission.
- API:
- Checks
kyc_status = 'approved'on streamer. Returns 403 if not. - Reads per-slot amount from
allocation_preimages.slots[slot_index]. - Inserts
payout_recordsrow with amount, wallet snapshot,allocation_id. - Updates
session_submissions.status = 'confirmed'.
- Checks
- Operator retrieves preimage for the slot (stored in
allocation_preimages). - Operator sends preimage to streamer off-platform (or automated via payout_type =
automatic). - Streamer calls
withdraw()on-chain using the preimage. - Streamer (or frontend) submits tx hash via
PATCH /api/session-submissions/:id/tx.
Postconditions: payout_records row has tx_hash. Streamer has received USDC.
| Test | Assertion |
|---|---|
| TC-DEL-04 | Confirming last slot → deals.status = completed (auto-complete regression) |
| TC-DEL-05 | Confirming partial slot → deals.status remains active |
| TC-DEL-06 | Streamer KYC not approved → confirmation blocked with 403 |
UC-6.3 · Reject Submission
Actor: Operator
Flow:
- Operator clicks "Reject" on a submission.
- System updates
session_submissions.status = 'rejected'. - Streamer can resubmit (no enforcement on retry count — F open).
| Test | Assertion |
|---|---|
| — | not yet automated |
→ Product Guide: Delivery Review · Payment Withdrawal · Refund
UC-7 · Earnings Tracking (Streamer)
UC-7.1 · View Earnings Dashboard
Actor: Streamer Preconditions: Authenticated.
Flow:
- Streamer opens
/profile/dashboard. - System fetches
payout_recordsfor the streamer (GET /api/streamers/:username/payouts). - Dashboard shows:
- Total Earned (sum of all
payout_records.amount_usdc) - Earned This Month (filtered by current month)
- In Escrow (sum of approved allocations not yet confirmed)
- Pending (count of pending submissions)
- Recent activity feed
- Total Earned (sum of all
| Test | Assertion |
|---|---|
| — | not yet automated — read-only aggregation |
UC-7.2 · View Application / Payout History
Actor: Streamer
Flow:
- Streamer opens
/profile/applications. - All applications listed with campaign name, status, allocation amount, confirmed amount.
- Streamer can expand each application to see submission-level detail and payout records.
| Test | Assertion |
|---|---|
| — | not yet automated — read-only list |
→ Product Guide: Profile
UC-8 · Streamer Profile & Verification
UC-8.1 · Streamer Registration
Actor: Public Preconditions: None, or operator has a funded account to view the streamer directory.
Flow:
- User opens
/streamer-signup. - Enters username, email, country, and languages.
- Verifies email via 4-digit PIN.
- Optionally connects Kick account via OAuth (links
streamer_channelsrow and populates Kick fields). - System creates
streamersrow (status =pending).
Postconditions: Account pending admin activation.
| Test | Assertion |
|---|---|
| TC-AUTH-02 | PIN sent and verified for streamer email → session established |
UC-8.2 · KYC Document Upload
Actor: Streamer Preconditions: Streamer authenticated.
Flow:
- Streamer opens
/profile/kyc. - Uploads identity document and/or proof of address (JPEG/PNG, max 5MB).
- System stores to S3; creates
streamer_documentsrow. - Admin reviews documents and sets
kyc_statustoapprovedorrejectedvia admin app. - If rejected, streamer can re-upload after viewing the rejection reason.
| Test | Assertion |
|---|---|
| — | not yet automated — requires S3 or mock bucket |
UC-8.3 · Connect / Manage Wallets
Actor: Streamer
Flow:
- Streamer opens
/profile/wallet. - Connects MetaMask wallet; system saves to
streamer_addresses. - Multiple addresses supported; each can have an optional label.
- Wallet address is used as payout destination in
payout_records.
| Test | Assertion |
|---|---|
| TC-NEG-04 ⚠️ | streamer_addresses row read at deal funding — wallet snapshotted correctly; CRUD not tested |
UC-8.4 · Update Profile & Deal Preferences
Actor: Streamer
Flow:
- Streamer opens
/profile/personal. - Edits personal info (country, languages) and streaming preferences (categories, GEOs, deal types, rates).
- Updates operator-facing bio.
- System issues
PUT /api/streamers/:username.
| Test | Assertion |
|---|---|
| — | not yet automated |
UC-8.5 · View Trust Score
Actor: Streamer / Public
Flow:
- Streamer opens
/trust-scoreor operator views/s/:username. - System displays trust score breakdown across 5 components: channel age, followers, stream frequency, avg viewers, engagement.
- Improvement suggestions displayed per pillar.
- Score is recomputed from
streamer_trust_scoresvia the poller/webhook pipeline.
| Test | Assertion |
|---|---|
| — | not yet automated — score computed externally by poller |
→ Product Guide: Registration & Onboarding · Profile · Wallet · Trust Score
UC-9 · Streamer Discovery (Operator)
UC-9.1 · Browse Streamer Directory
Actor: Operator Preconditions: Operator authenticated. Access is gated — redirects to /entry if not an operator.
Access to the streamer directory is tiered by whether the operator has at least one campaign with status funded or in_progress.
Tier 1 — No funded campaign (anonymous preview)
- Operator opens
/streamers. - System detects no
fundedorin_progresscampaign for this operator. - API returns an anonymised streamer list: follower count, engagement score, trust score, verified badge, platform icons, categories, and approximate price bracket.
- Username, bio, contact handles, country, and all identifying fields are withheld by the API.
- Free-text search is disabled.
- Each card shows a "Fund a campaign to unlock full profiles" CTA.
- Clicking a streamer card or navigating to
/s/:usernamereturns403.
Tier 2 — At least one funded campaign (full directory)
- Operator opens
/streamers. - System detects at least one
fundedorin_progresscampaign. - API returns full profiles: username, bio, country, languages, streaming categories, deal preferences, trust score, follower count, verification badge, platforms.
- Free-text search across username and categories is enabled.
- Operator can filter by platform (Kick / Twitch) and streaming category.
- Streamer cards show all public profile fields. Exact pricing is never shown — see UC-9.3.
- Operator can click through to the full public profile at
/s/:username(see UC-9.2).
Note: The invite flow (operator sends a direct deal offer) is a separate proposal — see the offer flow (UC-4.4).
| Test | Assertion |
|---|---|
| — | not yet automated — tier-gating logic and list response |
UC-9.2 · View Streamer Public Profile
Actor: Operator (Tier 2 only) Preconditions: Operator authenticated and has at least one funded or in_progress campaign.
Flow:
- Operator clicks a streamer card on
/streamersor navigates directly to/s/:username. - System checks the operator's tier. If Tier 1, returns
403with body:{ "error": "Fund a campaign to view full streamer profiles." } - For Tier 2 operators, system returns the full public profile:
- Avatar, username, verified badge, trust score
- Bio (operator-facing), country, languages
- Streaming categories, platform handles
- Deal type preferences, price bracket (not exact rate — see UC-9.3)
- Follower count, engagement score, live status
- Operator can initiate the invite flow from this page (future — see proposal).
| Test | Assertion |
|---|---|
| — | not yet automated — read-only + tier guard |
UC-9.3 · Pricing Display Rules
Actor: Operator, System Preconditions: Streamer has set deal_cpa_rate and/or deal_revshare_rate.
Rule: Exact streamer rates are never surfaced in the directory or on public profiles.
Flow:
- The API maps each streamer's rate fields to a price bracket (e.g.
$100–500 / stream). - The bracket is shown on streamer cards (Tier 2) and on the public profile.
- Exact figures are revealed only after:
- a. A campaign application is
approved, AND - b. An HTLC allocation (
allocation_preimagesrow) has been created for that application.
- a. A campaign application is
- Once both conditions are met, the operator's allocation panel shows the agreed amount.
Example bracket mapping:
| Rate range (USDC/stream) | Display bracket |
|---|---|
| 0–100 | < $100 |
| 100–500 | $100–500 |
| 500–2 000 | $500–2k |
| 2 000–10 000 | $2k–10k |
| > 10 000 | $10k+ |
| Test | Assertion |
|---|---|
| — | not yet automated — bracket mapping logic |
→ Product Guide: Dashboard & Streamer Discovery
UC-10 · Fund Breakdown Monitoring (Operator)
UC-10.1 · View Campaign Fund Breakdown
Actor: Operator
Flow:
- Operator opens
/operator/campaignsor/operator/active. - Each campaign card shows a
FundDonutchart with four segments:- Rewarded — confirmed payout_records sum
- Escrowed — approved allocation_amount minus rewarded
- Refunded — refunded allocation_amount
- Unallocated — remainder of budget_cap_usdc
- Detail panel shows the donut with legend and exact amounts.
| Test | Assertion |
|---|---|
| — | not yet automated — read-only aggregation |
→ Product Guide: Fund Deposit
UC-11 · Admin Operations
UC-11.1 · Impersonate Streamer / Operator
Actor: Admin
Flow:
- Admin creates an impersonation token via admin app (stored in
impersonation_tokenstable). - Admin opens
/auth/impersonate?token=UUID. - System validates token (single-use, time-limited).
- Session is established for the target account.
- Impersonation banner is displayed across all pages for the duration of the session.
| Test | Assertion |
|---|---|
| — | not yet automated — admin-only, single-use token |
UC-11.2 · Manage Invitations
Actor: Admin (via admin app at admin.verifluence.io)
Flow:
- Admin creates
invitationsrow with target email. - System emails the invitation link to the operator.
- Admin can view invitation status (pending / used / expired).
| Test | Assertion |
|---|---|
| — | not yet automated — admin-only |
→ Admin portal at
admin.verifluence.io(no product guide page — internal tool only)
UC-12 · Deal Negotiation
Status: Implemented — see UC-4B for the full negotiation and deal funding flow.
The Offer / Negotiation / Deal entity model replaces the earlier prototype described here. Minimum term floors are set per campaign (not per streamer); both operator- and streamer-initiated offers are supported via
initiated_by.
Out of Scope (Not Yet Implemented)
| Feature | Status |
|---|---|
Delivery entities (session_submissions, payout_records) remapped to deal_id | Migration 0079 — pending |
| Campaign Paused / Archived status | Not built |
| Application auto-complete on last slot confirmed | Bug (F-3) |
| Slot index validation against allocation | Bug (F-5) |
| Budget cap enforcement on allocation approval | Gap (F-8) |
| Campaign Analytics (VOD metrics, conversions) | Not built |
| In-app notifications (real-time) | Not built — email only |
| Negotiation UI (frontend components) | Planned — see negotiation-ui proposal |
| Referral program | Not built |
| Dispute / mediation flow | Not built |