⚖️ TrueTrade

Flows & Journeys

A visual map of how True Trade works — every role, journey, and money flow we've designed for the local home-services marketplace. Built to share and discuss.

Customers describe a job · interested local pros send free initial estimates · the customer compares and chooses · the platform sells customer-selected connections, not raw leads.

First launch: gardening & car wash, geo-clustered — see the Launch plan and the money decisions on Economics.

The big picture

Platform & the four roles

True Trade sits between customers and local pros. An admin curates supply and runs outreach; buildings can offer the whole thing to residents under their own brand.

Customer Pro / service provider Admin / operator Building / property manager Platform / system
flowchart LR
  C["🏠 Customer
homeowner · renter"]:::cust PRO["🔧 Local Pro
service provider"]:::pro A["🗂️ Admin
operator"]:::admin B["🏢 Building / PM
white-label"]:::bldg TT(["⚖️ True Trade"]):::sys C -->|"describe a job"| TT TT -->|"compare interested pros"| C TT -->|"estimate request"| PRO PRO -->|"free initial estimate"| TT A -->|"curate · outreach · review"| TT B -->|"branded resident portal"| TT classDef cust fill:#EAF6F2,stroke:#0F7458,color:#08382C; classDef pro fill:#FDF6EA,stroke:#C57D17,color:#7a4d09; classDef admin fill:#EBE2D3,stroke:#6B7B77,color:#1B2A28; classDef bldg fill:#E7EDF5,stroke:#1E3A5F,color:#13243a; classDef sys fill:#ffffff,stroke:#1C8F73,color:#1B2A28;
The main workflow

End-to-end: from job request to connection

The core loop, colored by who's acting at each step. Every completed job is paid through the platform; positive ones can become a recurring relationship.

flowchart TD
  A1["Start a job request"]:::cust --> A2["Chat intake
one question at a time"]:::cust A2 --> A3["Job brief + photos + consent"]:::cust A3 --> B1["Admin reviews & qualifies"]:::admin B1 --> B2["Generate search queries"]:::admin B2 --> B3["Add candidate pros
(manual / mock Google import)"]:::admin B3 --> B4["Contact pros — outreach"]:::admin B4 --> P1["Pro opens estimate link"]:::pro P1 --> P2["Submit free initial estimate"]:::pro P2 --> B5["Admin reviews & marks ready"]:::admin B5 --> A4["Customer compares interested pros"]:::cust A4 --> A5["Choose a pro"]:::cust A5 --> P3["Selected pro: accept connection"]:::pro P3 --> U["🔓 Contact details unlock"]:::sys U --> P4["Pro contacts within committed window"]:::pro P4 --> JOB["Job completed"]:::sys JOB --> PAY["Customer pays in-app"]:::cust PAY --> SPLIT["Platform splits payment · pro 4% all-in + customer 1%
→ pro paid out · platform nets ~2%"]:::sys SPLIT --> RV["Two-sided reviews"]:::sys RV --> REC{"Positive +
recurring-friendly?"}:::dec REC -->|"Yes"| RECP["Offer a recurring cadence"]:::cust REC -->|"No"| END(["Done"]):::sys classDef cust fill:#EAF6F2,stroke:#0F7458,color:#08382C; classDef pro fill:#FDF6EA,stroke:#C57D17,color:#7a4d09; classDef admin fill:#EBE2D3,stroke:#6B7B77,color:#1B2A28; classDef sys fill:#ffffff,stroke:#1C8F73,color:#1B2A28; classDef dec fill:#FAE8C8,stroke:#C57D17,color:#7a4d09;
Customer

Customer journey

"Describe your project and compare initial estimates from interested local pros." Contact details stay private until the customer chooses.

DescribeCompareConnectStay — the loop that turns one job into a relationship
1

Describe

A few minutes · no account needed
  • Land on the site — or your building's branded portal
  • Chat intake asks one friendly question at a time
  • Add photos, then confirm the brief & consent

🔒 Your contact details stay private from the start

2

Compare

Interested pros, side by side
  • Get notified the moment initial estimates are ready
  • Compare range, availability, ratings & what's included
  • Not sorted by cheapest — and never a random directory

⚖️ You choose who to connect with

3

Connect

Only the pro you picked
  • Pick a pro — we ask them to confirm the connection
  • They accept → contact unlocks; they reach out in-window
  • Job gets done — you pay securely in-app (protected)

📇 Details shared only with your chosen pro

4

Stay

One job becomes a relationship
  • Rate your pro after the job
  • Set a recurring cadence — set it and forget it
  • "My Home": saved pros, history & reminders → one-tap rebook

🏠 Your home gets looked after

Pro / service provider

Pro journey

"Submit estimates for free. You only pay a flat 4% service fee — and only out of money you've actually been paid through the platform."

flowchart LR
  O["Outreach hits pro
(no account needed)"]:::pro --> E["Submit free initial estimate"]:::pro E --> S{"Customer selects you?"}:::dec S -->|"No"| L["Reputation still compounds
for the next paid customer"]:::sys S -->|"Yes"| AC["Accept connection"]:::pro AC --> ONB["Connect onboarding
(so you get paid)"]:::sys ONB --> UN["🔓 Customer contact unlocks"]:::sys UN --> JOB["Do the job"]:::pro JOB --> PAY["Customer pays in-app →
flat 4% deducted, you're paid out"]:::sys PAY --> REP["Repeat & recurring work"]:::pro REP --> DASH["Pro dashboard:
booked revenue · book of business · reputation"]:::pro classDef pro fill:#FDF6EA,stroke:#C57D17,color:#7a4d09; classDef sys fill:#ffffff,stroke:#1C8F73,color:#1B2A28; classDef dec fill:#FAE8C8,stroke:#C57D17,color:#7a4d09;
Admin / operator

Admin workflow

The operator console runs the marketplace: triage jobs, discover & contact supply, review estimates, manage connections, and track outcomes.

flowchart TD
  D["📊 Dashboard
queue & alerts"]:::admin --> J["Jobs
filter · triage · qualify"]:::admin J --> DISC["Pro discovery
queries · mock Google import · add candidate"]:::admin DISC --> OUT["Outreach
log contacts · copy template"]:::admin OUT --> EST["Estimates
approve · reject · mark ready"]:::admin EST --> CONN["Connections
track accept · contact · outcome"]:::admin CONN --> REC["Recurring
oversight + scheduler sim"]:::admin J --> PROS["Pros CRM
profiles · verification · lifecycle"]:::admin J --> BLDG["Buildings
roster · privacy-safe dashboard"]:::admin CONN --> REV["Reviews
two-sided ratings"]:::admin REC --> MET["Metrics
intake · fulfillment · monetization · retention"]:::admin classDef admin fill:#EBE2D3,stroke:#6B7B77,color:#1B2A28;
Monetization

Service fee — a % of the job, paid through the platform

Estimates are free. The customer pays for the completed job through True Trade, which splits the payment via Stripe Connect: the pro pays a flat 4%, all-in (we absorb Stripe inside it — no surprise), the customer pays 1% (a service & protection fee), and the platform nets ~2%. No flat connection fee, no free-first — one model for every job.

sequenceDiagram
  actor Cust as Customer
  participant TT as True Trade
  actor Pro
  participant Stripe
  Cust->>TT: Selects this pro
  TT->>Pro: "You were selected"
  Pro->>TT: Accept + finish Connect onboarding (to get paid)
  TT->>Cust: 🔓 Contact details unlock
  Note over Pro,Cust: Pro does the job · final amount agreed
  Cust->>TT: Pays in-app (job + 1%)
  TT->>Stripe: Connect charge — split the payment
  Stripe-->>Pro: Payout (job − 4%, all-in)
  Stripe-->>TT: Platform fee (~2% net · Stripe absorbed)
      
$500 job → customer pays $505 · pro receives $480 · platform nets ~$10 (~2%).
stateDiagram-v2
  [*] --> not_started
  not_started --> awaiting_payment: job completed
  awaiting_payment --> processing: customer pays in-app
  processing --> paid: split settled · pro paid out
  paid --> refunded: refund / dispute reverses the split
  awaiting_payment --> [*]: no payment → no fee
      
Job-payment states — no payment, no fee. Payout is held until the pro completes Connect onboarding.
Trust core

Service-fee scenarios — when the platform earns

One rule replaces all the old charge / waive / credit logic: the fee is a % of money that actually moved through the platform. No payment → no fee. Bad behaviour is handled by reputation, not by chasing a fee.

OutcomePlatform earnsWho's accountable
Job completed & customer pays~2% net— (the only revenue event)
Repeat / recurring job~2% net— (same model)
Pro no-shows / never deliversNothingPro — reputation hit
Customer ghosts / cancels before workNothingCustomer — reputation hit
Off-platform settlement (leakage)Nothing— mitigated by in-app value
Refund / disputeReversed— split reversed proportionally
Tiny job (< ~$30–40)Min. fee— a floor so it doesn't net negative
The platform only earns when the pro earns and the customer pays. Leakage is fought by making in-app payment the easiest, most valuable path — fast payout for pros, payment protection + a satisfaction guarantee for customers (funded by the 1%).
Repeat revenue

Recurring services

After a positive review on a recurring-friendly job, the customer sets a cadence once and forgets it. The pro opts in; the scheduler runs each visit — paid in-app like any job, with the same service fee.

flowchart TD
  RV["⭐ Positive review
recurring-friendly category"]:::cust --> PR["Prompt: want them on a schedule?"]:::cust PR --> CAD["Customer picks cadence + per-visit rate
(anchored on what they just paid)"]:::cust CAD --> OPT["Pro opts in to the standing arrangement"]:::pro OPT --> SCH["Scheduler auto-generates each visit
+ reaches out to the pro"]:::sys SCH --> VIS["Visit completed"]:::pro VIS --> PAY["Per-visit charge — Stripe Connect"]:::sys PAY -->|"pro 4% + customer 1%"| PLAT["Platform fee (~2% net)"]:::sys PAY -->|"payout (job − 4%)"| POUT["Pro payout"]:::pro PAY -->|"next cycle"| SCH classDef cust fill:#EAF6F2,stroke:#0F7458,color:#08382C; classDef pro fill:#FDF6EA,stroke:#C57D17,color:#7a4d09; classDef sys fill:#ffffff,stroke:#1C8F73,color:#1B2A28;
Why both sides stay

The retention flywheel

Retention isn't two problems — it's one reinforcing loop. The customer's home profile & saved crew pull repeat work, which gives the pro predictable revenue, which deepens quality and trust, which routes even more work through the platform.

flowchart LR
  H["🏠 Home profile + saved 'Your pros'"]:::cust --> RB["Customer rebooks in one tap
(no comparison · trusted pro)"]:::cust RB --> PRO["Pro gets repeat + recurring revenue"]:::pro PRO --> Q["Pro stays · invests in reputation · quality up"]:::pro Q --> T["Customer trust deepens"]:::cust T --> MORE["More of the home's work routed in"]:::cust MORE --> H classDef cust fill:#EAF6F2,stroke:#0F7458,color:#08382C; classDef pro fill:#FDF6EA,stroke:#C57D17,color:#7a4d09;

🏠 Customer hub — "My Home"

Property record (the moat) · upcoming-care reminders (the demand engine) · "Your pros" roster with one-tap rebook · service history.

🔧 Pro hub — Dashboard

Booked recurring revenue (hero metric) · needs-action feed · book of business & regulars · reputation & Top-Pro tier · pipeline.

B2B2C distribution

White-label building portals

A condo or property manager offers True Trade to residents as a branded amenity. Residents get the normal flow, themed and scoped to a curated roster. The building sees only privacy-safe aggregates — never resident details.

flowchart TD
  PM["🏢 Building / PM
onboards"]:::bldg --> ROS["Curated, vetted roster
(insurance / license verified)"]:::bldg PM --> BRAND["Branded portal /b/their-building"]:::bldg BRAND --> RES["Resident describes an in-unit job"]:::cust RES --> FLOW(["Normal intake → compare → connect → recurring"]):::sys FLOW --> AGG["Privacy-safe building dashboard
anonymous totals only"]:::bldg ROS --> FLOW classDef bldg fill:#E7EDF5,stroke:#1E3A5F,color:#13243a; classDef cust fill:#EAF6F2,stroke:#0F7458,color:#08382C; classDef sys fill:#ffffff,stroke:#1C8F73,color:#1B2A28;
Money flows (Stripe)

How money moves — one rail

Every job — one-off or recurring — flows the same way: the customer pays through True Trade, Stripe Connect splits the payment, the pro is paid out, and the platform keeps its fee. The pro's 4% is all-in (Stripe absorbed); the customer adds 1%.

flowchart LR
  CUST["Customer card
(job + 1%)"]:::cust -->|"pays in-app"| TT["Stripe Connect
(platform)"]:::sys TT -->|"payout · job − 4%"| PRO["Pro"]:::pro TT -->|"5% gross − Stripe absorbed"| PLAT["Platform (~2% net)"]:::sys classDef cust fill:#EAF6F2,stroke:#0F7458,color:#08382C; classDef pro fill:#FDF6EA,stroke:#C57D17,color:#7a4d09; classDef sys fill:#ffffff,stroke:#1C8F73,color:#1B2A28;
Backend: Cloudflare Pages Functions + Neon Postgres; webhooks are the source of truth. Pros onboard to Stripe Connect to receive payouts.
State machines

Status lifecycles

The job moves through a clear set of statuses from submission to outcome.

stateDiagram-v2
  [*] --> submitted
  submitted --> qualified: admin review
  submitted --> needs_more_info
  needs_more_info --> qualified
  qualified --> finding_pros
  finding_pros --> pros_contacted
  pros_contacted --> estimates_received
  estimates_received --> ready_for_customer
  ready_for_customer --> customer_selected_pro
  customer_selected_pro --> pending_pro_acceptance
  pending_pro_acceptance --> connection_accepted
  connection_accepted --> contact_unlocked
  contact_unlocked --> in_progress
  in_progress --> completed
  completed --> [*]
  ready_for_customer --> closed_no_hire
  pending_pro_acceptance --> ready_for_customer: pro declines → pick another
      
Job status lifecycle (simplified) — plus cancelled and dispute as off-ramps.
Under the hood

Data model

The entities and how they relate — the spine the whole product is built on.

erDiagram
  CUSTOMER ||--o{ JOB : submits
  CUSTOMER ||--o| HOME : owns
  HOME ||--o{ MAINTENANCE_REMINDER : has
  HOME }o--o{ PRO : "saved 'Your pros'"
  JOB ||--o{ OUTREACH : "pros contacted"
  JOB ||--o{ ESTIMATE : receives
  PRO ||--o{ ESTIMATE : submits
  PRO ||--o{ OUTREACH : "reached via"
  JOB ||--o| CONNECTION : "customer-selected pro"
  CONNECTION ||--o{ REVIEW : "two-sided"
  CONNECTION ||--o| RECURRING_PLAN : "may become"
  RECURRING_PLAN ||--o{ RECURRING_OCCURRENCE : schedules
  ORGANIZATION ||--o{ JOB : "white-label source"
  ORGANIZATION }o--o{ PRO : "curated roster"