Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Home Helper — Full-Stack Home Services Booking Platform

Home Helper is a full-stack, multi-service platform that runs the entire lifecycle of an on-demand home service (house cleaning, ironing, and similar recurring services) — from the customer booking and paying online, through dispatching a real service provider in the field via an automated WhatsApp chatbot, to the job being completed and the CRM pipeline reflecting every step in between.

It's a portfolio project demonstrating production-grade backend architecture (clean architecture, dependency injection, event/webhook-driven services, background job processing) across two bridged subsystems: a sales & booking system that takes the customer's money, and an operations & fulfillment system that turns that sale into a dispatched cleaner at someone's door — coordinated entirely through CRM pipeline stages and a stateful WhatsApp chatbot, with no human dispatcher required.

Keywords: full-stack TypeScript, Node.js REST API, React, PostgreSQL, Prisma ORM, Redis, BullMQ job queues, clean architecture, dependency injection, event-driven microservices, payment gateway integration, WhatsApp Business API chatbot automation, CRM pipeline integration, webhook-driven workflows, field-service dispatch, multi-tenant SaaS, service marketplace, booking platform, franchise management system.

What problem does this solve?

Home-service businesses that operate across multiple cities/franchises need to:

  • Let customers book and pay for a service online, with pricing and availability that differ by city/branch
  • Track every booking through a status pipeline (created → checkout → paid → completed) with full history and audit logging
  • Turn a paid booking into an actual dispatched job: broadcast it to available service providers, let one accept it over WhatsApp, and lock out the rest
  • Keep both the customer and the assigned provider automatically informed at every stage — booking confirmed, provider assigned, day-of reminders, en route, check-in, check-out — without a human coordinator
  • Keep the CRM's sales pipeline and operational pipeline in sync with real-world job status at all times
  • Automatically follow up on abandoned carts and overdue payments
  • Let an internal team manage pricing, coupons, coverage areas, and holidays without touching code

Home Helper implements all of this as a set of independently deployable services rather than one monolith, with the CRM acting as the integration point between the sales side and the operations side.

Repository structure

Service What it is Stack README
back-end Sales & booking REST API — the booking domain, payment gateway integration, and CRM/marketing-funnel lead creation Node.js, Express 5, TypeScript, Prisma, PostgreSQL, Redis, BullMQ README
worker Sales-side background jobs — checkout reminders, status notifications, cart-abandonment recovery Node.js, TypeScript, BullMQ, Prisma README
front-end-client Customer-facing booking flow (the public website) React, TypeScript, Vite, MUI, Zustand README
front-end-admin Internal admin dashboard (coupons, holidays, franchise coverage map) React, TypeScript, Vite, MUI, Data Grid README
service-backend Operations orchestrator — listens for a CRM "lead converted" webhook, creates the internal service order, and keeps the CRM's operational pipeline in sync with real-world job status Node.js, Express, TypeScript, Prisma README
service-worker WhatsApp chatbot dispatch engine — broadcasts jobs to providers, runs the accept/decline conversation, and drives every stage (confirmations, en route, check-in/out) for both provider and customer Node.js, TypeScript, BullMQ README

There's no shared build tool (no Turborepo/Nx) — each service is an independent package with its own dependencies and lockfile, deployable on its own.

Architecture

flowchart LR
    Customer((Customer))
    Provider((Service Provider))

    subgraph SALES["Sales & Booking"]
        FEC[front-end-client]
        FEA[front-end-admin]
        BE[back-end API]
        WK[worker]
        RD1[(Redis queues)]
    end

    subgraph BRIDGE["CRM — the integration bus"]
        CRMC[Commercial pipeline]
        CRMO[Operational pipeline]
    end

    subgraph OPS["Operations & Fulfillment"]
        SB[service-backend<br/>orchestrator]
        SW[service-worker<br/>chatbot engine]
        RD2[(Redis queues)]
    end

    PG[Payment Gateway<br/>Pix / Boleto / Card]
    WA[[WhatsApp<br/>Evolution API]]
    DB[(PostgreSQL)]

    Customer -->|books & pays| FEC
    FEC -->|REST| BE
    FEA -->|REST| BE
    BE --> DB
    BE --> PG
    BE -->|create/update lead| CRMC
    BE -->|enqueue jobs| RD1
    WK -->|consume jobs| RD1
    WK -->|status & cart-abandonment notifications| WA

    CRMC -->|lead converted webhook| SB
    SB -->|create service order| DB
    SB <-->|sync stage| CRMO
    SB -->|enqueue dispatch jobs| RD2
    RD2 --> SW
    SW <-->|broadcast job, accept/decline,<br/>confirmations, en route, check-in/out| WA
    WA <-->|chat| Provider
    WA -->|status updates| Customer
    SW -->|sync stage| CRMO
Loading

Two independently deployable subsystems, bridged entirely through the CRM: back-end creates a lead in the CRM's commercial pipeline the moment a customer pays; when that lead is marked converted, a webhook hands it off to service-backend, which creates the internal service order and mirrors every subsequent status change into a separate operational pipeline in the same CRM. From there, service-worker runs the actual fulfillment as a stateful WhatsApp chatbot: it broadcasts the job to available providers, processes the first "accept" reply, locks out the rest, and then drives the provider and the customer through confirmations, en-route, check-in, and check-out — entirely through conversational WhatsApp messages, with cron jobs handling the time-based steps (reminders) and inbound webhooks handling the interactive ones (accept/decline, check-in/out).

Both subsystems also follow a provider adapter pattern for their external integrations (payment gateway, WhatsApp/messaging channel, CRM connection), each modeled as a Factory + Resolver + Provider interface resolved per city/branch — so a single deployment can run different payment gateways, WhatsApp instances, or CRM pipelines for different franchises.

WhatsApp chatbot flow

The dispatch/fulfillment side of the platform has no human dispatcher — it's a chatbot conversation, entirely over WhatsApp, that carries a service order from "published" to "completed." Each stage below is its own workflow class in service-worker (its name matches the real chat_session.workflow value persisted in the database), and every stage transition is mirrored to the CRM's operational pipeline via OpsPlatformIntegrationService:

flowchart TD
    Start(["Service order created<br/>(CRM lead converted)"]) --> Published["🟢 SERVICE_PUBLISHED<br/>job broadcast to the WhatsApp provider group"]

    Published -->|"first provider to reply '1 - confirm' wins"| ASP{{"ASSIGN_PROVIDER"}}
    ASP -->|confirms| Assigned["🟢 PROVIDER_ASSIGNED<br/>broadcast deleted for other providers<br/>customer notified"]
    ASP -->|declines| Published

    Assigned --> C24{{"CONFIRMATION_24H<br/>(24h before)"}}
    C24 -->|provider confirms| PreC2H["🟢 CONFIRMATION_2H<br/>customer notified"]
    C24 -->|provider declines + reason| Declined["🔴 PROVIDER_DECLINED<br/>re-broadcast to group"]
    C24 -->|customer cancels + reason| CustCanceled["🔴 CUSTOMER_CANCELED"]
    Declined -.-> Published

    PreC2H --> C2H{{"CONFIRMATION_2H<br/>(2h before)"}}
    C2H -->|"provider: on the way"| EnRoute["🟢 EN_ROUTE<br/>customer notified"]
    C2H -->|"provider: running late"| DelayMsg["notify customer + branch of delay"] --> C2H
    C2H -->|"provider: reports a problem"| Incident1[["⚠️ incident logged<br/>branch notified"]]

    EnRoute --> ERT{{"EN_ROUTE"}}
    ERT -->|"provider checks in on arrival"| CheckedIn["🟢 CHECK_IN"]
    ERT -->|"still en route"| ERT
    ERT -->|"provider: reports a problem"| Incident2[["⚠️ incident logged"]]

    CheckedIn --> CIN{{"CHECK_IN"}}
    CIN -->|"provider: job finished"| CheckedOut["🟢 CHECK_OUT"]
    CIN -->|"still working, gives ETA"| BranchNotice["notify branch of delay"] --> CIN
    CIN -->|"provider: reports a problem"| Incident3[["⚠️ incident logged"]]

    CheckedOut --> COT{{"CHECK_OUT"}}
    COT -->|"customer confirms all good"| Completed(["✅ COMPLETED<br/>thank-you messages sent"])
    COT -->|"customer reports a problem + details"| Incident4[["⚠️ incident logged<br/>escalated to ops team"]]
Loading

Every diamond in the diagram is, in the actual code, a small conversational state machine of its own — a "greet with numbered options" message, an answer-validation step, and a branch per option (proceed / report a delay / report a problem) — with chat_session.from/to persisting exactly which step a given phone number is on. Because that state lives in the database rather than in memory, the conversation survives a worker restart and can be picked up by any instance consuming the queue. The PROVIDER and CUSTOMER sides of each stage are handled as two separate conversation branches within the same workflow class, since the two audiences see different message copy and options at the same lifecycle stage.

Key features

Sales & booking:

  • Multi-branch / multi-city coverage — pricing, service plans, payment gateways, WhatsApp numbers, and holidays are all scoped per covered city
  • Full booking lifecycle — a service_solicitation moves through created → initiated_checkout → completed / cart_abandonment / payment_confirmed / payment_overdue / payment_refunded, with every transition recorded in a status-history table and an audit log
  • Real payment integration — Pix, Boleto, and credit card via a pluggable payment gateway adapter (implemented for Asaas)
  • CRM/sales-funnel sync — every booking is pushed to the CRM as a contact/opportunity in the commercial pipeline
  • Discount coupons, out-of-coverage lead capture, holiday-aware scheduling (national/state/municipal holidays)
  • Admin dashboard for coupon management, holiday management, and a franchise coverage map (Google Maps)

Operations & fulfillment:

  • Webhook-driven service order creation — a CRM "lead converted" event automatically creates the internal service order, no manual data entry
  • Automated WhatsApp job dispatch — the job is broadcast to a group of available service providers; the chatbot processes the first "I accept" reply, assigns that provider, and removes the offer from the rest
  • Stateful chatbot conversations — a persisted chat-session state machine drives multi-step conversations (accept/decline, check-in, check-out) with both the assigned provider and the customer
  • Automated day-of reminders — 24h and 2h confirmation messages, en-route notification, and completion confirmation, all cron-scheduled and sent without human intervention
  • Bidirectional CRM pipeline sync — every internal status change (assigned, en route, checked in, completed) is mirrored to the CRM's operational pipeline stage in real time

Cross-cutting:

  • Rate limiting, API-key auth, CORS allow-listing, and structured logging on both APIs
  • Encryption at rest for third-party credentials stored in the database (see the back-end README)

Engineering highlights

  • Clean/modular backend architecture — each domain module (serviceSolicitation, discountCoupon, coveredCity, etc.) has a consistent routes → controller → use case split, with routes and DI providers auto-discovered at boot instead of manually registered
  • Dependency injection via tsyringe, Zod schema validation at the HTTP boundary, and Prisma transactions for multi-table writes (e.g. creating a booking + its status history + its audit log atomically)
  • Factory/Resolver/Provider adapter pattern for every third-party integration, keyed by a provider enum per city/branch
  • BullMQ + Redis for background job processing, decoupled from the request/response cycle, in both subsystems
  • Event/webhook-driven service boundaryback-end and service-backend don't call each other directly; they're decoupled through CRM webhooks and pipeline stages, so either side can be redeployed or replaced independently
  • Persisted conversation state machine — the WhatsApp chatbot in service-worker tracks each conversation's state (chat_session.from/to) in the database rather than in memory, so a multi-step exchange survives process restarts and works across a distributed set of workers

Getting started

Each service is run independently — see its own README for setup:

Sales & booking:

  1. back-end — start Postgres/Redis, run migrations, yarn dev
  2. workeryarn worker
  3. front-end-client and front-end-adminpnpm install && pnpm dev

Operations & fulfillment: 4. service-backend — start Postgres/Redis, run migrations, yarn dev 5. service-workeryarn worker

Tech stack

TypeScript · Node.js · Express · React · Vite · PostgreSQL · Prisma ORM · Redis · BullMQ · Zod · tsyringe (Dependency Injection) · Material UI · Zustand · Docker · CapRover

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages