DEV Community

Cici Yu for Momen

Posted on

BayHaul: An AI Junk Removal Booking App Built with Momen and Claude Code

Junk removal is hard to quote remotely — the price depends on what the items actually are and how far the crew has to drive. BayHaul solves both: customers describe their junk and upload photos, and a multimodal AI agent analyzes both together to return a price range with a detected-items breakdown. When they schedule a pickup, the backend calculates real driving distance from the company warehouse before the request ever reaches staff.

The Momen backend handles the AI quoting, the routing calculation, and a two-role permission system — all without server code. The frontend is a React + Vite app built with Claude Code using the Momen no-code plugin.

Try the live app · Open in Momen editor / Clone project

What the App Does

A customer signs up with email and password, then creates a removal request: a text description of what they need hauled, plus one or more photos. Submitting the request kicks off an async AI quoting flow in the background. When the estimate is ready, the request shows a price range (low and high in USD) and a structured breakdown of the detected items — what the AI identified from the photos and description, with approximate quantity and volume.

If the customer is happy with the quote, they proceed to booking: they pick a weekday date, one of nine fixed 1-hour time slots (10 AM through 7 PM Pacific), and their pickup address. The frontend geocodes the address to coordinates client-side using Nominatim, then passes those coordinates to the backend. The backend runs its own geocode call for the company's warehouse address and uses OSRM to calculate the real driving route. The driving distance in miles and duration in minutes are written permanently to the request, and its status changes to scheduled.

On the staff side, a second login route leads to the BayHaul dashboard. Staff see all requests across all customers, filterable by status. Each request shows the customer's description, photos, AI quote, requested time slot, and — critically — the driving distance and time calculated at booking. From the detail view, staff can accept or decline the request, optionally adding a note. A decline note is visible to the customer. A declined request can be edited (different date, time slot, or address) and resubmitted, which runs the distance calculation again for the new address.

How the Backend Is Built

Everything server-side — data model, AI agent, routing logic, permissions — lives in Momen. No server code, no deployment configuration. The backend was configured using Momen's in-product AI Copilot, described entirely in natural language:

COMPANY INFO (fixed, use exactly this everywhere it's needed):
- Company name: BayHaul Junk Removal
- Company warehouse / dispatch address: 1400 Fairway Drive, San Leandro, CA 94577
- Business hours: Monday to Friday, 10:00 AM to 7:00 PM, Pacific Time. Closed Saturday and Sunday.
- Appointment slots are fixed 1-hour blocks during business hours: 10-11, 11-12, 12-1, 1-2, 2-3, 3-4, 4-5, 5-6, 6-7 (all Pacific Time).

USER ROLES:
There are two kinds of accounts: regular customers, and company staff. A logged-in customer can only create and see their own removal requests, never anyone else's, and has read-only access to the company and appointment-slot data (no write access). Staff can see every request submitted by every customer, including their contact info, address, and photos, and can accept or decline requests, and have full read/write access to the company and appointment-slot data. Set this up using the platform's role/permission system rather than adding a "role" field to the user table. Only staff — never customers — may call the role-assignment logic described below.

Create one staff account directly with email/password login: {STAFF_EMAIL} / {STAFF_PASSWORD}.

Also build a one-off callable action that grants the staff role to a given account id, restricted to staff-only callers, so new staff accounts can be onboarded later.

REQUEST DATA:
Each removal request stores: the customer who submitted it, a text description, one or more uploaded photos, an AI-estimated price range (low and high, in USD), an AI-generated structured breakdown of detected items (item types, approximate quantity, rough volume estimate), the pickup address, the requested pickup date and time slot, a status, a driving distance, a driving duration, and an optional staff note.

Status is a field with exactly four fixed options, hard-coded as the only allowed values: quoted, scheduled, accepted, declined.

AI PRICE ESTIMATE:
Given a request's text description and its uploaded photos as input, generate as output: an estimated price range (low and high USD numbers) and a structured breakdown of detected items (item types, approximate quantity, rough volume estimate), based on analyzing both the description and the photos together. This sets the request's price and detected-items fields. The request's status is already "quoted" from creation and stays "quoted" after this step.

BOOKING:
Given a request already in "quoted" status plus a pickup date (must be a weekday), a time slot (must be one of the fixed slots above), a pickup address, and its coordinates as input: look up the warehouse address's coordinates, calculate the driving distance and time from the warehouse to the pickup coordinates, save the pickup date/time slot/address/coordinates and the calculated distance and duration on the request, and set status to "scheduled".

ACCEPT:
Given a request in "scheduled" status and an optional staff note as input: save the note if provided and set status to "accepted". Do not recalculate distance or duration here — they were already calculated and saved during booking.

DECLINE:
Given a request in "scheduled" status and an optional staff note as input: save the note if provided and set status to "declined".

RESUBMIT:
Given a request in "declined" status plus an updated pickup date, time slot, address, and coordinates as input: look up the warehouse address's coordinates again, recalculate the driving distance and time to the new pickup coordinates, update the pickup date/time slot/address/coordinates and the recalculated distance/duration on the request, and set status back to "scheduled".

DISTANCE AND DRIVING TIME:
Use OSRM (Open Source Routing Machine) for the driving distance/time calculation. Server: http://router.project-osrm.org, "driving" profile. Documentation: http://project-osrm.org/docs/v5.10.0/api/#route-service. Use OpenStreetMap Nominatim (https://nominatim.openstreetmap.org/search) to look up the warehouse address's coordinates, sending a descriptive User-Agent header on every request since Nominatim rejects requests without one. Read distance and duration from the OSRM response as output (convert meters to miles, and seconds to minutes). This calculation happens only during booking and resubmission — never during accept/decline.
Enter fullscreen mode Exit fullscreen mode

Data Model

Five tables, each with a clear role:

  • account — Momen's built-in authentication table, extended with phone_number and email. Handles signup and login.
  • removal_request — The core record. Stores description, price_low_usd, price_high_usd, detected_items, pickup_address, pickup_date, time_slot, pickup_location (GEO_POINT), status, driving_distance_miles, driving_duration_minutes, and staff_note. Linked to account via customer_id.
  • removal_photo — One record per uploaded photo, linked to its removal_request. Stores the image in Momen's IMAGE type.
  • company — A single record containing BayHaul's fixed business data: company name, warehouse address, business hours, timezone, opening and closing times, and which days are working days. Pre-populated at project setup.
  • appointment_slot — Nine records, one per 1-hour time slot (10:00–19:00 Pacific). Each stores slot_label, start_time, end_time, and an is_active flag. Linked to company. Pre-populated at project setup.

The status machine captures the full request lifecycle:

quoted  →  scheduled  →  accepted
                      →  declined  →  scheduled (resubmit)
Enter fullscreen mode Exit fullscreen mode

Two roles are configured with Momen's RBAC system — Logged-in User for customers, BayHaul Staff for employees. There is no role field on the account table; permission boundaries are enforced at the platform level. Customers can only read their own removal_request records and have no direct write access to that table — all mutations go through Actionflows. Staff see every request with no row-level restriction.

The AI Quote Agent

One AI Agent, BayHaul AI Price Estimate, handles the quoting step. It runs on google/gemini-3-flash at temperature 0 and takes two inputs: description (text) and photos (an array of images). The image array is built with an arrayMapping formula that iterates over the removal_photo records linked to the request, passing each photo field to the model as a separate image input.

The agent's system prompt instructs it to analyze both the written description and the uploaded photos together, then return three structured outputs: price_low_usd, price_high_usd, and detected_items. The detected items field is a structured breakdown — item types, approximate quantities, rough volume estimates — derived from what the model can identify in the photos and description combined.

The Actionflows

Seven Actionflows orchestrate the full lifecycle of a removal request.

Create BayHaul Request (sync) — Takes a text description and the authenticated account ID, inserts a new removal_request record with status = quoted, and returns the new record's ID. Photos are uploaded separately before this flow runs; the flow itself only creates the parent request.

Estimate BayHaul Request (async) — Takes request_id. Queries all removal_photo records linked to that request, builds an image array via arrayMapping, and passes that array alongside the request description to the BayHaul AI Price Estimate agent. Writes the returned price_low_usd, price_high_usd, and detected_items back to the request. Status stays quoted.

Book BayHaul Pickup (sync) — Takes request_id, pickup_date, time_slot, pickup_address, and pickup_location (the customer's coordinates, resolved client-side). Requires the request to be in quoted status. Calls a Custom Code node that geocodes the warehouse address via Nominatim and calculates the driving route via OSRM, then converts the response to miles and minutes. Writes the pickup details and calculated distance/duration to the request and sets status to scheduled.

Accept BayHaul Request (sync) — Takes request_id and an optional staff_note. Requires scheduled status. Updates status to accepted and writes the note if provided. Distance and duration are not recalculated — they were written at booking and do not change.

Decline BayHaul Request (sync) — Takes request_id and an optional staff_note. Requires scheduled status. Updates status to declined and writes the note. The decline note is the only staff-authored field the customer can see.

Resubmit BayHaul Request (sync) — Takes request_id and new pickup_date, time_slot, pickup_address, and pickup_location. Requires declined status. Runs the same Custom Code distance calculation as booking, overwrites all pickup and distance fields, and sets status back to scheduled.

Assign BayHaul Staff Role (sync) — An operational utility. Takes an account_id and grants the BayHaul Staff role. Only callable by accounts that already have the BayHaul Staff role.

External APIs: Nominatim and OSRM

Both distance-related APIs are free public services with no API keys required. They are configured as Third-Party APIs in Momen and called inside the Custom Code nodes of Book BayHaul Pickup and Resubmit BayHaul Request using context.callThirdPartyApi().

Nominatim (OpenStreetMap) geocodes the company's warehouse address (1400 Fairway Drive, San Leandro, CA 94577) to coordinates. The endpoint requires a descriptive User-Agent header on every request — requests without one are rejected. The warehouse address is fixed and known in advance, so this geocode call is straightforward: query once, read latitude and longitude from the first result.

OSRM (Open Source Routing Machine) calculates the driving route between the warehouse coordinates and the customer's pickup coordinates. The public demo server at router.project-osrm.org takes a pair of {longitude},{latitude} coordinate strings and returns a route object with distance (meters) and duration (seconds). The Custom Code node converts those to miles and minutes and writes them to the request record.

Distance is calculated at booking time and written once. Accept and Decline never touch it. If a customer resubmits with a different address, the calculation runs again for the new coordinates.

Building the Frontend with Claude Code

With the Momen backend in place, the Momen no-code plugin passed the project's full context — data model, GraphQL API schema, Actionflow IDs, role configuration — to Claude Code. The frontend was built from natural language:

Use Momen nocode plugin to build the frontend of this project: {project_url} with React and Vite, calling into the backend already built in this project.

Use light green with soft pastel tones as the primary color palette. Keep the interface simple and clean, avoiding a typical SaaS-style look. Add junk removal-related visual elements throughout so the interface feels engaging and relevant to the subject.

Don't make the homepage just a login screen. Give it a clear value proposition with supporting copy explaining what the app does, along with junk removal-related visual elements, so it feels warm and inviting rather than a bare sign-in form.
Enter fullscreen mode Exit fullscreen mode

Two Ways to Build Something Like This

This project used Momen's in-product AI Copilot to configure the backend, then the plugin to pass that context to Claude Code for the frontend. Two paths are available:

Momen AI Copilot — describe your app in natural language directly inside the Momen editor. The in-product Copilot configures your data model, Actionflows, and UI without switching tools. See Meet Your Nocode AI Copilot — Build Apps by Chatting in Momen for how this works.

Momen plugin + Claude Code — build or describe the Momen backend, then install the Momen no-code plugin in your AI coding agent. The plugin passes your project's full context so you can describe the frontend in natural language and have it wired to the correct endpoints automatically. See the complete setup guide for Momen + Claude Code to get started.

How Long Does This Take

Setting up this Momen backend from scratch — five tables, one AI agent, seven Actionflows, two third-party API configurations, and role-based permissions — takes about 30 minutes to an hour with AI Copilot handling configuration from natural language prompts. Building the frontend with Claude Code, once the project context is loaded, takes around 30–45 minutes for a working version covering both the customer flow and the staff dashboard.

The minimum plan for this project is Basic at $39/month — it covers unlimited AI agents, Actionflows, and third-party API integrations, plus a custom domain.

Add-ons layer on top based on actual usage. For this app, the three that grow with volume are AI Points (the multimodal quoting agent spends points on every photo-based estimate), object storage (customer photos accumulate over time), and outbound data transfer (photos served to the staff dashboard). The calculator sizes its estimate around 4,500 cumulative customers and 225 operating days of data — at that scale, AI Points alone account for $70/month (42M points across ongoing usage scenarios), and storage and transfer add another ~$14. The total comes to approximately $123/month. At a smaller early-stage footprint, the add-on costs would be significantly lower. You can plug in your own usage assumptions and see the line-by-line breakdown in Momen's pricing calculator.

Both Nominatim and OSRM are free public services with no usage fees. Frontend hosting on Vercel is free for most early-stage projects.

Try It and Clone the Project

Submit a request with a description and photo to see the AI quote flow, then book a pickup with a real Bay Area address to see the distance calculation run.

Try the live app

Open in Momen editor / Clone project

Top comments (0)