Claims + end-to-end product flow (from Lovable source)
Source: Lovable clone
origin/main—docs/application-overview.md,docs/database-overview.md, supabase migrations, and the claims/PO hooks+pages. Researched 2026-07-09 (T74 day 1). This RECONSTRUCTS the untranscribed 2:40–40:00 walkthrough segment (claim process: PO → ready-to-claim → claims; evidence pack; sharing). Confirm details with Malcolm in daily Q&A.
What a claim IS
Framing from docs/application-overview.md:3: “FibreTrace is a credit-based traceability platform. Physical fibre is marked with a pigment, scanned at facilities along the supply chain, and those scans are metered against a Fibre Programme so participating brands can make verifiable claims about the volume they handled.”
A production claim = the moment platform credit converts into a brand-visible, verifiable statement: “our company handled X metric tonnes of traced fibre from programme Y”. Backed by production_claims (programme_id, company_id, quantity_mt, status, purchase_order_id, proposed/confirmed/rejected_* fields).
- Lifecycle:
status IN ('proposed','confirmed','rejected')(migration20260618105531). PO-linked claims: manufacturer proposes → brand confirms or rejects (rejected can be revised + re-proposed). Legacy non-PO claims default straight toconfirmed. - The claim gate —
validate_production_claim_limits(migration20260421164336:78-134): quantity must be > 0, AND ≤ company’s remaining reservation (reserved − already claimed), AND ≤ programme’s unclaimed produced volume (SUM(production_records.weight_kg)/1000 where excluded=false − total claimed). “Before it passes the gate, no claim is created.” - Sessions backing a claim:
production_claim_sessions(claim_id ↔ session_id, unique per company+session — a session is claimable once per company; matches the dashboard copy “Claimed once — retired from the pool, never re-claimable”).
Key supporting concepts
- Reservation / claim position (
programme_reservations): a brand’s PRE-allocated right to claim volume from a programme; capacity-gated byvalidate_programme_reservation_capacity(SUM(reservations) ≤ SUM(programme_producers.ceiling_mt)). UI: Claim Position pages. - Chain of custody: every shipment = TWO paired
sessionsrows joined byshipping_doc_id(case-insensitive) — outbound at sender (partner_company_id=recipient), inbound at recipient (partner_company_id=sender).src/lib/chainWalk.tswalkSupplyChainBFS (depth cap 12) walks these joins;session_shares(Tier 1 → brand) is the anchor. - PO ↔ sessions link:
purchase_order_verifications(session_id UNIQUE). Manual via LinkToPo page, or automatic via triggerauto_associate_session_to_po(session’spurchase_ordertext matches exactly one active non-fully-claimed PO of the facility’s company).validate_po_verificationenforces the session’s facility belongs to the PO’s partner company and bumps PO →ready. - Evidence pack (DB):
purchase_order_evidence_packs(purchase_order_id, claim_id, volume_mt, is_partial) — created ONLY on claim confirm; triggerapply_po_evidence_packenforces pack volume ≤ PO remaining volume and flips PO topartially_claimed/fully_claimed. - Evidence pack (UI catalogue):
src/lib/evidencePacks.ts— 8 pack keys:risk, sustainability, procurement, retailer, assurance, regulator, dpp, supplier(each with sections, audience, CTAs: export pdf/csv/json, share, copy public link, request evidence). DB seeds only 3 token pack_types on confirm:trade,sustainability,procurement;LEGACY_PACK_REDIRECTS = { trade: "regulator" }. Rendered at/claims/:claimId/evidence/:packType. - Public verification:
public_verification_tokens(token, session_id | claim_id + pack_type, enabled; unique per claim+pack). Routes:/v/:token= one session public page (session code, fibre, facility, company, date, scan count, claim status);/c/:token= one claim+pack public page (programme, quantity_mt, pack label, issuer);/verifications/webhook/:sessionId= raw JSON view (page, NOT a real outbound webhook — no HTTP push exists; SharePackModal “Send” is a toast-only mock). QR code generated client-side from the page URL viaapi.qrserver.com. Tokens can be enabled/disabled per session or per claim+pack (useConnections.ts:160-220).
End-to-end flow (actor → action → tables)
- Programme owner creates
fibre_programmes+programme_producers(per-ginceiling_mt,scans_per_mt, window) + enrolls brands asprogramme_participants. - Tier 4 producer (gin) sprays pigment + scans →
sessionsat their facility; triggerauto_associate_session_to_programmewritesprogramme_facility_scans, recomputesprogramme_producers.produced_mt(capped at ceiling). Manual path:production_records. - Each hop Tier 3 → Tier 1: sender outbound session + recipient inbound session paired by
shipping_doc_id(chain of custody). - Tier 1 shares the final verification with the brand →
session_shares. - Brand (Tier 0) reserves programme volume →
programme_reservations(capacity-gated). - Brand issues
purchase_ordersto the manufacturer (draft→shared). - Manufacturer links sessions to the PO →
purchase_order_verifications(manual LinkToPo or auto-associate); PO →ready. - Manufacturer proposes a claim →
production_claims(status='proposed'), PO →proposed, brand notified (useProposeEvidenceClaim). - Brand reviews on ReadyToClaim (
ReviewClaimProposalModal):- Confirm → claim
confirmed; insertpurchase_order_evidence_packs(trigger advances PO volume_claimed/status); copy PO’s sessions →production_claim_sessions; seed 3public_verification_tokens(trade/sustainability/procurement); notify manufacturer (useConfirmEvidenceClaim). - Reject → claim
rejected, unlink verifications, PO reverts toshared, manufacturer revises.
- Confirm → claim
- (Non-PO path) Brand claims directly against its reservation — gated by
validate_production_claim_limits. - Users view packs at
/claims/:claimId/evidence/:packType; anyone with link/QR verifies at/v/:token(session) or/c/:token(claim+pack), gated by tokenenabled.
Page → step map
- ClaimPosition / ClaimPositionList = step 5 (reservations vs ceiling/claimed).
- PurchaseOrders = step 6; LinkToPo (manufacturer: “Awaiting evidence pack” / “Awaiting brand confirmation” / “Confirmed”) = steps 7–8.
- ReadyToClaim (brand: POs with status in ready/linked/proposed/partially_claimed AND volume_claimed < volume) = step 9; Claims = confirmed claim list.
- EvidencePackDetail + SharePackModal + Connections (token toggles) = steps 11+.
UPDATE 2026-07-09 (evening): the full walkthrough capture arrived and CONFIRMS this source-derived flow end-to-end (PO → notification → partner links verifications + optional certificate → retailer confirms → claims list + packs + downloadable claim certificate with QR for customs). New concepts from Malcolm’s narration: implied chain of custody (unmatched shipping doc = unconfirmed process, still catered for), mass balance (proving fibre MOVEMENT, not bale-to-t-shirt), claim quantity = fibre component only (blended goods, per-component tax rules), partnership prerequisite for inbound scans, supply-chain page privacy (partner = name+location, non-partner = city+country only). See
2026-07-08-malcolm-walkthrough-demo.md§ Middle segment.
Open questions
- [x] Malcolm said “webhook version” in the demo — source shows only the
/verifications/webhook/:sessionIdJSON PAGE, no outbound webhook. Is a real webhook planned for BE, or is the page the deliverable? — RESOLVED (2026-07-16, source): NO real outbound webhook exists; the “Webhook” toggle only inserts averification_connectionsrow pointing at a non-existent/api/v1path, andWebhookPreview.tsxis a pull-style JSON page. Public URL/QR (/c/:token) IS real. See2026-07-16-code-resolved-open-questions.md§2.5. (Whether BE builds a real dispatcher later is still a BE decision.) - [x] 3 DB pack_types (trade/sustainability/procurement) vs 8 UI catalogue packs — which set does BE need to support? (trade→regulator redirect suggests catalogue is mid-migration.) Demo confirms procurement/sustainability/risk are “same data, different views”. — RESOLVED (2026-07-16, source):
pack_typeis plaintext(no DB enum); 3 seeded values vs 8 UI catalogue packs;LEGACY_PACK_REDIRECTS = {trade: "regulator"}, 2 map 1:1, 5 unbacked. See §2.4. (Which set BE supports is still a BE call.) - [x] Certificates attach point — ANSWERED by full capture: manufacturer can attach certificates when linking verifications to a PO (so the “transaction” ≈ the PO-verification link), and programme-owner certificates also land on evidence packs. Data model for MULTIPLE certificates per transaction still being reworked by Malcolm (tracked in the 07-08 file).
- [x] Non-PO direct claims (step 10): still a supported path in the final product, or legacy? (Demo showed ONLY the PO path; Malcolm: “to create an evidence pack… I have to have a purchase order” — suggests PO path is THE path now.) — RESOLVED (2026-07-16, source):
production_claims.purchase_order_idis nullable and legacy pages still exist DB-side, but the UI removed the legacy Claim-Position / Request-Evidence menu items for retailers — PO is the ENFORCED path. See §2.3.