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.
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.
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 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;
"Describe your project and compare initial estimates from interested local pros." Contact details stay private until the customer chooses.
🔒 Your contact details stay private from the start
⚖️ You choose who to connect with
📇 Details shared only with your chosen pro
🏠 Your home gets looked after
"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;
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;
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)
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
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.
| Outcome | Platform earns | Who's accountable |
|---|---|---|
| Job completed & customer pays | ~2% net | — (the only revenue event) |
| Repeat / recurring job | ~2% net | — (same model) |
| Pro no-shows / never delivers | Nothing | Pro — reputation hit |
| Customer ghosts / cancels before work | Nothing | Customer — reputation hit |
| Off-platform settlement (leakage) | Nothing | — mitigated by in-app value |
| Refund / dispute | Reversed | — split reversed proportionally |
| Tiny job (< ~$30–40) | Min. fee | — a floor so it doesn't net negative |
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;
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;
Property record (the moat) · upcoming-care reminders (the demand engine) · "Your pros" roster with one-tap rebook · service history.
Booked recurring revenue (hero metric) · needs-action feed · book of business & regulars · reputation & Top-Pro tier · pipeline.
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;
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;
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
cancelled and dispute as off-ramps.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"