Skip to content
arch v1.0.0

Verifluence — Implemented Use Cases

Documents the currently working use cases derived from API handlers, DB schema, and frontend pages. Last updated: March 2026.


Actors

ActorDescription
PublicUnauthenticated visitor
StreamerAuthenticated content creator
OperatorAuthenticated casino / sportsbook company
AdminPlatform 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:

  1. Operator opens /entry?invitation=CODE.
  2. System validates the invitation code (status = pending).
  3. Operator enters display name; slug is auto-generated from the name.
  4. Operator accepts T&C consent.
  5. System creates an operators row (status = prepared) and marks the invitation used.
  6. Operator is redirected to /operator/account.

Postconditions: Operator account exists with status prepared. Admin must change status to published to grant full access.

TestAssertion
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:

  1. Operator opens /operator/wallet.
  2. Operator clicks "Connect Wallet"; MetaMask prompts for signature.
  3. System records operator_wallets row with wallet address and current consent version.
  4. Multiple wallets can be connected; each is stored independently.

Postconditions: Wallet address available for on-chain campaign funding.

TestAssertion
not yet automated — on-chain / MetaMask, not API-testable

UC-1.3 · Operator Sign In

Actor: Operator Preconditions: Operator account exists.

Flow:

  1. Operator visits any /operator/* page.
  2. If not authenticated, system redirects to /signin2.
  3. Operator enters registered email; system sends a 4-digit PIN via email.
  4. Operator enters PIN; session cookie is set.
  5. Operator is redirected to original destination or /operator/account.
TestAssertion
TC-AUTH-01Happy 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:

  1. Operator opens /operator/campaigns and clicks "New Campaign".
  2. 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
  3. System creates a campaigns row with status = prepared and settings JSONB.

Postconditions: Campaign in Draft state. Not visible to streamers.

TestAssertion
not yet automated

UC-2.2 · Edit Campaign

Actor: Operator Preconditions: Campaign exists with status prepared.

Flow:

  1. Operator selects campaign in the list; clicks "Edit".
  2. Form is pre-populated with existing data.
  3. Operator modifies any allowed fields and saves.
  4. System issues PUT /api/campaigns/:id.

Constraints: Edit is allowed only for Draft campaigns. Once funded, edits are not available through the UI.

TestAssertion
not yet automated

UC-2.3 · Delete Campaign

Actor: Operator Preconditions: Campaign status is prepared.

Flow:

  1. Operator clicks "Remove" in the campaign detail panel.
  2. System issues DELETE /api/campaigns/:id.
  3. Campaign row is hard-deleted.

Constraints: Only prepared campaigns can be deleted (API enforced).

TestAssertion
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:

  1. Operator opens campaign detail panel on /operator/campaigns.
  2. FundCampaignPanel displays escrow deposit form (amount, network, timelock).
  3. Operator approves USDC spend in MetaMask, then confirms the deposit transaction.
  4. System detects on-chain confirmation; updates campaign escrow_id, network_id, funding_address, and status to funded.

Postconditions: Campaign is visible to streamers. Funds locked in HTLC contract.

TestAssertion
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:

  1. User opens /campaigns.
  2. System fetches campaigns with status funded or in_progress from the API.
  3. User can filter by tag (Beginner friendly, High budget, Closing soon) and sort (Featured, Highest budget, Newest).
  4. 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.

TestAssertion
not yet automated — read-only list endpoint

UC-3.2 · View Campaign Detail

Actor: Public / Streamer

Flow:

  1. User opens /campaign/:id.
  2. System fetches campaign details.
  3. Unauthenticated users see full public info with a sign-in CTA.
  4. Authenticated streamers see an application card (apply / already applied / approved).
  5. Tabbed sections: Overview, Requirements, Reward.
TestAssertion
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:

  1. Streamer clicks "Apply" on the campaign detail page or card.
  2. Offer form shows five deal term fields pre-filled from the campaign's minimal_terms.
  3. Streamer adjusts values and optionally adds a pitch message.
  4. System validates all starting terms are ≥ campaign floor values.
  5. System creates an offers row with initiated_by = 'streamer', status = 'pending', and no expiry (streamer offers do not expire).
  6. 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).
TestAssertion
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:

  1. Streamer opens /profile/offers.
  2. Clicks "Withdraw" on a pending offer.
  3. System issues PATCH /api/offers/:id with action = 'withdraw'.
TestAssertion
TC-OFFER-04revoke_decline blocked by uq_offer_active when conflict exists → 409
TC-OFFER-05revoke_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:

  1. Operator opens /operator/active and selects a campaign.
  2. System fetches offers for the campaign via GET /api/campaigns/:id/offers.
  3. Offers listed with streamer username, Trust Score, starting terms, and current status.
TestAssertion
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:

  1. Operator selects a pending offer and clicks "Accept".
  2. System issues PATCH /api/offers/:id with action = 'accept'.
  3. API transitions offer status to accepted.
  4. API auto-creates a negotiations row seeded from the offer's starting_terms, with offer_id set and initial turn = 'operator' (since streamer proposed).
  5. Both parties are notified.

Postconditions: Negotiation exists with status in_progress.

TestAssertion
TC-OFFER-02Duplicate accept is idempotent or returns 409 — offer never left in inconsistent state

UC-4.3 · Decline Offer

Actor: Operator

Flow:

  1. Operator clicks "Decline" on a pending offer.
  2. System issues PATCH /api/offers/:id with action = 'decline'.
  3. Offer transitions to declined. Streamer can re-apply.
TestAssertion
TC-OFFER-03action = 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:

  1. Operator opens a streamer's public profile at /s/:username.
  2. Clicks "Send Offer" and selects a campaign.
  3. Offer form shows five deal term fields pre-filled from campaign.minimal_terms.
  4. Operator adjusts values, adds an optional message, and sets an expiry date (default: 7 days).
  5. System validates starting terms ≥ campaign floors.
  6. System creates offers row with initiated_by = 'operator', status = 'pending', expires_at set.
  7. 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.

TestAssertion
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:

  1. Actor opens the negotiation panel and sees all five terms with current proposed values and approval states.
  2. Approve — Actor clicks "Approve" on a term they agree with.
    • System sets op_ok or str_ok = true on that term.
  3. Propose — Actor enters a new value for a term.
    • System updates value and proposed_by.
    • Resets the other party's ok flag to false on that term.
  4. After either action, the system checks whether all five terms have both op_ok = true and str_ok = true.
  5. If all agreed → negotiation status transitions to agreed; agreed_at is recorded.
  6. Otherwise → turn advances to the other party.

Constraints: Values must remain ≥ campaign floor values throughout negotiation.

TestAssertion
TC-NEG-01Streamer 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:

  1. Actor clicks "Cancel Negotiation".
  2. System issues POST /api/negotiations/:id/cancel.
  3. Negotiation transitions to cancelled. A new offer can be created to restart.
TestAssertion
not yet automated

UC-4B.3 · Fund Deal

Actor: Operator Preconditions: Negotiation status = agreed.

Flow:

  1. Operator opens the agreed negotiation and clicks "Fund Deal".
  2. System confirms the negotiation is agreed and the operator is the correct party.
  3. Operator supplies on-chain parameters (escrow ID, network, funding address, allocation ID and amount).
  4. Operator signs the HTLC allocation transaction in MetaMask.
  5. System creates a deals row with:
    • negotiation_id FK
    • agreed_terms — immutable JSONB snapshot of the five negotiated values
    • On-chain fields (escrow_id, network_id, funding_address, allocation_id, allocation_amount)
    • status = 'active'
  6. Both parties notified. Streamer's delivery panel becomes active.

Postconditions: Deal exists and is active. Agreed terms are permanently frozen.

TestAssertion
TC-NEG-02allocation_amount exceeds budget cap → 409
TC-NEG-03allocation_amount within budget cap → 201, status = active
TC-NEG-04wallet_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:

  1. Streamer opens /profile/campaigns.
  2. Selects approved campaign and an available slot.
  3. Pastes stream/VOD URL.
  4. Optionally selects a tracked Kick session from the dropdown.
  5. Clicks "Submit".
  6. System creates session_submissions row (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).

TestAssertion
TC-DEL-01slot_index outside allocation range → 400, error lists valid indices
TC-DEL-02Valid slot_index → 201, status = pending_review, attempt = 1
TC-DEL-03Slot 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:

  1. Operator opens /operator/active.
  2. Submission listed under the relevant application.
  3. Operator reviews stream URL and any notes.
  4. Operator clicks "Confirm" or "Reject".
TestAssertion
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:

  1. Operator confirms submission.
  2. API:
    • Checks kyc_status = 'approved' on streamer. Returns 403 if not.
    • Reads per-slot amount from allocation_preimages.slots[slot_index].
    • Inserts payout_records row with amount, wallet snapshot, allocation_id.
    • Updates session_submissions.status = 'confirmed'.
  3. Operator retrieves preimage for the slot (stored in allocation_preimages).
  4. Operator sends preimage to streamer off-platform (or automated via payout_type = automatic).
  5. Streamer calls withdraw() on-chain using the preimage.
  6. Streamer (or frontend) submits tx hash via PATCH /api/session-submissions/:id/tx.

Postconditions: payout_records row has tx_hash. Streamer has received USDC.

TestAssertion
TC-DEL-04Confirming last slot → deals.status = completed (auto-complete regression)
TC-DEL-05Confirming partial slot → deals.status remains active
TC-DEL-06Streamer KYC not approved → confirmation blocked with 403

UC-6.3 · Reject Submission

Actor: Operator

Flow:

  1. Operator clicks "Reject" on a submission.
  2. System updates session_submissions.status = 'rejected'.
  3. Streamer can resubmit (no enforcement on retry count — F open).
TestAssertion
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:

  1. Streamer opens /profile/dashboard.
  2. System fetches payout_records for the streamer (GET /api/streamers/:username/payouts).
  3. 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
TestAssertion
not yet automated — read-only aggregation

UC-7.2 · View Application / Payout History

Actor: Streamer

Flow:

  1. Streamer opens /profile/applications.
  2. All applications listed with campaign name, status, allocation amount, confirmed amount.
  3. Streamer can expand each application to see submission-level detail and payout records.
TestAssertion
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:

  1. User opens /streamer-signup.
  2. Enters username, email, country, and languages.
  3. Verifies email via 4-digit PIN.
  4. Optionally connects Kick account via OAuth (links streamer_channels row and populates Kick fields).
  5. System creates streamers row (status = pending).

Postconditions: Account pending admin activation.

TestAssertion
TC-AUTH-02PIN sent and verified for streamer email → session established

UC-8.2 · KYC Document Upload

Actor: Streamer Preconditions: Streamer authenticated.

Flow:

  1. Streamer opens /profile/kyc.
  2. Uploads identity document and/or proof of address (JPEG/PNG, max 5MB).
  3. System stores to S3; creates streamer_documents row.
  4. Admin reviews documents and sets kyc_status to approved or rejected via admin app.
  5. If rejected, streamer can re-upload after viewing the rejection reason.
TestAssertion
not yet automated — requires S3 or mock bucket

UC-8.3 · Connect / Manage Wallets

Actor: Streamer

Flow:

  1. Streamer opens /profile/wallet.
  2. Connects MetaMask wallet; system saves to streamer_addresses.
  3. Multiple addresses supported; each can have an optional label.
  4. Wallet address is used as payout destination in payout_records.
TestAssertion
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:

  1. Streamer opens /profile/personal.
  2. Edits personal info (country, languages) and streaming preferences (categories, GEOs, deal types, rates).
  3. Updates operator-facing bio.
  4. System issues PUT /api/streamers/:username.
TestAssertion
not yet automated

UC-8.5 · View Trust Score

Actor: Streamer / Public

Flow:

  1. Streamer opens /trust-score or operator views /s/:username.
  2. System displays trust score breakdown across 5 components: channel age, followers, stream frequency, avg viewers, engagement.
  3. Improvement suggestions displayed per pillar.
  4. Score is recomputed from streamer_trust_scores via the poller/webhook pipeline.
TestAssertion
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)

  1. Operator opens /streamers.
  2. System detects no funded or in_progress campaign for this operator.
  3. API returns an anonymised streamer list: follower count, engagement score, trust score, verified badge, platform icons, categories, and approximate price bracket.
  4. Username, bio, contact handles, country, and all identifying fields are withheld by the API.
  5. Free-text search is disabled.
  6. Each card shows a "Fund a campaign to unlock full profiles" CTA.
  7. Clicking a streamer card or navigating to /s/:username returns 403.

Tier 2 — At least one funded campaign (full directory)

  1. Operator opens /streamers.
  2. System detects at least one funded or in_progress campaign.
  3. API returns full profiles: username, bio, country, languages, streaming categories, deal preferences, trust score, follower count, verification badge, platforms.
  4. Free-text search across username and categories is enabled.
  5. Operator can filter by platform (Kick / Twitch) and streaming category.
  6. Streamer cards show all public profile fields. Exact pricing is never shown — see UC-9.3.
  7. 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).

TestAssertion
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:

  1. Operator clicks a streamer card on /streamers or navigates directly to /s/:username.
  2. System checks the operator's tier. If Tier 1, returns 403 with body: { "error": "Fund a campaign to view full streamer profiles." }
  3. 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
  4. Operator can initiate the invite flow from this page (future — see proposal).
TestAssertion
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:

  1. The API maps each streamer's rate fields to a price bracket (e.g. $100–500 / stream).
  2. The bracket is shown on streamer cards (Tier 2) and on the public profile.
  3. Exact figures are revealed only after:
    • a. A campaign application is approved, AND
    • b. An HTLC allocation (allocation_preimages row) has been created for that application.
  4. 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+
TestAssertion
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:

  1. Operator opens /operator/campaigns or /operator/active.
  2. Each campaign card shows a FundDonut chart with four segments:
    • Rewarded — confirmed payout_records sum
    • Escrowed — approved allocation_amount minus rewarded
    • Refunded — refunded allocation_amount
    • Unallocated — remainder of budget_cap_usdc
  3. Detail panel shows the donut with legend and exact amounts.
TestAssertion
not yet automated — read-only aggregation

→ Product Guide: Fund Deposit


UC-11 · Admin Operations

UC-11.1 · Impersonate Streamer / Operator

Actor: Admin

Flow:

  1. Admin creates an impersonation token via admin app (stored in impersonation_tokens table).
  2. Admin opens /auth/impersonate?token=UUID.
  3. System validates token (single-use, time-limited).
  4. Session is established for the target account.
  5. Impersonation banner is displayed across all pages for the duration of the session.
TestAssertion
not yet automated — admin-only, single-use token

UC-11.2 · Manage Invitations

Actor: Admin (via admin app at admin.verifluence.io)

Flow:

  1. Admin creates invitations row with target email.
  2. System emails the invitation link to the operator.
  3. Admin can view invitation status (pending / used / expired).
TestAssertion
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)

FeatureStatus
Delivery entities (session_submissions, payout_records) remapped to deal_idMigration 0079 — pending
Campaign Paused / Archived statusNot built
Application auto-complete on last slot confirmedBug (F-3)
Slot index validation against allocationBug (F-5)
Budget cap enforcement on allocation approvalGap (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 programNot built
Dispute / mediation flowNot built

Verifluence Documentation