Skip to content
arch v1.0.0

Platform Domain Model

PostgreSQL schema after migrations 0001–0093. Last updated: April 2026.

The platform is built around a Campaign → Offer → Negotiation → Deal chain. Operators fund campaigns on-chain via HTLC escrow; streamers and operators exchange offers, negotiate five deal terms bilaterally, and execute delivery through HTLC-backed deals. D2 diagrams below show key columns and FK relationships — scroll right or zoom in on wide tables.


ER Diagram — Campaign Flow

Core business entities: who creates campaigns, who participates, and how deals are agreed.

operatorsidserialPKslugtextUNQnametextcontact_emailtextUNQstatusprepared | published | hiddenoperator_walletsidserialPKoperator_idintFKwallet_addresstextUNQconsent_versiontextinvitationsidserialPKcodetextUNQemailtextstatuspending | used | expiredoperator_idint FK → operatorscampaignsidserialPKpublic_idtextUNQoperator_idintFKnametextcategorysportsbook | casinostatusprepared | funded | in_progress | completed | cancelledbudget_cap_usdcnumeric(18,6)escrow_idtextnetwork_idtextsettingsjsonbstreamersidserialPKusernametextUNQemailtextUNQcountrytextstatuspending | active | suspended | archivedkyc_statusnot_started | pending | approved | rejectedprofile_publishedbooleandeals_publishedbooleanoffersidbigintPKpublic_idtextUNQcampaign_idintFKoperator_idintFKstreamer_idintFKinitiated_byoperator | streamerstarting_termsjsonbstatuspending | accepted | declined | withdrawnexpires_attimestamptznegotiationsidbigintPKpublic_idtextUNQoffer_idbigint FK UNIQUEFKtermsjsonbturnoperator | streamer | nullstatusin_progress | agreed | cancelledagreed_attimestamptzdealsidbigintPKpublic_idtextUNQnegotiation_idbigint FK UNIQUEFKagreed_termsjsonb (immutable snapshot)allocation_amountnumeric(18,6)allocation_idtextwallet_addresstextstatusactive | completed | refunded | cancelledredeemed byon accept (1:1)on fund (1:1)

ER Diagram — Streamer Profile

Content creator account and all linked sub-entities (channels, wallets, KYC docs, portfolio, trust score).

streamersidserialPKusernametextUNQemailtextUNQcountrytextstatustextkyc_statustextdeal_cpa_ratetextdeal_revshare_ratetextoperator_biotextstreamer_channelsidserialPKstreamer_idint FK (nullable)FKplatformkick | twitch | youtube | facebook | twitterchannel_urltextchannel_nametextverifiedbooleankick_user_idtextkick_follower_countintkick_is_livebooleantextidserialPKstreamer_idintFKwallet_addresstextverifiedbooleanstreamer_documentsidserialPKstreamer_idint FK (cascade)FKdoc_typeidentity | proof_of_addressfile_nametextstorage_keytextUNQstreamer_videosidserialPKstreamer_idint FK (cascade)FKvideo_urltexttitletextsort_orderintstreamer_trust_scoresidserialPKstreamer_idint FK (set null)FKplatformtextplatform_user_idtextUNQscorenumeric(5,2)score_channel_agenumeric(5,2)score_followersnumeric(5,2)score_stream_frequencynumeric(5,2)score_avg_viewersnumeric(5,2)score_chatter_rationumeric(5,2)computed_attimestamptz

ER Diagram — Delivery Chain

How a funded deal results in delivery proofs, operator confirmation, and on-chain payouts.

offersidbigintPKpublic_idtextUNQcampaign_idintFKstreamer_idintFKstatustextallocation_preimagesidserialPKoffer_idbigint FK UNIQUEFKallocation_idtextslotsjsonb [{slot, amount, preimage}]session_submissionsidserialPKpublic_idtextUNQoffer_idbigintFKslot_indexintattemptint (1-based)statuspending_review | confirmed | rejectedstream_urltextsubmitted_attimestamptzreviewed_attimestamptzpayout_recordsidserialPKoffer_idbigintFKsubmission_idintFKslot_indexintamount_usdcnumeric(18,6)tx_hashtextwallet_addresstextconfirmed_attimestamptzkick_stream_sessionsidserialPKkick_user_idtextstream_started_attimestamptzended_attimestamptzavg_viewersintpeak_viewersintavg_chattersintmeasurement_countintkick_streamer_probeidserialPKkick_user_idtextviewer_countintstream_started_attimestamptzrecorded_attimestamptzHTLC preimages (1:1)delivery proofson confirmper-minute probes

Status Machines

Campaign

preparedfundedin_progresscancelledcompletedescrow depositconfirmed on-chainfirst deal activeall deals settledoperator cancels

Offer

pendingaccepteddeclinedwithdrawnexpirednegotiation_createdreceiving partyacceptsreceiving partydeclinesinitiating partycancelspast expires_at(lazy)automatic

Negotiation

in_progressagreedcancelledall 5 terms:op_ok && str_okeither partycancels

Deal

activecompletedrefundedcancelledall slots confirmed& paid outoperator recoversunspent funds

Streamer

pendingactivesuspendedarchivedadmin verifies

Session Submission

pending_reviewconfirmedrejectedpayout_createdoperator confirms→ payout_record insertedoperator rejects→ streamer may resubmitautomatic

Table Reference

operators

ColumnTypeConstraints
idSERIALPK
slugTEXTUNIQUE NOT NULL
nameTEXTnullable
contact_emailTEXTNOT NULL
statusTEXTprepared · published · hidden
created_at / updated_atTIMESTAMPTZ

operator_wallets

ColumnTypeNotes
idSERIALPK
operator_idINTFK → operators
wallet_addressTEXTUNIQUE
consent_versionTEXTT&C version at time of connection
connected_atTIMESTAMPTZ

invitations

ColumnTypeNotes
idSERIALPK
codeTEXTUNIQUE hex token
email / nameTEXTIntended recipient
statusTEXTpending · used · expired
operator_idINTFK → operators (set on redeem)
created_byTEXTAdmin identifier
created_at / used_atTIMESTAMPTZ

campaigns

ColumnTypeNotes
idSERIALPK
public_idTEXTUNIQUE · C-XXXXXX (IS-10)
operator_idINTFK → operators
nameTEXT
categoryTEXTsportsbook · casino
statusTEXTsee state machine
budget_cap_usdcNUMERIC(18,6)Total escrow ceiling
escrow_id / network_id / funding_addressTEXTOn-chain identifiers
settingsJSONBVersioned rich config (§ Campaign Settings)
start_date / end_dateTEXTYYYY-MM-DD
minimum_termsJSONBNegotiation floor values per term
created_at / updated_atTIMESTAMPTZ

Campaign Settings JSONB (version "0.1")

KeyTypeNotes
versionstring"0.1"
geosstring[]Target audience GEO codes
spots_totalnumberMax simultaneous streamers
payout_modelstringfixed · fixed+rs
payout_bracketsobject[]{condition, amount} per viewer tier
brief_summarystringOperator brief shown to streamers
deliverables / brand_dos / brand_dontsstring[]Content guidelines
application_deadlinestringISO date

streamers

ColumnTypeNotes
idSERIALPK
username / emailTEXTUNIQUE NOT NULL
countryTEXTISO-3166
statusTEXTpending · active · suspended · archived
kyc_statusTEXTnot_started · pending · approved · rejected
deal_cpa_rate / deal_revshare_rateTEXTWithheld by API until allocation context
profile_published / deals_publishedBOOLEANVisibility flags
created_at / updated_atTIMESTAMPTZ

Streamer Visibility Rules

RuleConditionBehaviour
A — Streamer isolationAny streamer session/api/streamers and /:username return 403
B — Operator tierNo funded/in-progress campaignAnonymised list only; /:username returns 403
B — Operator tierAt least one funded/in-progress campaignFull profile fields returned
C — PricingAlwaysdeal_cpa_rate / deal_revshare_rate replaced with computed price_bracket

streamer_channels

ColumnTypeNotes
idSERIALPK
streamer_idINTFK → streamers (nullable — unregistered streamers tracked by kick_user_id)
platformTEXTkick · twitch · youtube · facebook · twitter
channel_url / channel_nameTEXTchannel_name stored lowercase
verifiedBOOLEAN
kick_user_id / kick_follower_count / kick_is_livevariousKick profile snapshot
twitter_user_id / twitter_follower_countvariousX profile snapshot

UNIQUE on (streamer_id, platform, channel_url).

streamer_addresses

EVM wallet addresses for HTLC payouts. UNIQUE on (streamer_id, wallet_address).

streamer_documents

KYC uploads. storage_key is UNIQUE (S3 object key). streamer_id CASCADE on delete.

streamer_trust_scores

Latest trust score per (platform, platform_user_id) — UNIQUE. Full history in streamer_trust_score_history.

Score componentColumn
Overallscore NUMERIC(5,2)
Channel agescore_channel_age
Followersscore_followers
Stream frequencyscore_stream_frequency
Avg viewersscore_avg_viewers
Chatter ratioscore_chatter_ratio

Weights and benchmark pool are configurable via app_settings.trust_score_config.

offers

ColumnTypeNotes
idBIGINT IDENTITYPK
public_idTEXTUNIQUE · OFF-XXXXXX (IS-10)
campaign_id / operator_id / streamer_idINTFKs
initiated_byTEXToperator · streamer
starting_termsJSONBPre-seeded term values, nullable
statusTEXTsee state machine
expires_atTIMESTAMPTZOperator-initiated only; null for streamer-initiated
created_at / updated_atTIMESTAMPTZ

Partial UNIQUE index on (campaign_id, streamer_id) WHERE status IN ('pending', 'accepted').

negotiations

ColumnTypeNotes
idBIGINT IDENTITYPK
public_idTEXTUNIQUE · NEG-XXXXXX
offer_idBIGINTFK UNIQUE → offers (1:1)
termsJSONB{termKey: {value, proposed_by, op_ok, str_ok}}
turnTEXToperator · streamer · NULL when agreed
statusTEXTin_progress · agreed · cancelled
agreed_atTIMESTAMPTZ

Five negotiated terms

Term keyWhat it governs
timeframe_daysCampaign window length in days
deliveriesNumber of qualifying streams to deliver
min_viewersMinimum average concurrent viewers per stream
min_durationMinimum stream length in hours
payment_per_streamUSDC paid per confirmed stream

A term is agreed when op_ok && str_ok. Proposing a new value resets the other party's flag.

deals

ColumnTypeNotes
idBIGINT IDENTITYPK
public_idTEXTUNIQUE · D-XXXXXX
negotiation_idBIGINTFK UNIQUE → negotiations (1:1)
agreed_termsJSONBImmutable flat snapshot at funding time
allocation_id / escrow_id / network_id / funding_addressTEXTOn-chain identifiers
allocation_amountNUMERIC(18,6)Total USDC locked
wallet_addressTEXTStreamer wallet snapshotted at funding time
statusTEXTactive · completed · refunded · cancelled

kick_stream_sessions

One row per distinct Kick broadcast, keyed by (kick_user_id, stream_started_at). Not linked to streamers by FK — join via streamer_channels.kick_user_id.

kick_streamer_probe

Per-minute viewer/follower/subscription snapshots for active broadcasts. Source data for trust score computation and delivery verification.

allocation_preimages

HTLC preimage set per offer. offer_id is UNIQUE (1:1). slots JSONB holds [{slot, amount, preimage}] — raw preimages for operator to reveal per confirmed slot.

session_submissions

ColumnTypeNotes
idSERIALPK
public_idTEXTUNIQUE · SS-XXXXXX
offer_idBIGINTFK → offers
slot_indexINT0-based HTLC slot index
attemptINT1-based; multiple attempts allowed per slot
statusTEXTpending_review · confirmed · rejected
stream_urlTEXTVOD/stream link
submitted_at / reviewed_atTIMESTAMPTZ

payout_records

Permanent confirmed-payout ledger. UNIQUE on (offer_id, slot_index).

ColumnTypeNotes
idSERIALPK
offer_idBIGINTFK → offers
submission_idINTFK → session_submissions
slot_indexINT
amount_usdcNUMERIC(18,6)Exact payout amount
allocation_idTEXTOn-chain allocation identifier
tx_hashTEXTwithdraw() on-chain tx; NULL until confirmed
wallet_addressTEXTSnapshot at confirmation time
confirmed_at / tx_confirmed_atTIMESTAMPTZ

End-to-End Flow

Operator creates Campaign (prepared)Operator funds escrow on-chain→ Campaign (funded)Path A — Streamer-initiatedStreamer sends Offer (pending)Operator accepts → Offer (accepted)Path B — Operator-initiatedOperator sends Offer (pending)Streamer accepts → Offer (accepted)Negotiation created automatically (in_progress)5 terms proposed & approved bilaterallyAll terms agreed → Negotiation (agreed)Operator funds Deal on-chainHTLC allocation locked → Deal (active)Streamer streams → SessionSubmission (pending_review)Operator confirms→ PayoutRecord insertedPreimage revealed → streamer calls withdraw()Operator rejects→ Streamer resubmitsAll slots confirmed → Deal (completed)new attempt

Known Data Quality Notes

#TableIssue
F-2session_submissionsNo FK to kick_stream_sessions — platform session not joined to submission at review time
F-3dealsAuto-complete to completed on last slot confirmed not yet implemented
F-5session_submissionsslot_index not validated against allocation_preimages.slots array length

Verifluence Documentation