1 Change Orders
2 File Dispute
3 Resolution
Create Change Order Contractor
9:41
Request Change Order
Current Contract
Kitchen Remodel — Phase 2
HomeownerSarah Mitchell
Contract Amount$12,400.00
Timeline14 days
What needs to change?
Reason for Change
Additional Work Discovered Material Upgrade Scope Expansion Weather Delay
Price Adjustment
+
$
Updated Timeline
+
days
Photo Evidence *
Submit Change Order

ContractorChangeOrderScreen — create mode

useMutation(api.jobs.changeOrders.create), MediaUpload component

Review Change Order Poster
9:41
Change Order
Change Order Requested by Contractor
Order Number
CO-01
Pending Review

JobKitchen Remodel — Phase 2
ContractorMike's Renovation Co.
SubmittedFeb 22, 2026
Scope Comparison
Original Scope
Remove existing backsplash, install new subway tile backsplash with accent border, replace under-cabinet lighting.
Proposed Changes
Replace water-damaged drywall (approx 18 sq ft), apply moisture barrier, then install new subway tile backsplash with accent border and under-cabinet lighting.
Cost Impact
Original
$12,400
New Total
$14,250
Additional Cost+$1,850.00
Timeline Impact
Original
14 days
New Timeline
19 days
Timeline Change+5 days
Contractor's Evidence
Decline
Approve

PosterChangeOrderScreen — review mode

useMutation(api.jobs.changeOrders.approve / reject), ConfirmationDialog

Change Order History Both
9:41
Change Orders
Original Contract
$12,400.00
Current Total
$14,650.00
Net Change +$2,250.00
CO-01
Approved
Water damage repair behind backsplash — drywall replacement and moisture barrier
Amount+$1,850.00
DateFeb 22, 2026
CO-02
Pending
Upgrade cabinet hardware from brushed nickel to matte black
Amount+$400.00
DateFeb 24, 2026
CO-03
Declined
Extend kitchen island by 12 inches with additional granite countertop
Amount+$2,800.00
DateFeb 18, 2026

ChangeOrderHistoryScreen

useQuery(api.jobs.changeOrders.listByJob), audit trail pattern


File Dispute Poster
9:41
File Dispute
Step 1 of 5
Select Job
Kitchen Remodel — Phase 2
Mike's Renovation Co. · $14,250
Dispute Category
Quality Issue Timeline Missed Incomplete Work Communication Billing Discrepancy
Describe the Issue
Photo Evidence *
Desired Resolution
Partial Refund Full Refund Redo Work Mediation
Requested Amount
$
Submit Dispute

CreateDisputeScreen — Typeform wizard

useMutation(api.features.disputes.createDispute), MediaUpload, 5-step flow

Dispute Confirmation Poster
9:41
Dispute Filed
Case #DIS-000042
What Happens Next
Dispute Filed
Completed just now
Admin Reviews
Within 48 hours
Both Parties Respond
Contractor will be notified
Resolution Proposed
Fair resolution for both parties
Escrow Action
Funds released or refunded
View Dispute

SuccessScreen (inline component)

Navigation: router.replace to dispute detail

Dispute Detail Poster
9:41
Dispute #DIS-000042
#DIS-000042
Under Review
Status
Filed
Feb 22, 2026 · 2:14 PM
Under Review
Admin assigned · Est. 24h
Awaiting Response
Pending
Resolution
Pending
Closed
Pending
Case Details
CategoryQuality Issue
Amount$2,400.00
ResolutionPartial Refund
JobKitchen Remodel
ContractorMike's Renovation Co.
Evidence Submitted
3 files attached
Communication
A
SupportFeb 23, 10:30 AM
We've received your dispute and assigned it to our review team. We'll notify the contractor and request their response within 48 hours.
S
YouFeb 23, 11:15 AM
Thank you. I also have a text message from the contractor acknowledging the issue — should I upload that?

DisputeDetail (app/disputes/[id].tsx)

useQuery(api.features.disputes.getDisputeDetail), real-time messages

Dispute Response Contractor
9:41
Respond to Dispute
A dispute has been filed against you for Kitchen Remodel
Dispute #DIS-000042
Filed by Sarah Mitchell · Feb 22, 2026

CategoryQuality Issue
ClaimCracked tiles, grout inconsistencies
RequestedPartial Refund — $2,400
Your Response
Counter Evidence
Your Resolution Offer
Partial refund amount you're willing to offer:
$
Only for the grout rework, not the tile damage
Submit Response

DisputeResponseScreen (contractor-side)

useMutation(api.features.disputes.addResponse), counter-evidence upload


Resolution Proposed Both
9:41
Dispute #DIS-000042
Admin has proposed a resolution
Respond within 47 hours, 23 minutes
Proposed Resolution
From 3Bids Review Team
Recommended Action
After reviewing evidence from both parties, we recommend a partial refund of $1,200 to the homeowner. The grout inconsistencies are confirmed and warrant rework. However, the tile damage appears to have occurred after project completion based on the contractor's timestamped walkthrough photos.
Refund Breakdown
Grout Rework$800.00
Inconvenience Credit$400.00

Total Refund$1,200.00
Reasoning
The contractor's photos from the final walkthrough clearly show intact tiles. The homeowner's claim for tile replacement is not supported. The grout issue is valid and the contractor should cover rework costs.
Appeal
Accept Resolution

DisputeDetail — resolution_proposed state

useMutation(api.features.disputes.acceptResolution), 48h deadline timer

Resolved — Refund Poster
9:41
Dispute Resolved
Case #DIS-000042 has been resolved with a partial refund.
Resolution Summary
Partial refund for grout rework and inconvenience credit. Tile damage claim denied.

Refund Amount$1,200.00
Escrow Adjustment
Original Escrow$14,250.00
Refund to You-$1,200.00

Final to Contractor$13,050.00
Was this resolution fair?
Yes
No
Return to Dashboard

DisputeDetail — resolved state

Escrow adjustment via api.admin.escrow, satisfaction survey mutation

Escalated Both
9:41
Escalated to Review Board
Escalation in Progress
What Happens Now
This dispute has been escalated to the 3Bids Review Board for further investigation. A senior reviewer will evaluate all evidence from both parties.
Estimated Timeline
5–7 business days
Assigned Reviewer
David Chen
Senior Dispute Reviewer
Evidence Summary
Homeowner Evidence3 files
Contractor Evidence2 files
Admin Notes4 entries
You will be notified of the decision via email and in-app notification.
Back to Disputes

DisputeDetail — escalated state

Admin escalation via api.admin.disputes.escalate, Slack: dispute_notice channel


Data Architecture

Schema: disputes

escrowId: Id<"escrow">
jobId: Id<"jobs">
posterId: Id<"posterUsers">
contractorId: Id<"contractorUsers">
disputeNumber: string // "DIS-000001"
initiatedBy: string // poster | contractor
reason: string
description: string
status: string
  // open → under_review → awaiting_response
  // → resolution_proposed → resolved | escalated
amountInDispute: number
amountToPoster: number?
amountToContractor: number?
resolutionNotes: string?
media: Array<{storageId, type, mimeType}>
resolvedByAdminId: Id<"adminUsers">?

Schema: changeOrders

jobId: Id<"jobs">
escrowId: Id<"escrow">
changeOrderNumber: string? // "CO-01"
requestedById: string
requestedByType: string // poster | contractor
description: string
reason: string?
additionalCost: number // + or -
additionalDays: number?
status: string
  // pending_signatures → pending_funding
  // → approved | rejected | paid
media: Array<{storageId, type, mimeType}>
paymentCompleted: boolean
signedByContractorAt: number?
signedByPosterAt: number?

Hooks & Mutations

// Disputes
useQuery(api.features.disputes.getMyDisputes)
useQuery(api.features.disputes.getDisputeDetail)
useMutation(api.features.disputes.createDispute)
useMutation(api.features.disputes.addResponse)
useMutation(api.features.disputes.addEvidence)
useMutation(api.features.disputes.acceptResolution)
useMutation(api.features.disputes.withdrawDispute)

// Change Orders
useQuery(api.jobs.changeOrders.get)
useQuery(api.jobs.changeOrders.listByJob)
useMutation(api.jobs.changeOrders.create)
useMutation(api.jobs.changeOrders.approve)
useMutation(api.jobs.changeOrders.reject)
useMutation(api.jobs.changeOrders.cancel)
useMutation(api.jobs.changeOrders.markPaid)

Integrations

// Slack Alerts
Channel: dispute_notice
  → New dispute filed
  → Resolution accepted/appealed
  → Escalation triggered
Channel: ops_alerts
  → Change order created
  → Change order funded

// Escrow (refund processing)
api.admin.escrow.processRefund
api.payments.escrow.adjustForDispute

// Stripe
api.stripe.stripe.createChangeOrderPaymentIntent
api.stripe.stripe.createRefund

// Transactional Email (SendGrid)
dispute_filed → poster + contractor
dispute_resolved → both parties
change_order_submitted → poster
Changes & Disputes
9:41
Changes & Disputes
Active Cases
18
Open Cases
42
This Month
84%
Resolution
3.4d
Avg Time
Active Cases
DSP-2847 — Johnson Roof
Filed 2 days ago — Scope dispute
Open
CO-1423 — Davis Siding
Filed 5 days ago — Material upgrade
In Review
DSP-2844 — Chen Gutters
Filed 1 week ago — Timeline
Resolved
Resolution Center
9:41
Resolution Center
Details
Title
Dispute #D-1087: Incomplete Siding
Description
Homeowner claims north wall siding was not completed per contract.
Configuration
Auto-Escalate After 48h
Require Photo Evidence
Preview
Case Timeline
Full dispute history with messages, evidence uploads, and resolution steps.
Performance
91%
Resolved
2.1d
Avg Time
$850
Avg Value
Disputes Dashboard
https://app.3bids.io/admin/disputes
3Bids
Cases ⌘1
Changes ⌘2
Resolution ⌘3
Timeline ⌘4
Settings ⌘5
MK
Mike Kowalski
Contractor
Settings ⌘,

Disputes Dashboard

247
Total Cases
18
Open
92%
Resolution Rate
2.8d
Avg Resolution
Recent Activity
DSP-2847 — Johnson Roof
Filed 2 days ago — Scope dispute
CO-1423 — Davis Siding
Filed 5 days ago — Material upgrade
DSP-2844 — Chen Gutters
Filed 1 week ago — Timeline
Performance