Services Marketplace

Marketplace app · built by the Vibecode team

Trellis is a local services marketplace seeded with 40 fictional Austin pros across cleaning, handyman, plumbing, electrical, moving, tutoring, beauty and pet care, with 300 reviews and 60 bookings in every state. Customers search by job and ZIP, compare pros on a list and a map, book an open slot or request a quote, chat, pay with a test card or after the job, and leave a review. Pros sign up, set their services, area and hours, answer leads with quotes, mark jobs done and see earnings after the platform fee. An admin approves new pros from an ID queue, settles disputes with refunds, edits categories and featured pros, runs payouts and sets the commission. One-click demo logins for all three roles appear on first run.

  • Web app
  • Built in 13 prompts
  • Free to remix
Services Marketplace, marketplace app built with Vibecode
Remix this template

Remix copies the working app into your account for free, exactly as we built it. It runs in your browser.

The prompt that builds it

We built Services Marketplace in 13 prompts. Here they are folded into one, so a single paste into a new app builds the finished version.

Prompt · 10,215 words

Build "Trellis", a two-sided local services marketplace web app (like Thumbtack and TaskRabbit, with Airbnb-level photography and type). Customers find, book and pay trusted local pros; pros answer requests, send quotes and get paid minus a platform commission; an admin verifies pros and runs the marketplace. The demo city is Austin, TX. It must work end to end with a real backend, a real database and seeded demo data, and look like a polished, designed product, not a generic AI template.

Design references (the original screenshots are not included; build from these descriptions):
- Reference: Thumbtack home hero. Big two-field search (problem + ZIP) with a dark pill "Find a pro" button over a full-bleed home photo, small caption card bottom-right.
- Reference: Thumbtack "Choose a service" photo cards with white title + "$154 and up" over a dark bottom gradient, 2x2 grid, plus a 3-item feature list with round icon chips.
- Reference: Thumbtack results. Filters column on the left (radio groups), pro rows with avatar, rating line, "In high demand" badge, facts with icons, review snippet, "View profile" pill on the right.
- Reference: Thumbtack pro profile header. Large round avatar, name, rating, Share, section tabs (About / Services / Photos / Reviews / Credentials), Overview facts with icons, two wide pill buttons "Message" and "Request a quote", sticky request card on the right.
- Reference (Profile services reviews): services offered as pill chips, extra services with check marks, a photo carousel, and the reviews summary (big score, stars, 5-to-1 distribution bars).
- Reference: review list layout (avatar, name, stars, source, date on the right, body, grey "reply" box), keyword chips with counts above. Names and text are blurred on purpose; only the layout matters.
- Reference: TaskRabbit "Book your next task": centred search with a solid green search button, outline pill chips, "Taskers recommended for you" cards (photo, name, badge, completed tasks, rating, "Top skills" pills with $/hr, "View Tasker profile").
- Reference: TaskRabbit "Browse Taskers & prices": progress stepper at the top, filter card (Date pills Today / Within 3 Days / Within A Week / Choose Dates, Time of day checkboxes, price histogram slider), pro card with big round photo, "$60.91/hr", "2 HOUR MINIMUM" tag, rating, task count, grey "How I can help:" box, green "Select & Continue" pill.
- Reference (Browse cards): more of the same list, price slider with "The average hourly rate is $49.55/hr", "Elite" tag, trust card with a shield icon.
- Reference: TaskRabbit tasker profile: left column (photo, name, badge, rating, About me with ID Verified, My Skills list with chevrons), right column skill cards "Arts / Crafts for $36.13/hr" with "Select & Continue".
- Reference: Thumbtack phone home (390 px): photo on top, big headline, search card with ZIP pill + "Find a pro" button.
- Reference: Thumbtack phone category page: headline, ZIP field, full-width dark button, breadcrumb, "House cleaners near Austin, TX".
Borrow layout, density and mechanics from these. Do NOT copy their brands, logos or colours: the product is Trellis with the design system below. They are only references: delete the refs/ folder when the app is finished so it doesn't ship with the project.

## Stack, data and auth

- Use the workspace's standard stack: React + Vite + Tailwind + shadcn/ui in webapp/, Hono on Bun in backend/, with the database-auth skill (Prisma + Better Auth, email + password) for accounts and persistence. All API routes live under /api. Shared Zod schemas in backend/src/types.ts.
- Roles on the user: CUSTOMER, PRO, ADMIN. Every API route checks the role server-side (a customer can't call pro or admin routes; a pro only sees their own leads, jobs and earnings).
- Sign-in must work inside the Vibecode preview iframe and on the deployed domain (follow the database-auth skill's cookie and trusted-origin settings so there is never an "Invalid origin" or a sign-out loop). Role-guarded routes read the role from the shared useSession() store: whenever the role changes (become-pro, demo switch, sign-in) refetch that store before navigating, and when a guard sees a role that doesn't match the route it refetches the session once before redirecting. A new pro who signs up must land on /pro/onboarding without a reload.
- Remixes get backend/.env with BETTER_AUTH_SECRET cleared, so add backend/src/lib/authSecret.ts with ensureAuthSecret(), called in backend/src/env.ts before the environment is validated: when the value is blank it reuses a secret already saved in backend/.env, otherwise it generates a random 32-byte base64 secret, writes it to backend/.env and logs "Generated a new BETTER_AUTH_SECRET". Keep the existing validation.
- File uploads (pro profile photos, work photos, ID documents, job photos) use the upload-assets skill (Vibecode Storage). Never store base64 in the database.
- Seed data runs automatically when the server starts and the database has no categories, so remixes and the deployed app always open full. Commit the SQLite database (backend/prisma/dev.db with its -wal and -shm files): before recycling an idle sandbox the platform saves the workspace with `git add --all`, which skips ignored files, and a remix copies only what is in git, so an ignored database loses everything a user entered. Store the day the demo was seeded; at startup, before the server answers, and then hourly, move every seeded demo timestamp forward by the whole calendar days since then, leaving rows a user created or edited alone, so dated views look as they did on seed day. Never store a visitor's IP address or user agent on sessions (blank both in a Better Auth databaseHooks.session hook). Admin > Settings has "Reset demo data" (confirm dialog) that wipes and re-seeds.
- Prisma models (add fields as needed): User (+ role, phone, neighborhood, zip), ProProfile (slug, businessName, headline, about, categoryId, baseNeighborhood, zip, lat, lng, radiusMiles, yearsInBusiness, languages, responseMinutes, status PENDING|APPROVED|REJECTED|SUSPENDED, rejectReason, featured, autoAccept, licenseNumber, insured, idDocUrl, licenseDocUrl, submittedAt, verifiedAt, availability JSON), ProPhoto, Category (slug, name, description, icon, imageUrl, startingPriceCents, sortOrder, active), Service (proId, name, description, priceType FIXED|HOURLY|QUOTE, priceCents, minHours, durationMins, instantBook), Booking (ref like "TR-1042", customerId, proId, serviceId, type INSTANT|QUOTE, status REQUESTED|QUOTED|PENDING|CONFIRMED|COMPLETED|CANCELLED|DECLINED|DISPUTED, details, when ASAP|WEEK|FLEXIBLE|DATE, address, unit, zip, neighborhood, scheduledAt, priceCents, quoteCents, quoteMessage, quoteValidUntil, paymentMethod CARD|PAY_AFTER, paymentStatus UNPAID|HELD|PAID|RELEASED|REFUNDED|PARTIAL_REFUND, commissionPct snapshot, feeCents, payoutCents, payoutStatus NONE|PENDING|PAID, paidOutAt, completedAt, cancelledAt, declineReason), Thread + Message (kind TEXT|QUOTE|SYSTEM, readAt), Review (proId, authorId, bookingId optional, rating 1-5, tags, body, proReply, createdAt), Dispute (bookingId, reason, description, status OPEN|RESOLVED, resolution REFUND|RELEASE|PARTIAL, refundCents, note, resolvedAt), Notification (userId, type, title, body, link, readAt), Setting (commissionPct default 15, payoutDay "Friday").
- Ratings and review counts are always computed from Review rows, never typed in. No invented stats anywhere (no "4.9 from 15M reviews", no "300K pros"). Pros show years in business (their own profile field) and computed review counts instead of hire counts.
- Every write saves to the database first and only then creates notifications (in-app bell). Email and SMS sending are not connected; Admin > Settings lists "Email notifications: Not connected" honestly.
- Money is stored in cents and shown as "$185" or "$157.25". Commission math: fee = price x commissionPct, payout = price - fee. Changing the commission in Admin applies to new bookings; each booking keeps its snapshot.
- Dates are human-readable in Austin time (America/Chicago): "Tue, Nov 4 · 10:00 AM", "Today · 2:00 PM", "3 weeks ago", "Oct 12, 2025". Never ISO strings, seconds or ids in the UI. Seed dates are relative to the seed time so "today" and "upcoming" always look current.
- Payments: Stripe test mode. If STRIPE_SECRET_KEY (sk_test_) and VITE_STRIPE_PUBLISHABLE_KEY exist in env, create a PaymentIntent server-side with capture_method "manual" (held until the job is done), capture it when the job is marked done and cancel/refund it from Admin disputes. With no keys (the default), the same card form runs as a clearly labelled demo: a "Test mode" badge, prefilled 4242 4242 4242 4242 · 12/28 · 123 · ZIP 78704, format validation, and the server records paymentStatus HELD. Never claim real money moved. Admin > Settings shows "Stripe: Not connected — demo payments" with one line on adding the keys.

## Roles, demo logins and first run

Seed three demo accounts (password demo1234 for all):
- Customer: Jordan Ellis, jordan@trellis.example, Travis Heights 78704, (512) 555-0142, address "1517 Bluebonnet Bend, Unit B, Austin, TX 78704".
- Pro: Luis Ortega, Ortega Plumbing Co., luis@trellis.example, (512) 555-0147.
- Admin: Avery Quinn (Trellis Ops), admin@trellis.example.
Every seeded address uses a reserved example domain: pros @pros.trellis.example, customers @example.com.

First run (no session, not dismissed in localStorage): a centred modal, 560 px wide, title "Try every side of Trellis", subtitle "This is a demo marketplace with fictional pros, reviews and bookings. Pick a role to explore — you can switch anytime.", three stacked role rows, each with a 40 px icon circle, title, one-line description, the email/password in small mono text and a button:
- "Customer — Jordan Ellis" · "Book a pro, chat, pay and leave a review." · button "Continue as Jordan"
- "Pro — Luis Ortega, Ortega Plumbing Co." · "Answer leads, send quotes, mark jobs done, see earnings." · button "Continue as Luis"
- "Admin — Avery Quinn" · "Approve pros, settle disputes, set the commission." · button "Continue as Avery"
Footer link "Just browse" closes it. Buttons sign in with the real auth API (no fake session) and land on Home, /pro/leads and /admin respectively. A small pill "Demo accounts" fixed bottom-left is shown to signed-out visitors only; signed-in users reopen the modal from the avatar menu, the Account page and the demo bar's "Switch demo account" link, and the admin sidebar has a "Demo accounts" item above "Sign out". /signin also lists the three demo accounts under the form.

Above the header on every page: a 36 px demo bar, background #F4F4F0, 13 px #5C6370 text, centred: "Demo marketplace · Every pro, review and booking here is fictional sample data." with a green link "Switch demo account". Dismissible with an X (localStorage).

## Design system

- Font: Figtree from Google Fonts (400, 500, 600, 700, 800) for everything. Headings 700-800 with letter-spacing -0.02em. Body 16/24, small 14/20, caption 13/18. Desktop H1 56/60, section H2 32/38, card titles 18/24. Phone H1 34/38, H2 24/30. Numbers in tables use tabular figures.
- Colours (one accent only):
  - Ink #16181D (text, dark buttons, selected states), Slate #5C6370 (secondary text), Muted #8A919C (tertiary), Line #E7E8EA (borders, dividers), White #FFFFFF (page), Sand #F6F6F3 (alternate section background, input fill on hover), Mist #F1F2EF (grey boxes like "How I can help", review replies, their chat bubbles).
  - Accent "Trellis green" #0B7A4B for primary buttons, links, active tabs, map circles, chart bars; hover #096A41, pressed #075735; tint #E8F4EE with text #0A6640 for badges and selected chips.
  - Status pills only: Requested = white with Line border + Slate text; Quoted = #FEF3E2 / #9A5B00; Pending = #F1F2EF / #16181D; Confirmed = tint #E8F4EE / #0A6640; Completed = #16181D / white; Cancelled and Declined = #F1F2EF / #8A919C; Disputed = #FDECEC / #B42318.
  - Stars are Ink (#16181D) filled, like Airbnb, not yellow.
- Radius: buttons and chips fully rounded (999 px); inputs 12 px; cards 16 px; photos 12 px; modals 20 px; bottom sheets 20 px top corners.
- Buttons: primary = green fill, white 15 px 600 text, 48 px tall (40 px small); secondary = white with 1 px #16181D border; tertiary = text link in green. Press = scale 0.98.
- Cards: white, 1 px Line border, no shadow at rest; hover lifts 2 px with shadow 0 8px 24px rgba(22,24,29,0.08) in 150 ms ease-out. The sticky booking card has shadow 0 8px 28px rgba(22,24,29,0.10).
- Spacing scale 4/8/12/16/24/32/48/64/96. Container max width 1200 px, 24 px side padding desktop, 16 px phone. Sections 96 px apart on desktop, 56 px on phone.
- Icons: lucide-react, 1.75 stroke, never emoji. Category icons: Cleaning Sparkles, Handyman Hammer, Plumbing Wrench, Electrical Zap, Moving Truck, Tutoring GraduationCap, Beauty at home Scissors, Pet care PawPrint.
- Badges (pill, 12 px 600 uppercase-free text, 24 px tall, icon 14 px): "Verified" ShieldCheck on tint green; "Top Pro" Award on #F1F2EF ink; "Instant book" Zap on tint green; "New on Trellis" Sprout on #F1F2EF slate; "Licensed" BadgeCheck on #F1F2EF ink.
- Logo: a 26 px mark (rounded square radius 8 px, fill #0B7A4B, two white 2.5 px diagonal strokes crossing like a garden lattice) followed by the wordmark "trellis" in Figtree 800, 24 px, letter-spacing -0.03em, Ink. Use the mark as the SVG favicon. Page title "Trellis — Book trusted local pros in Austin"; meta description; og:image is our own 1200x630 card (white, the mark, "Book trusted local pros in Austin" in Figtree 800, three category photos). Replace the template favicon.ico, og-base.png and every "Vibecode" title or meta.
- Never: purple or blue gradients, glassmorphism, emoji icons, default shadcn grey look, drop shadows on everything, stock "hero blob" shapes.

## Header and navigation

- Desktop header 72 px, white, 1 px bottom Line, sticky. Left: logo. Centre (all pages except Home): compact search pill 520 px — "What do you need?" input | "78704" ZIP input | 40 px green circle with a Search icon. Right for guests: "Explore" (opens a 2-column menu of the 8 categories with icons and "from $X"), "Become a pro", "Log in" (text), "Sign up" (secondary pill). Customer: "Explore", "My jobs", Messages icon with a green unread dot, Bell icon (notifications popover: list with title, body, time, unread dot, "Mark all read"), avatar menu (My jobs, Messages, Account, Demo accounts, Sign out). Pro: "Leads" with a count bubble, "Jobs", "Messages", "Earnings", "Profile", bell, avatar menu with "View public profile". Admin: uses the admin layout below.
- Phone (under 768 px): 56 px header with logo left and bell + avatar (or "Log in") right. A fixed bottom tab bar 64 px plus safe-area padding, white with top Line, icons + 11 px labels, active = green: customers "Explore · Jobs · Messages · Account"; pros "Leads · Jobs · Messages · Earnings · Profile"; guests "Explore · Log in".
- Footer: logo + "Book trusted local pros in Austin, TX." then columns Customers (How it works, Browse categories, My jobs), Pros (Become a pro, Pro dashboard), Company (About, Trust & safety, Terms, Privacy), and "© 2026 Trellis · Demo marketplace".

## Customer screens

1. Home (/)
   - Hero, desktop: two columns. Left (48%): H1 "Book trusted local pros in Austin." Sub (18/28 Slate): "Cleaners, handymen, plumbers, tutors and more. Compare verified pros, see real prices, and book in minutes." Search card (white, 16 px radius, 1 px Line, shadow 0 8px 28px rgba(22,24,29,0.08), 8 px padding): input "What do you need help with?" with a Search icon (autocomplete dropdown of categories and service names, keyboard navigable, matched text bold), a 1 px divider, a ZIP/neighborhood input (fixed ~200 px; the service input takes the rest, min 280 px, so "What do you need help with?" never clips) with a MapPin icon prefilled "78704" (suggestion rows read "78704 · Travis Heights"), and a green "Search" pill button 48 px. Under it a row of outline chips "House cleaning · TV mounting · Leaky faucet · Ceiling fan install · Help moving · Dog walking · Math tutor · Haircut at home" (each runs a search). Then a trust row with three small icon+text items in Slate: ShieldCheck "Every pro is ID-verified by our team", Lock "Pay is held until the job is done", CalendarCheck "Free cancellation up to 24 hours before". Right (52%): the hero photo, 560 px tall, 24 px radius, with a white caption card bottom-left (12 px radius): "Rosa D. · House cleaning · Hyde Park" and her real rating and count from the API, e.g. "★ 4.7 (14) · Instant book". On phone the photo uses object-position center 25% so her face shows.
   - "Browse by category": 4x2 grid of photo cards (aspect 4:3, 16 px radius, dark bottom gradient), white 20 px 700 title and the starting price with its unit under it ("from $48/hr", "from $109"; the same unit wherever a starting price appears), category icon in a white 32 px circle top-left. Hover zooms the photo 1.04. Links to /search?category=slug.
   - "Top-rated pros near you" with "See all pros" link and prev/next circle buttons: horizontal carousel of featured pro cards (280 px wide): portrait 1:1 with 12 px radius and badges overlaid top-left, name + ShieldCheck, business name, "★ 4.9 (16 reviews)", "Responds in about 15 min", top service "Faucet replacement · $185", full-width secondary button "View profile".
   - "How Trellis works": three columns with a 48 px tint-green icon circle, step number, title and text: 1 "Tell us what you need" — "Search by job, or describe it in your own words. Add your ZIP to see pros who serve your street." 2 "Book instantly or compare quotes" — "Pick an open slot with instant book, or request quotes from a few pros and choose the one that fits." 3 "Pay when it's done" — "Your card is held securely and released to your pro only after the job is marked done. Or choose to pay after the job."
   - "Recently reviewed in Austin": three review cards from the seed data (stars, quote, "Priya S. · Faucet replacement with Luis O. · 3 weeks ago").
   - Pro band (Sand background, 24 px radius block): left H2 "Are you a pro? Get hired by neighbors." text "Send quotes from your phone, keep your calendar full, and get paid when the job's done. Trellis keeps 15% only when you get paid. No lead fees, no subscription." (the % comes from Settings), green button "Become a Trellis pro"; right a photo of a pro at work.
2. Search results (/search?q=&category=&zip=)
   - Under the header a sticky two-row filter bar (nothing may clip at 1280 or 1440 px). Row 1: category chips (All, Cleaning, Handyman, Plumbing, Electrical, Moving, Tutoring, Beauty at home, Pet care; selected = ink fill white text). Row 2: toggle chips "Instant book", "Available this week", "4.5+ rating", a "Price" popover (range slider with a small histogram of the results' starting prices and "The average starting price is $X"), and on the right "Sort: Recommended" dropdown (Recommended, Highest rated, Most reviews, Lowest price, Fastest response).
   - Title row: H1 24 px "Plumbers near Travis Heights" (or "Pros near 78704" for no category, "Results for "faucet"" for text) and Slate count "5 pros · prices before you book".
   - Desktop layout: results list left (58%), map right (42%, sticky under the filter bar, full remaining height, 16 px radius, 16 px gap). Map = MapLibre GL (react-map-gl/maplibre) with OpenFreeMap's free keyless vector style https://tiles.openfreemap.org/styles/positron and the attribution "© OpenFreeMap © OpenMapTiles © OpenStreetMap contributors" (CARTO now needs a key; use the same map for the profile and onboarding service areas). Fit the map to the results with 48 px padding. The search location is a 10 px Ink dot with a white 2 px ring drawn under the pins. Pins are auto-width white price pills ("$185", 13 px 700 Ink, padding 6px 10px, white-space nowrap, centred on the point, shadow 0 2px 8px rgba(0,0,0,0.18)); hover or select = Ink fill, white text, scale 1.06, on top. Overlapping pins cluster into Ink count circles ("6") that zoom in on click and split as you zoom. Service-area circles are GeoJSON circle polygons (green #0B7A4B line, 8% fill). Hovering a list card highlights its pin and draws that pro's service-area circle (green, 8% fill); clicking a pin opens a mini card (photo, name, rating, price, "View profile"). Checkbox on the map "Search as I move the map" re-queries by map bounds.
   - Pro row card (horizontal, 16 px radius, 20 px padding): 168 px square portrait (12 px radius) left; middle: name 18 px 700 + green ShieldCheck, business name 14 px Slate, "★ 4.9 · 16 reviews · 11 yrs in business", badges row, Clock "Responds in about 15 min", MapPin "Travis Heights · 2.3 mi away", and a Mist box with a top review quote in 14 px: “Found the leak was the supply line, not the faucet, and saved us $150.” — Priya S.; right column: "from" 13 px Slate above "$89" 22 px 800, "/ service call", then buttons "View profile" (secondary) and "Book" (green, only when the pro has instant book) or "Request quote".
   - Search logic: text matches category, service names, pro and business names; location = ZIP or neighborhood mapped to lat/lng from the built-in Austin table below (signed-in customers searching their own ZIP measure from their home); only APPROVED pros whose service radius reaches the search point; distance shown to one decimal. Recommended sort = featured first, then rating x log(reviews) and distance.
   - Phone: the list is full width with 96 px portraits, a "Filters" button opens a bottom sheet with every filter and "Show 5 pros", and a floating Ink pill "Map" (Map icon) at the bottom centre switches to a full-screen map that fills exactly the space between the header and the bottom tab bar (the demo bar stays visible above the header). In map mode a "List" pill sits at the top centre, 12 px below the header, never over a card; zoom buttons are hidden on phone (pinch to zoom); compact pro cards about 120 px tall (88 px rounded photo, name with the verified shield, "★ 4.9 · 16 reviews", "from $89" and a small green "Book" or "Request quote" button) sit 12 px above the tab bar in a horizontal snap carousel, each 85% of the screen wide with 12 px gaps. Swiping a card into view highlights its pin and pans the map to it; tapping a pin centres its card (no pin popup on phone).
   - Empty: "No pros match those filters" + "Try a wider area or fewer filters" + "Clear filters" button. Loading: 4 skeleton cards with shimmer.
3. Pro profile (/pros/:slug)
   - Breadcrumb "Austin › Plumbing › Ortega Plumbing Co.". Header: 120 px round portrait, H1 32 px "Luis Ortega", business name, rating line "★ 4.9 · Exceptional · 16 reviews" (Exceptional 4.8+, Excellent 4.5+, Great 4.0+), badges, a facts row with icons (Clock "Responds in about 15 min", Briefcase "11 years in business", MapPin "Serves Travis Heights + 12 mi", Languages "English, Spanish"), and actions "Share" (copies link, toast "Link copied") and "Save" (Heart, persisted for signed-in customers).
   - Sticky section tabs under the header on scroll: About · Services · Photos · Reviews · Credentials · Service area (scroll-spy underline in green).
   - About: bio with "Read more"; two wide pill buttons "Message" and "Request a quote" (as in ref-04).
   - Services & prices: rows with name 16 px 600, description, duration "About 1.5 hrs", price on the right ("$185 flat", "$65/hr · 2 hr min", "Free estimate"), and "Book" (instant) or "Get a quote" button.
   - Photos: 3-column grid of work photos with captions ("New kitchen faucet · Bouldin Creek"); click opens a lightbox (fade in, arrows, Esc closes, counter "3 / 6").
   - Reviews: left a big "4.9" + 5 stars + "16 reviews"; right 5-to-1 distribution bars (Ink fill on Line track, percentages); keyword chips from review tags with counts ("On time · 11", "Fair price · 8", "Great communication · 7", "Tidy · 5", "Expert work · 9"); list of reviews: 40 px initials circle (Mist background, Ink initials), "Priya S.", stars, service name chip, date right-aligned ("3 weeks ago"), body, and the pro's reply in a Mist box "Response from Luis". Show 5, then "Show all 16 reviews" loads the rest.
   - Credentials: rows with icons: "ID verified by Trellis · Oct 12, 2025", "Background check · Passed", "Texas master plumber license M-41872 · Verified", "General liability insurance · $1M". Availability table (Mon–Fri 8:00 AM–6:00 PM, Sat 9:00 AM–1:00 PM, Sun Closed). Service area: 320 px map with the green radius circle and a "Covers" list of neighborhoods inside it.
   - Right sticky card (desktop, 380 px): price "from $89" + "★ 4.9 (16)"; segmented control "Instant book | Request a quote". Instant book: service select (with prices), a 14-day horizontal date strip of pills ("Tue 4" etc., greyed when unavailable), time slot grid (2-hour slots inside the pro's availability, minus taken slots and past times; "No open times this day" state), summary "Faucet replacement · $185" and green full-width "Continue to book". Request a quote: textarea "Describe the job" (placeholder "e.g. Kitchen faucet drips constantly and the handle is loose"), "When do you need it?" radio pills (As soon as possible / Within a week / I'm flexible / Pick a date), optional photo upload (up to 5), "Request quote" button. Under the card: "Responds in about 15 min" and "Your phone number stays private until you book." Guests are sent to sign in and returned to the same step.
   - "More plumbers near 78704" row of 3 cards at the bottom.
   - Phone: content single column, a sticky bottom bar (white, top Line, safe area): left "from $89" + "★ 4.9 (16)", right green "Book" pill → full-screen sheet with the booking card.
4. Booking flow (/book/:slug)
   - TaskRabbit-style progress stepper at the top (as in ref-08): "1 Details · 2 Date & time · 3 Payment", green line fill. Two columns: steps left, summary card right (pro photo + name, service, date/time, address, price, "Free cancellation up to 24 hours before"; customers never see the commission).
   - Details: street address (prefilled from the account), unit, ZIP, "Job details" textarea, optional photos, phone "Shared with your pro only after booking".
   - Date & time: month calendar + the same slot grid (skip when already picked on the profile; allow "Change").
   - Payment: two radio cards. "Pay now with card" — "Held by Trellis and released to Luis only after the job is done." with the card form (Stripe Payment Element when keys exist, else the "Test mode" demo form). "Pay after the job" — "Pay through Trellis once Luis marks the job done. We'll remind you." Button "Confirm and book · $185" with a spinner while saving.
   - Confirmation (/bookings/:ref): 64 px green check circle, H1 "You're booked!" (or "Request sent" when the pro must accept), "Luis Ortega will see you Tue, Nov 4 at 10:00 AM." Summary card with ref "TR-1061", status pill, payment line ("Paid · held until the job is done" / "Pay after the job"). Actions: "Message Luis", "Add to calendar" (downloads a valid .ics), "View my jobs". A contact row unlocked after booking: "Call" (tel:+15125550147), "Text" (sms:+15125550147?body=Hi Luis, it's Jordan about booking TR-1061), "WhatsApp" (https://wa.me/15125550147?text=...) as secondary pills.
   - Instant booking result: CONFIRMED if the pro has auto-accept on, otherwise PENDING ("Waiting for Luis to accept · usually within 15 min"). A quote request creates REQUESTED and opens the chat thread.
5. My jobs (/jobs) — customer
   - Tabs "Active" and "Past" with counts. Each job card: service + pro (photo, name), status pill, date/time or "Requested 2 hours ago", address short, price, payment line, and actions by state:
     - REQUESTED: "Waiting for Luis's quote" · Message · "Cancel request".
     - QUOTED: a quote box (Mist) "Rosa quoted $249" + her note + "Valid until Sat, Nov 8" → green "Accept & book" (goes to Date & time then Payment) and "Decline".
     - PENDING: "Waiting for Megan to accept" · Message · Cancel.
     - CONFIRMED: date and time big, "Call / Text / WhatsApp", Message, "Cancel booking" (free over 24 h before, confirm dialog).
     - COMPLETED: "Done Oct 28" · if PAY_AFTER and unpaid, green "Pay $185" (same card form) · "Leave a review" if none · "Report a problem".
     - DISPUTED: red pill "Under review" + "Trellis support is reviewing this job. We'll update you here."
     - CANCELLED / DECLINED: grey, with reason.
   - Leave a review: modal "How did Luis do?" 5 large stars (hover fill), tag chips (On time, Fair price, Great communication, Tidy, Expert work), textarea "Tell neighbors about your experience" (min 20 characters), "Post review" → toast "Thanks! Your review is live." → the pro's rating updates everywhere.
   - Report a problem: modal with reason select (Job not finished, Not as described, Damage, No-show, Overcharged), description, "Submit" → booking DISPUTED, held payment frozen, admin notified.
6. Messages (/messages, /messages/:threadId)
   - Desktop two panes: thread list 360 px (avatar, name, service chip, last message, time "2:14 PM" / "Mon", unread green dot; search box on top) and the chat: header with name, "View booking" link and Call/Text icons once booked; a context card pinned at the top (service, status pill, date, price); bubbles: mine = green #0B7A4B with white text right-aligned, theirs = Mist with Ink text, 18 px radius, time under each group; QUOTE messages render as a card ("Quote · $249 · Deep clean · Valid until Sat, Nov 8" + "Accept & book" for the customer); SYSTEM messages are centred 13 px Slate lines ("Booking confirmed for Tue, Nov 4 at 10:00 AM"). Composer: auto-growing textarea "Write a message…", green round send button, Enter sends, Shift+Enter new line. Optimistic send, then poll every 4 s. Opening a thread marks it read. On desktop the most recent thread opens automatically and is highlighted in the list.
   - Phone: list screen, then full-screen thread with a back arrow.

## Pro screens

7. Become a pro (/become-a-pro) and onboarding (/pro/onboarding)
   - Landing: hero H1 "Get hired by neighbors in Austin." sub "Create a free profile, answer job requests, and get paid when the work's done." green "Create your pro profile"; three steps ("Create your profile", "Answer requests and send quotes", "Get paid when the job's done"); a fee line "Free to join. Trellis keeps a 15% service fee on completed jobs. No lead fees, no subscription." (live % from Settings); an earnings example card "On a $200 job you earn $170.00".
   - Sign up as a pro (name, email, password), then a 5-step onboarding with a progress stepper; each step saves to the database on "Continue" so a reload resumes where you left off:
     1. Business: profile photo upload (round crop preview), full name, business name, category (8), headline (max 80 chars with counter), about, years in business, languages (chips), phone.
     2. Services: 1 to 6 service rows (name, description, price type Fixed price / Hourly / Free estimate, price, minimum hours, typical duration, "Allow instant book" switch). When the pro has no services yet, prefill 2 editable suggestions for their category: Cleaning: Standard clean (2 bed) $139 fixed, 3 hrs, instant; Deep clean $229, 4.5 hrs. Handyman: Handyman hour $60/hr, 2 hr min, instant; TV mounting $119, 1.5 hrs, instant. Plumbing: Service call & diagnosis $89, 1 hr, instant; Faucet replacement $185, 1.5 hrs, instant. Electrical: Service call $95, 1 hr; Light fixture install $125, 1.5 hrs, instant. Moving: 2 movers + truck $139/hr, 2 hr min; Loading & unloading help $80/hr, 2 hr min, instant. Tutoring: Tutoring session $60/hr, 1 hr min, instant; Test prep $85/hr, 1 hr min. Beauty at home: Haircut at home $65, 1 hr, instant; Blowout $55, 1 hr, instant. Pet care: Dog walk 30 min $22, instant; Drop-in visit $25, instant. Each with a one-line "What's included".
     3. Service area: base ZIP select + radius slider 1–30 mi with a live map circle and the computed "Covers: Downtown, Bouldin Creek, Zilker…" list.
     4. Availability: 7 day rows with a switch and start/end time selects; "Auto-accept instant bookings" switch.
     5. Verify your identity: dropzone "Upload a photo of your government ID (front)" (image preview), optional license number + license photo for Plumbing and Electrical, checkbox "I confirm this information is accurate and agree to a background check." → "Submit for review".
   - Then: "Thanks, Keisha — your profile is under review." "We review new pros within 1 business day. You'll get a notification here as soon as you're live." The pro dashboard shows an amber banner "Pending review — customers can't see your profile yet" until approved. Approved pros appear in search immediately and get the notification "You're approved! Your profile is live."
8. Leads (/pro/leads)
   - H1 "Leads" + "New job requests from customers in your area." Filter chips All / New / Quoted. Lead cards: customer first name + last initial, neighborhood + distance ("Bouldin Creek · 2.1 mi"), service, "When: Within a week", the job details text, photo thumbnails, "Received 25 min ago". Buttons: green "Send quote", secondary "Message", text "Decline" (reason select).
   - Send quote modal: amount ($), type (Fixed / Hourly), "What's included" textarea, earliest availability (date + time), "Quote valid for" (3 / 7 / 14 days). Live line under the amount: "You'll earn $204.00 after the 15% Trellis fee ($36.00)." Submit → status QUOTED, a QUOTE message in the thread, customer notified, toast "Quote sent to Priya".
   - Empty: "No new leads right now. Requests from customers near Travis Heights show up here."
9. Jobs (/pro/jobs)
   - Tabs (on phone the short labels "To accept", "Upcoming", "Waiting", "Done" so all four fit at 390 px): "Requests to accept" (PENDING instant bookings with Accept / Decline and a countdown "Respond within 23 hrs"), "Upcoming" (CONFIRMED, grouped Today / Tomorrow / This week), "Waiting on customer" (QUOTED), "Completed".
   - A today's job card is highlighted: "Today · 2:00 PM", service, customer, full address with "Directions" (Google Maps link), Call / Text / WhatsApp to the customer, payment line, green "Mark job done". Confirm dialog: "Mark this job as done? Grace will be asked to review you and your payout of $157.25 will be released." → COMPLETED, card payments RELEASED, payout PENDING, customer notified.
10. Earnings (/pro/earnings)
   - KPI cards (tabular numbers), metric name on line one and the period as a muted second line: "Earned" / "Last 30 days" (net), "Pending payout" / "Next payout Friday", "Completed jobs" / "Last 30 days", "Trellis fee paid" / "Last 30 days" (with the 15% note). A 6-month bar chart of net earnings (green bars, hover tooltip "Sep · $1,118.30"). Table: Date, Job, Customer, Price, Trellis fee, You earn, Payout ("Paid out Fri, Oct 31" / "Pending · Fri, Nov 7" / "Awaiting customer payment"). "Export CSV". Note: "Trellis keeps 15% of each completed job. Payouts go out every Friday."
11. Profile editor (/pro/profile): tabs Business, Services, Photos, Availability, Service area, Verification, reusing the onboarding forms, each with "Save changes" (disabled until dirty, toast "Saved") and a "View public profile" link. Services support add, edit, delete (confirm) and the instant book switch.

## Admin screens (/admin, Admin role only)

Layout: left sidebar 248 px (logo + "Admin" tag, nav with icons and count bubbles: Overview, Verification (4), Disputes (3), Bookings, Pros, Categories, Featured, Payouts, Settings), content max 1100 px. Phone: top bar with title and a horizontally scrolling tab row; tables turn into cards.
12. Overview: KPI cards "Gross bookings", "Trellis revenue", "Jobs completed" (each with a muted "Last 30 days" second line), "Active pros", "Awaiting verification", "Open disputes" (all computed). "Bookings per week" bar chart (12 weeks in Austin time, Ink bars, green for the current week, tooltip "Week of Oct 25 · 3 bookings"). "Bookings by status" list with counts for all 8 states and a link to each filtered list. "Latest activity" feed (booking created, quote sent, review posted, pro applied) with relative times.
13. Verification: queue of PENDING pros as cards: portrait, name, business, category, ZIP, "Submitted 2 days ago", services and prices preview, documents (ID thumbnail and license thumbnail; click opens a viewer modal with zoom), a 3-item checklist (Name matches ID, Photo matches profile, License is valid). Actions: green "Approve", "Request more info" (message), "Reject" (reason dialog; shows on the applicant's dashboard). Tabs Pending / Approved / Rejected.
14. Disputes: list with booking ref, customer vs pro, service, amount, reason, "Opened 3 days ago", status. Detail drawer (right sheet 520 px): timeline of the booking, both sides' statements, the last 6 chat messages, payment status, and resolution actions: "Refund customer in full", "Release payment to pro", "Partial refund" (amount input) + required note → RESOLVED, booking moves to COMPLETED or CANCELLED with the matching paymentStatus, both parties notified.
15. Bookings: filterable table (status chips for all 8 states, search by ref, customer or pro, category select), columns Ref, Customer, Pro, Service, Date, Price ("Quote pending" in Slate while a request has no price), Status, Payment. Row click opens a read-only drawer. Dispute rows show the booking price; after a partial refund "$185 · $40 refunded".
16. Pros: table (portrait, name, business, category, rating, reviews, "Jobs · 90 days" with "–" for zero and correct plurals, status) with Suspend / Reinstate.
17. Categories: grid of category cards (photo, icon, name, description, starting price, active pros count, Active switch) with "Add category" and Edit dialogs (name, slug, description, icon picker from the lucide set above, cover photo upload, sort order up/down). Inactive categories disappear from the customer side.
18. Featured: list of featured pros with toggles and a search box to add one (max 8); featured pros lead Home's carousel and get the "Top Pro" badge.
19. Payouts: range select (Last 30 days by default / This month / Last month / Last 90 days); table per pro: Pro, Jobs completed, Gross, Commission, Net, Paid out, Pending, with a totals row; "Run payouts for pending" (confirm → marks PENDING payouts PAID with today's date); "Export CSV".
20. Settings: "Platform commission" number input with % (default 15, 0–40) and a live example "On a $200 job the pro earns $170.00 and Trellis earns $30.00", "Payout day: Friday", integrations list (Stripe: Not connected — demo payments; Email notifications: Not connected; SMS: Not connected), "Reset demo data", which restores exactly the seed (it also clears the Session and Verification tables and removes sign-ups that aren't part of the seed, then runs PRAGMA wal_checkpoint(TRUNCATE) and VACUUM on the SQLite file).

## Seed data (fictional people, Austin, TX)

Austin ZIP table with lat/lng and neighborhoods: 78701 Downtown (30.2700,-97.7430), 78702 East Austin (30.2620,-97.7180), 78703 Tarrytown/Clarksville (30.2900,-97.7650), 78704 Travis Heights / Bouldin Creek / Zilker / South Congress / Barton Hills / South Lamar (30.2470,-97.7620), 78705 West Campus (30.2950,-97.7400), 78722 Cherrywood (30.2880,-97.7140), 78723 Mueller / Windsor Park (30.3030,-97.6990), 78741 Riverside / Montopolis (30.2330,-97.7150), 78745 St. Elmo (30.2140,-97.7690), 78746 Westlake (30.2900,-97.8140), 78751 Hyde Park / North Loop (30.3100,-97.7240), 78757 Crestview / Allandale (30.3430,-97.7380), 78758 North Austin (30.3780,-97.7100), 78613 Cedar Park (30.5052,-97.8203), 78653 Manor (30.3410,-97.5567), 78660 Pflugerville (30.4394,-97.6200), 78664 Round Rock (30.5083,-97.6789). Every person gets their own neighborhood centre plus a small random offset that is stable per person (never an exact address), so distances read 0.1–4 mi rather than all "0.4 mi": Travis Heights 30.2480,-97.7420; Bouldin Creek 30.2555,-97.7590; South Congress 30.2470,-97.7505; Zilker 30.2640,-97.7720; Barton Hills 30.2565,-97.7850; South Lamar 30.2450,-97.7810; St. Elmo 30.2140,-97.7690; East Austin 30.2620,-97.7180; Riverside 30.2390,-97.7230; Montopolis 30.2300,-97.6950; Hyde Park 30.3050,-97.7270; North Loop 30.3170,-97.7190; Mueller 30.2985,-97.7040; Windsor Park 30.3110,-97.6930; Cherrywood 30.2880,-97.7140; Crestview 30.3480,-97.7310; Allandale 30.3400,-97.7450; Tarrytown 30.2970,-97.7680; Clarksville 30.2830,-97.7600; Downtown 30.2690,-97.7430; West Campus 30.2870,-97.7450; Westlake 30.2900,-97.8140; North Austin 30.3780,-97.7100; Round Rock 30.5083,-97.6789; Pflugerville 30.4394,-97.6200; Cedar Park 30.5052,-97.8203; Manor 30.3410,-97.5567.

Categories (sortOrder in this order): Cleaning ("Regular, deep and move-out cleans", from $109), Handyman ("Mounting, assembly and small repairs", from $52/hr), Plumbing ("Leaks, drains, fixtures and water heaters", from $85), Electrical ("Fixtures, fans, outlets and EV chargers", from $89), Moving ("Movers, trucks and heavy lifting", from $70/hr), Tutoring ("Math, reading, test prep and languages", from $45/hr), Beauty at home ("Hair, makeup and nails at your place", from $25), Pet care ("Walks, sitting, grooming and training", from $22). Starting prices are computed from services.

40 approved pros (name — business — neighborhood ZIP — years — typical response — services with prices — flags). Write a specific headline and a 3-4 sentence first-person bio for each, availability that fits the trade, a radius of 8-20 mi, and languages. Every service gets a specific one-sentence description and a realistic duration (e.g. Drain cleaning: "Snake one clogged sink, tub or shower drain and clear the trap; camera check if it keeps coming back." About 1 hr. Faucet replacement: "Remove the old faucet, install your new one (or one I bring), new supply lines, leak test." About 1.5 hrs. Water heater replacement: "Haul away the old tank and install a new 40–50 gal gas or electric heater to code, with permit." About 4 hrs). Durations display rounded to the half hour.
Cleaning:
- Rosa Delgado — Bright Nest Cleaning — Hyde Park 78751 — 9 — 10 min — Standard clean (2 bed) $139 instant, Deep clean $229 instant, Move-out clean $289, Hourly cleaning $48/hr 2 hr min — featured, English/Spanish.
- Mei Tanaka — Tidy Haus Austin — Mueller 78723 — 5 — 20 min — Standard clean $129 instant, Deep clean $219 instant, Home organizing $55/hr.
- Danielle Brooks — Fresh Start Cleaners — Riverside 78741 — 7 — 30 min — Standard clean $119, Move-out clean $259, Post-construction clean free estimate.
- Ana Lucía Ferreira — Casa Limpia Co. — East Austin 78702 — 12 — 15 min — Standard clean $145 instant, Deep clean $239, Short-term rental turnover $95 instant — featured, English/Spanish/Portuguese.
- Tyler Nguyen — Spotless ATX — North Loop 78751 — 1 — 1 hr — Standard clean $109 instant — New on Trellis.
Handyman:
- Marcus Bell — Bell & Sons Handyman — Crestview 78757 — 15 — 25 min — Handyman hour $65/hr 2 hr min instant, TV mounting $129 instant, Drywall patch $149, Door repair $95 — featured.
- Priya Raman — Fixwell Home Repair — Allandale 78757 — 6 — 15 min — Furniture assembly $55/hr instant, Shelves & art hanging $89 instant, Re-caulk tub or shower $119.
- Hank Morales — Hill Country Handyman — South Congress 78704 — 20 — 45 min — Handyman hour $70/hr, Fence repair $175, Deck repair free estimate — English/Spanish.
- Jamal Carter — Carter Fix-It — Windsor Park 78723 — 4 — 20 min — TV mounting $119 instant, Smart lock & doorbell install $99 instant, Handyman hour $58/hr.
- Sofia Petrova — Level Line Repairs — Barton Hills 78704 — 3 — 35 min — Furniture assembly $52/hr instant, Picture hanging $79, Minor repairs $60/hr — English/Russian.
Plumbing (all "Licensed"):
- Luis Ortega — Ortega Plumbing Co. — Travis Heights 78704 — 11 — 15 min — Service call & diagnosis $89 instant, Faucet replacement $185 instant, Toilet repair $165 instant, Drain cleaning $149 instant, Water heater replacement free estimate — featured, license M-41872, insured, auto-accept OFF, English/Spanish, Mon–Fri 8–6, Sat 9–1, radius 12 mi. Bio: "I've been fixing Austin's pipes for 11 years, the last six with my own shop. Most jobs are same-week, and you always get the price before I start. Licensed, insured, and I clean up like it's my own kitchen. Hablo español."
- Grace Whitfield — Whitfield Plumbing — Tarrytown 78703 — 18 — 40 min — Service call $95, Leak repair $175, Water heater install free estimate, Repiping free estimate.
- Dev Patel — FlowRight Plumbing — Cedar Park 78613 — 8 — 20 min — Drain cleaning $139 instant, Garbage disposal install $210, Sewer line inspection free estimate.
- Carlos Mendoza — Mendoza Rooter & Drain — Montopolis 78741 — 10 — 30 min — Drain cleaning $129 instant, Hydro jetting $349, Toilet install $225 — English/Spanish.
- Hannah Kim — Pipeline Pros ATX — Round Rock 78664 — 2 — 1 hr — Faucet install $165, Service call $85 — New on Trellis.
Electrical (all "Licensed"):
- Ben Okafor — Okafor Electric — Cherrywood 78722 — 13 — 20 min — Service call $99 instant, Light fixture install $125 instant, Ceiling fan install $165 instant, Outlet or switch replacement $95, Panel upgrade free estimate, EV charger install free estimate — featured.
- Rachel Stein — Bright Wire Electric — Zilker 78704 — 9 — 30 min — Recessed lighting $145 per light, Ceiling fan install $175 instant, Smart switches $110.
- Tomás Rivera — Rivera Electrical Services — Pflugerville 78660 — 16 — 45 min — Service call $89, Panel upgrade free estimate, Generator hookup free estimate — English/Spanish.
- Kevin Zhou — Volt & Co. — Downtown 78701 — 5 — 15 min — EV charger install free estimate, Outdoor lighting $189, Outlet install $105 instant.
- Aisha Johnson — Current Electric ATX — St. Elmo 78745 — 3 — 25 min — Light fixture install $115 instant, Troubleshooting visit $95.
Moving:
- Andre Williams — Longhorn Lift Movers — Riverside 78741 — 8 — 20 min — 2 movers + truck $139/hr 2 hr min instant, Loading & unloading help $85/hr instant, Junk haul-away $189 — featured, insured.
- Emily Sorensen — Bluebonnet Moving Co. — North Austin 78758 — 6 — 30 min — 3 movers + truck $179/hr 3 hr min, Packing help $60/hr, Piano move free estimate.
- Diego Castillo — Castillo Haul & Move — Manor 78653 — 4 — 1 hr — Moving labor only $70/hr 2 hr min instant, Junk removal $165 — English/Spanish.
- Nate Harper — Easy Load ATX — Westlake 78746 — 10 — 25 min — Furniture pickup & delivery $99 instant, Storage unit move $149.
- Leila Haddad — Lighthouse Packing & Moving — Clarksville 78703 — 2 — 40 min — Packing & unpacking $58/hr, Move planning call $75 — New on Trellis, English/Arabic.
Tutoring (online or in-home):
- Samuel Osei, PhD — Osei Math Lab — Hyde Park 78751 — 12 — 1 hr — Algebra & geometry $65/hr instant, Calculus & AP Calc $80/hr instant, SAT/ACT math $90/hr.
- Lauren Park — Park Reading & Writing — Allandale 78757 — 7 — 30 min — Reading K–5 $55/hr instant, Essay coaching $70/hr.
- Javier Ruiz — Hablemos Spanish — Bouldin Creek 78704 — 5 — 20 min — Spanish conversation $50/hr instant, Spanish for kids $45/hr instant — English/Spanish.
- Olivia Grant — Grant Test Prep — Tarrytown 78703 — 9 — 45 min — SAT prep $95/hr, ACT prep $95/hr, College essays $110/hr.
- Arjun Mehta — Code Club ATX — Mueller 78723 — 2 — 15 min — Intro to Python $60/hr instant, Scratch for kids $50/hr instant — New on Trellis.
Beauty at home:
- Camila Reyes — Camila Hair at Home — South Lamar 78704 — 10 — 10 min — Haircut at home $70 instant, Blowout $55 instant, Balayage $210, Bridal hair $180 — featured, English/Spanish.
- Jasmine Taylor — Glow On Call — East Austin 78702 — 6 — 20 min — Event makeup $110 instant, Bridal makeup $180, Lash lift $90.
- Thi Lan Pham — Nail Nook Mobile — North Loop 78751 — 8 — 25 min — Gel manicure $50 instant, Spa pedicure $65 instant, Mani-pedi combo $105 — English/Vietnamese.
- Brianna Cole — Fade & Fringe Barber — Windsor Park 78723 — 5 — 30 min — Men's cut at home $45 instant, Kids cut $35 instant, Beard trim $25.
- Noor Aziz — Brow & Lash House Calls — Cedar Park 78613 — 3 — 40 min — Brow shaping $40 instant, Lash extensions $140, Lash fill $70.
Pet care:
- Megan O'Neill — Happy Tails Walks — Zilker 78704 — 6 — 10 min — Dog walk 30 min $22 instant, Dog walk 60 min $35 instant, Drop-in visit $25 instant, Overnight sitting $85 per night — featured, auto-accept ON.
- Chris Alvarez — Barton Creek Pet Sitting — Barton Hills 78704 — 4 — 20 min — Drop-in visit $24 instant, Overnight sitting $80 per night.
- Kayla Robinson — Suds & Snips Mobile Grooming — Round Rock 78664 — 7 — 45 min — Full groom small dog $85, Full groom large dog $120, Bath & tidy $60 instant.
- Ethan Brooks — Good Dog Training ATX — Crestview 78757 — 9 — 30 min — Private training session $75 instant, Puppy basics (4 sessions) $260.
- Isabel Cruz — Whiskers & Paws Cat Care — Clarksville 78703 — 3 — 25 min — Cat drop-in $22 instant, Litter & meds visit $28 instant.
Featured (Top Pro): Rosa, Ana Lucía, Marcus, Luis, Ben, Andre, Camila, Megan.

5 pending applicants in the Verification queue (not visible to customers), each with services, an uploaded ID document and portrait: Keisha Monroe — Sparkle & Shine Cleaning — Pflugerville — submitted 2 days ago; Victor Hale — Hale Electric — Round Rock — license TECL 55120 — 1 day ago; Rina Sato — Paws on Parade — Hyde Park — 5 hours ago; Omar Shaikh — Shaikh Tutoring — North Austin — 3 days ago; Brett Lawson — Lawson Plumbing — Westlake — license M-52219 — 4 days ago. One rejected: Quick Fix Guys (reason "Name on the ID didn't match the profile"). For ID documents use one generated SVG at webapp/public/images/demo-id.svg: a neutral grey card with a person silhouette, grey bars and a red "SAMPLE · NOT A REAL ID" stamp (no realistic license design).

30 customers with neighborhoods (shown publicly as first name + last initial): Jordan Ellis (demo), Priya Shah, Daniel Kim, Maria Gonzalez, Ashley Turner, Omar Farouk, Grace Liu, Kevin O'Brien, Fatima Ali, Ryan Cooper, Natalie Vega, Ben Harris, Chloe Martin, Isaac Green, Sara Lindqvist, Mateo Silva, Hannah Walsh, Elijah Moore, Zoe Adams, Aaron Fischer, Lily Chen, Noah Bennett, Emma Rodriguez, Jacob Wright, Ava Collins, Sam Okoro, Mia Novak, Leo Garcia, Ruby Ellison, Theo Lambert. Phones (512) 555-0101 to 0199.

300 reviews: per pro Rosa 14, Mei 9, Danielle 7, Ana Lucía 12, Tyler 2, Marcus 13, Priya R. 8, Hank 6, Jamal 7, Sofia 4, Luis 16, Grace 9, Dev 7, Carlos 5, Hannah 3, Ben 12, Rachel 8, Tomás 6, Kevin 5, Aisha 3, Andre 14, Emily 8, Diego 5, Nate 6, Leila 3, Samuel 11, Lauren 7, Javier 6, Olivia 5, Arjun 3, Camila 13, Jasmine 8, Thi Lan 8, Brianna 6, Noor 4, Megan 14, Chris 8, Kayla 6, Ethan 6, Isabel 3. Spread over the last 18 months, mostly 5 stars with some 4s, a few 3s and two or three 1–2 star reviews, about 40% with a pro reply. Every review is specific to the trade and the service (what was done, how long, a detail), 1–3 sentences; no two reviews share a sentence or a distinctive phrase, and a customer reviews a given pro at most once (keep a small check script for this). Write them in seed files split by category. Examples of the voice:
- Luis, by Priya S., 5★, Faucet replacement: "Luis showed up inside the window, found the leak was the supply line, not the faucet, and saved us $150. Explained everything in plain English." Reply: "Thanks Priya! Call me anytime that kitchen sink acts up again."
- Rosa, by Ashley T., 5★, Move-out clean: "Rosa and her partner did the move-out clean on our 2-bed in Hyde Park and we got the whole deposit back. They even did the inside of the oven."
- Marcus, by Kevin O., 5★, TV mounting: "Mounted a 65-inch TV above our brick fireplace and ran the cables inside the wall. Two hours, and he vacuumed up every bit of dust."
- Andre, by Zoe A., 5★, 2 movers + truck: "Third-floor walk-up, three hours, not a single scratch. His crew wrapped every piece of furniture before it left the apartment."
- Samuel, by Mia N., 5★, Algebra & geometry: "My son went from a C to a B+ in Algebra II in six weeks. Dr. Osei makes it click without making him feel slow."
- Camila, by Chloe M., 5★, Blowout: "Best blowout I've had, in my own bathroom, two hours before a wedding. She brought everything, even a ring light."
- Megan, by Jordan E., 5★, Dog walk 60 min: "Megan sends a photo and a map of every walk. Biscuit runs to the door when she hears her car."
- Hank, by Ryan C., 3★, Fence repair: "Solid repair on the fence, but he showed up an hour late and didn't text. Work itself was good."

60 bookings, with every state represented: REQUESTED 8, QUOTED 6, PENDING 4, CONFIRMED 10, COMPLETED 24, CANCELLED 3, DECLINED 2, DISPUTED 3, refs TR-1001 to TR-1060 in date order. Create them across the last 12 weeks with a gentle upward trend (at least 2 a week) so the admin chart is full; about 10 completed jobs fall in the last 30 days. Future jobs sit on each pro's time grid, only on days they work, and booked slots block the job's real duration (not a fixed 2 hours). Must include:
- Jordan (customer): TR-1058 REQUESTED Water heater replacement with Luis ("Our 40-gallon gas water heater is 14 years old and leaking at the base." · within a week · 2 hours ago); TR-1055 QUOTED Deep clean with Rosa (quote $249, "Includes inside the oven and fridge, baseboards and both bathrooms.", valid 5 more days); TR-1053 CONFIRMED Dog walk 60 min with Megan tomorrow 12:00 PM, card HELD (Megan auto-accepts); TR-1050 CONFIRMED Ceiling fan install with Ben in 3 days 9:00 AM, pay after the job; TR-1047 DISPUTED TV mounting with Marcus, $129 card HELD, 9 days ago, reason "Job not finished" ("The TV is up but the cables are hanging below it. We agreed he'd run them inside the wall."); TR-1041 COMPLETED Faucet replacement with Luis, $185, 6 days ago, card RELEASED, no review yet; TR-1030 COMPLETED Haircut at home with Camila $70, reviewed; TR-1022 COMPLETED 2 movers + truck with Andre, 3 hrs = $417, reviewed; TR-1015 CANCELLED Algebra & geometry with Samuel (cancelled by Jordan a month ago).
- Luis (pro): leads TR-1058 (Jordan), TR-1059 Priya S. "Kitchen sink drains slowly and gurgles" Bouldin Creek, ASAP, 25 min ago, TR-1060 Ruby E. "Toilet keeps running all night" Bouldin Creek, flexible, 1 day ago; TR-1054 QUOTED hose bib replacement for Theo L. ($165); TR-1057 PENDING Drain cleaning $149 for Mateo S. in 2 days 1:00 PM, card HELD (needs Accept); TR-1056 CONFIRMED Faucet replacement $185 for Grace L. TODAY 2:00 PM, card HELD; TR-1051 CONFIRMED Service call $89 for Sam O. in 4 days 10:00 AM, pay after; 14 COMPLETED jobs over the last 6 months, at least 2 every month and 3 in the last 30 days, mixing card (RELEASED) and pay-after (PAID), so his earnings chart has a bar every month (including TR-1041, a $1,850 water heater install 3 months ago, and TR-1029 for Ava C. whose dispute was RESOLVED with a $50 partial refund); TR-1024 DECLINED for Leo G. ("Gas line for an outdoor kitchen", reason "Outside my license scope"). Past payouts PAID on Fridays, the most recent completed one PENDING.
- The other bookings spread across the other pros and customers; disputes also on Danielle Brooks (Chloe M., "Not as described": oven skipped in a deep clean, $229) and Diego Castillo (Kevin O., "Damage": scratched dresser, $280).

Chats: about 35 threads with 3–10 realistic messages each, including every one of Jordan's and Luis's bookings above. Examples: Jordan to Megan "Biscuit pulls a little at first, but he settles after a block. Harness is on the hook by the door."; Megan "Perfect, I'll use the front clip. See you tomorrow at noon!"; Luis to Grace "On my way, about 20 minutes out. I have the Moen cartridge you picked."; quote messages as QUOTE cards; system lines for confirmations.

## Images (generate them, AI people only)

Run env to find the project's proxied OPENAI_API_KEY and call https://api.openai.com/v1/images/generations with model "gpt-image-2.5-flare". Write one idempotent script (backend/scripts/generate-images.ts) that skips files that already exist, runs 6 requests at a time, retries twice, converts with sharp to JPEG (portraits 640 px q82, photos 1400 px q80) and saves into webapp/public/images/ so remixes keep them. Start it in the background early and keep building; the UI falls back to the category photo or initials until an image exists. Generate:
- 45 portraits (the 40 pros + 5 applicants; keep a check script that confirms every portrait, cover and work photo path is a real JPEG), 1024x1024: "Natural-light candid portrait photograph of a [age] [ethnicity] [gender] [trade] professional in Austin, Texas, wearing [work clothes for the trade], [setting: porch, kitchen, workshop, park, salon chair], looking at the camera with a relaxed, friendly smile, 50mm lens, shallow depth of field, warm late-afternoon light, realistic skin texture, editorial style, no text, no logos." Vary ages (25–60), ethnicities and settings; match each pro's name and trade.
- 8 category covers, 1536x1024, real-looking photography: Cleaning (gloved hands wiping a bright white kitchen counter in a Craftsman bungalow), Handyman (hands mounting a TV on a white wall with a drill and level), Plumbing (a plumber's hands tightening a new chrome kitchen faucet), Electrical (an electrician installing a pendant light above a dining table), Moving (two movers carrying a mid-century sofa down porch steps), Tutoring (a tutor and a teenager working through algebra at a sunlit kitchen table), Beauty at home (a stylist giving a blowout in a bright living room), Pet care (a dog walker with two happy dogs on a leafy Austin street).
- The hero, 1024x1536 portrait: a cleaner (Rosa, Latina, 40s, sage green apron) smiling in a sunlit Hyde Park craftsman living room, cinematic, realistic.
- The pro band photo, 1536x1024: an electrician on a short ladder in a bright hallway, warm light.
- 24 work photos (3 per category), 1536x1024, no people's faces: e.g. spotless bathroom, organized pantry, made bed with fresh linens; mounted TV with hidden cables, patched and painted drywall, assembled bookshelf; new faucet, neat P-trap under a sink, new water heater; ceiling fan, recessed lights, EV charger on a garage wall; moving truck loaded with blankets, labelled boxes, wrapped sofa; open notebook with algebra, Spanish flashcards, kid's reading book; finished blowout from behind, gel manicure, makeup kit; groomed doodle, leash by the door, cat on a windowsill. Pros show the 3 photos of their category (plus any uploads) with specific captions.

## Interactions and animation

Hover lifts on cards (150 ms), photo zoom 1.04 on category cards, map pin and list highlight in sync, autocomplete dropdown fades and slides 6 px in 120 ms, sheets and drawers slide in 240 ms ease-out, modals fade + scale from 0.98, star rating hover fill, skeleton shimmer, toasts (sonner) bottom-centre for every save ("Quote sent to Priya", "Booking confirmed", "Review posted", "Saved"), all styled the same: Ink #16181D background, white 14 px text, green check icon, 12 px radius; errors use the same toast with a "Try again" action, buttons show a spinner and disable while saving. Respect prefers-reduced-motion.

## Loading, empty and error states

Every list has a skeleton loader and a written empty state with a next action (My jobs: "You haven't booked anything yet." + "Find a pro"; Messages: "No messages yet. Start by messaging a pro from their profile."; Earnings: "No completed jobs yet."; Admin queues: "Nothing waiting. Nice."). Form errors appear under the field in #B42318 13 px; ZIP must be 5 digits; prices above $0. Failed requests show a toast with "Try again", and nothing is lost from forms. Unknown pro or booking → a friendly not-found page with a way back. Signed-out users who hit a protected page go to /signin and return afterwards.

## Phone layout (390 px) — most customers book on phones

Accessibility: every visible form label is linked to its control (htmlFor + id) on every form, each field's error sits directly under that field, and every overlay (phone booking sheet, filters sheet, drawers, dialogs) is a real dialog (shadcn Sheet/Drawer/Dialog: role="dialog", aria-modal, focus trap, Esc/back closes).

Design phone first and check every screen at 390 px: no horizontal scroll, tap targets at least 44 px, 16 px inputs (no iOS zoom), the bottom tab bar never covers content (pad the page), sticky bottom CTAs on profile and booking, bottom sheets for filters, booking and dialogs, tables become stacked cards, the home hero stacks as photo (260 px, no radius) → headline → search card → chips (scroll) → categories as a 2-column grid → pros carousel with 260 px cards.

## Build order

Build in small source files (one component or route per file, none over about 250 lines), in this order, and get a first version running before polishing:
1. Theme (fonts, colours, radius in Tailwind), logo, favicon, title, demo bar, header, footer, phone tab bar.
2. Prisma schema, Better Auth with roles, the seed (split into files: zips, categories, pros by category, customers, reviews by category, bookings, chats) and auto-seed on boot; check the counts with a script.
3. Start the image script in the background.
4. API routes per resource (categories, search, pros, bookings, quotes, payments, messages, reviews, disputes, notifications, pro, admin, settings, uploads), each tested with curl.
5. Home, Search with map, Pro profile.
6. Sign in / sign up and the demo accounts modal.
7. Booking flow, confirmation, My jobs, reviews, report a problem, Messages.
8. Pro: Leads, Jobs, Earnings, Profile editor, Become a pro + onboarding.
9. Admin: Overview, Verification, Disputes, Bookings, Pros, Categories, Featured, Payouts, Settings.
10. Phone pass at 390 px, loading/empty/error states, then click through every flow in the preview (book, quote → accept → pay, message, mark done, review, dispute → resolve, approve a pro, change commission) and fix every console error.

Build it fully, run it, and fix every error, checking every screen at 1440 px and 390 px. Finish by deleting refs/. Deliver the complete app, not a plan.
All templates