Uber-Like Negotiable Service for Mobile Car Washing

A Negotiable Service Platform for Mobile Automotive Detailing

UBER

PROCESS HIGHLIGHTS

PART ONE - EXPLORATION

PROCESS HIGHLIGHTS

PART ONE - EXPLORATION

Challenge

Avoiding wasting time by travelling both ways, waiting in line, and potential unforeseen mishaps such as an auto accident.

Opportunity

Create a platform to match customers and mobile car wash providers while offering real-time price negotiation, media-verified service validation, and an integrated payment and communication solution. Extend backend flexibility to support other verticals like dog grooming and boat detailing.

Challenge

Avoiding wasting time by travelling both ways, waiting in line, and potential unforeseen mishaps such as an auto accident.

Opportunity

Create a platform to match customers and mobile car wash providers while offering real-time price negotiation, media-verified service validation, and an integrated payment and communication solution. Extend backend flexibility to support other verticals like dog grooming and boat detailing.

Timeline

Week 1: Research & Requirements Gathering

Week 2-3: Wireframing, Technical Architecture, Prototyping

Week 4-6: Frontend & Backend Development

Week 7: Integration Testing & Deployment

Week 8: Iteration & Refinement

Disciplines

Software Engineering

Product Design

DevOps

UX Research

Systems Architecture

Data Modeling

Responsibilities

Architected backend for scalability and abstraction

Designed the user journey and negotiation logic

Integrated payment system (Stripe)

Tools

React.js, Node.js

Redis

PostgreSQL

AWS

Docker

AWS SES, Stripe API

Google SSO, Express-rate-limit

Timeline

Week 1: Research & Requirements Gathering

Week 2-3: Wireframing, Technical Architecture, Prototyping

Week 4-6: Frontend & Backend Development

Week 7: Integration Testing & Deployment

Week 8: Iteration & Refinement

Disciplines

Software Engineering

Product Design

DevOps

UX Research

Systems Architecture

Data Modeling

Responsibilities

Architected backend for scalability and abstraction

Designed the user journey and negotiation logic

Integrated payment system (Stripe)

Tools

React.js, Node.js

Redis

PostgreSQL

AWS

Docker

AWS SES, Stripe API

Google SSO, Express-rate-limit

BACKGROUND

The Why

Mobile services are the future of local commerce. However, trust and reliability are major blockers. With gig economy models working well for transportation and food, the same principles can apply to car washing—with added flexibility and safeguards.

The Process

Research

Conducted interviews with 12 mobile car wash business owners and surveyed over 50 potential customers to identify frustrations and expectations.

1

Research

Conducted interviews with 12 mobile car wash business owners and surveyed over 50 potential customers to identify frustrations and expectations.

1

Research

Conducted interviews with 12 mobile car wash business owners and surveyed over 50 potential customers to identify frustrations and expectations.

1

Synthesis

Key pain points were grouped: lack of customer trust, scheduling inefficiencies, absence of price transparency, and insufficient service verification.

2

Synthesis

Key pain points were grouped: lack of customer trust, scheduling inefficiencies, absence of price transparency, and insufficient service verification.

2

Synthesis

Key pain points were grouped: lack of customer trust, scheduling inefficiencies, absence of price transparency, and insufficient service verification.

2

Ideation

Brainstormed core flows: offer negotiation, before/after photo proof, dispute mechanisms, media-based profiles, and business-to-employee delegation.

3

Ideation

Brainstormed core flows: offer negotiation, before/after photo proof, dispute mechanisms, media-based profiles, and business-to-employee delegation.

3

Ideation

Brainstormed core flows: offer negotiation, before/after photo proof, dispute mechanisms, media-based profiles, and business-to-employee delegation.

3

Final Designs

Prototypes validated via clickable Figma flows. Backed by a multi-state, multi-vertical Node.js backend. Included AWS SES integration and Stripe for secured payments.

4

Final Designs

Prototypes validated via clickable Figma flows. Backed by a multi-state, multi-vertical Node.js backend. Included AWS SES integration and Stripe for secured payments.

4

Final Designs

Prototypes validated via clickable Figma flows. Backed by a multi-state, multi-vertical Node.js backend. Included AWS SES integration and Stripe for secured payments.

4

Reflection

Learned the value of building for trust and transparency. Customers are more willing to pay if they feel protected. Service providers gained legitimacy with media-based portfolios.

5

Reflection

Learned the value of building for trust and transparency. Customers are more willing to pay if they feel protected. Service providers gained legitimacy with media-based portfolios.

5

Reflection

Learned the value of building for trust and transparency. Customers are more willing to pay if they feel protected. Service providers gained legitimacy with media-based portfolios.

5

RESEARCH

Desk Research

Based on sources, in particular The Digital Project Manager, here were the three main pain points:

Missing Trust Mechanisms

Needing to switch platforms frequently broke user flow.

Rigid Pricing Structure

The absence of a dynamic negotiation or counter-offer model limits flexibility and discourages user engagement.

Poor Geolocation Relevance

Lack of state- or region-specific filtering reduces match accuracy and leads to irrelevant service listings.

Gig Economy Trends

There’s a growing demand for on-demand services outside traditional verticals like ridesharing and food.

Trust in Peer Services

Trust is the leading factor when booking mobile services. Features like ratings and media significantly increase conversion.

User Retention Factors

Customers who engage in flexible negotiation stay longer due to perceived control and fairness.

RESEARCH

Competitor Analysis

We benchmarked against industry-leading retailers with modern omnichannel platforms:

Spiffy

Pros

·

·

Professional branding

·

·

Streamlined service booking

Cons

·

·

No negotiation features

·

·

Only fixed pricing

Washer

Pros

·

·

Real-time booking

·

·

Mobile app ease of use

Cons

·

·

No provider vetting

·

·

Lacks dispute process

MobileWash

Pros

·

·

Real-time booking

·

·

Mobile app ease of use

Cons

·

·

No provider vetting

·

·

Lacks dispute process

Synthesis

User Persona

To stay grounded in the real-world needs of my target audience, I created a user persona based on research interviews and common patterns I observed. This helped me make product and engineering decisions with a clear user in mind. The following persona represents a typical mobile detailing business owner who would use the platform day-to-day.

Carlos Rivera

LOCATION

Phoenix, AZ

EDUCATION

Associate Degree in Business Management

EXPERIENCE

+6 Years

Goals

·

·

Expand business reach without hiring salespeople

Needs

·

·

A platform that gets him new jobs, protects against no-shows

Pain Points

·

·

Difficulty in building trust with new customers, waste of time on fake requests

Synthesis

User Journey

Carlos Rivera

Scenario:

Carlos signs up for the platform to streamline his daily operations and increase bookings.

Starting

Signs up and uploads past work photos

Trying

Gets notified of a nearby client offer

Conflicting

Client counters his price offer with a lower one

Quitting

Sends a new counteroffer and lands the deal

IDEATION

Developing a Solution .1

Features Created

Scam prevention measures added

To complete an order, service provider must provide before and after pictures

Users are protected by being allowed to dispute if a job was not done.

Users are protected by being allowed to dispute if a job was not done.

Guarantee payment to service provider by pre authorizing customer credit card

Daily payouts

Daily cron jobs to check who is eligible to get paid out - email sent out to those getting paid out

User Bot Prevention

Utilized Google SSO to filter out bots

Rate Limit protection

Profile Building

Service providers can showcase their past work

Show reviews from past customers on the platform

Display services offered and general price

Chat Rooms and Privacy Protection

Allow to quickly chat with each other without exposing each others phone numbers to each other

Business Own-Employee Management

Allow businesses to give Users “employee” level access, allowing them to only accept offers / give counter offers

Negotiation

Allow users to compete for a better price.

Allow businesses to adjust prices based on their day.

During the negotiation phase, businesses can add-on more products and services and build a complex deal just for one customer – allowing businesses to have upsell opportunities.

Multi State Backend Abstraction

Handle requests handled by different State-Level Frontend Applications

Reason: Isolate areas to state level to allow communities to build up properly with relevant information related to where they live / do business.

Multi Business Types Backend Abstraction

Using the same business model, can apply it to the same backend, apply it to other verticals, eg: Dog Grooming, and Boat Washing

IDEATION

Developing a Solution .2

Order Flow

1. Negotiation Phase

2. Client creates an offer, selecting some common services provided by all service providers

3. Backend receives and sends out an Email using AWS SES to all relevant service providers

4. Service providers

Accept the offer / Sends Counter Offer

5. Client

Sends counter offer

Accepts and goes through pre-authorization flow with Stripe

6. Service Phase

7. Service provider

a) Completes the job - Provides Evidence

b) Reports the job - Provides Evidence → gets 50%

c) Contact client via chat room

8. Client receives email that job is completed

Client receives email that job is completed

9. Review Phase

10. Client can leave a review

11. Business can use previous work media on their business profile to show off

Flow Chart

CA Application
CA Applicati...
NY Application
NY Applicati...
FL
Application
FL...
Monolith Backend
Monolith B...
Redis
Redis
RDS
RDS
S3
S3
Stripe
Stripe
AWS SES
email
AWS SES...
Cloudflare CDN
Cloudflare CDN
Client
Client
Text is not SVG - cannot display

Code Snippet

// This is a high-level full-stack implementation example for "Uber-Like Negotiable Service for Mobile Car Washing"
// It combines frontend (React), backend (Express.js), and integrations (Stripe, AWS SES, Google SSO)
// This is just one complex code sample focusing on negotiation flow with key business logic implemented.

// === BACKEND (Node.js with Express.js) ===
// server.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const { v4: uuidv4 } = require('uuid');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const AWS = require('aws-sdk');
const nodemailer = require('nodemailer');

AWS.config.update({ region: 'us-east-1' });
const ses = new AWS.SES();

const app = express();
app.use(cors());
app.use(bodyParser.json());

let offers = {}; // In-memory offer store
let users = {};
let businesses = {};

// === Google SSO Bot Prevention ===
app.post('/auth/google', (req, res) => {
  const { id_token } = req.body;
  // Validate token using Google Auth lib and filter spam based on domain/IP etc
  // If valid, store user in DB or memory
  res.send({ success: true });
});

// === Create Offer ===
app.post('/offer', (req, res) => {
  const { clientId, services, location } = req.body;
  const offerId = uuidv4();
  const offer = { offerId, clientId, services, location, status: 'negotiation', timestamp: Date.now() };
  offers[offerId] = offer;

  // Notify businesses by SES
  const params = {
    Destination: { ToAddresses: ['provider@example.com'] },
    Message: {
      Body: {
        Text: { Data: `New service offer posted: ${JSON.stringify(services)}` },
      },
      Subject: { Data: 'New Car Wash Offer Available!' },
    },
    Source: 'no-reply@yourdomain.com',
  };

  ses.sendEmail(params, (err, data) => {
    if (err) console.error(err);
  });

  res.send({ offerId });
});

// === Counter Offer ===
app.post('/counter-offer', (req, res) => {
  const { offerId, businessId, newPrice, addons } = req.body;
  if (!offers[offerId]) return res.status(404).send('Offer not found');

  offers[offerId].counterOffer = { businessId, newPrice, addons, timestamp: Date.now() };
  res.send({ success: true });
});

// === Accept Offer and Pre-authorize Payment ===
app.post('/accept-offer', async (req, res) => {
  const { offerId, paymentMethodId } = req.body;
  const offer = offers[offerId];
  if (!offer || !offer.counterOffer) return res.status(400).send('Invalid offer');

  const paymentIntent = await stripe.paymentIntents.create({
    amount: offer.counterOffer.newPrice * 100,
    currency: 'usd',
    payment_method: paymentMethodId,
    capture_method: 'manual',
    confirm: true,
  });

  offer.paymentIntentId = paymentIntent.id;
  offer.status = 'in_progress';

  res.send({ success: true, clientSecret: paymentIntent.client_secret });
});

// === Complete Service ===
app.post('/complete-service', async (req, res) => {
  const { offerId, beforeImages, afterImages, proof } = req.body;
  const offer = offers[offerId];
  if (!offer) return res.status(404).send('Offer not found');

  offer.status = 'completed';
  offer.proof = { beforeImages, afterImages, proof };

  // Email client job is done
  // Store to DB for review/profile etc.

  res.send({ success: true });
});

// === Daily Cron Job (Mock Function) ===
const dailyPayouts = () => {
  Object.values(offers).forEach(async (offer) => {
    if (offer.status === 'completed' && offer.paymentIntentId) {
      await stripe.paymentIntents.capture(offer.paymentIntentId);
      offer.status = 'paid';
      // Notify service provider by email
    }
  });
};

app.listen(3001, () => console.log('Backend running on port 3001'));


// === FRONTEND (React Component Example) ===
// components/CreateOffer.js
import React, { useState } from 'react';
import axios from 'axios';

const CreateOffer = () => {
  const [services, setServices] = useState('');
  const [location, setLocation] = useState('');

  const createOffer = async () => {
    const response = await axios.post('http://localhost:3001/offer', {
      clientId: '12345',
      services: services.split(','),
      location,
    });
    alert('Offer ID: ' + response.data.offerId);
  };

  return (
    <div className="p-4 max-w-xl mx-auto">
      <h2 className="text-xl font-bold mb-2">Create Service Offer</h2>
      <input className="border p-2 mb-2 w-full" placeholder="Services (comma-separated)" onChange={e => setServices(e.target.value)} />
      <input className="border p-2 mb-2 w-full" placeholder="Location" onChange={e => setLocation(e.target.value)} />
      <button className="bg-blue-500 text-white px-4 py-2 rounded" onClick={createOffer}>Submit Offer</button>
    </div>
  );
};

export default CreateOffer;


// NOTE: For production, use MongoDB/PostgreSQL for storing users/offers securely.
// Protect endpoints with authentication middleware.
// Use file uploads (like AWS S3) for media proof images.
// Set up Stripe Webhooks for real-time payment event tracking.
// Schedule daily cron jobs with node-cron or serverless functions.
// Implement chat and Google SSO with Firebase or similar.
// Add unit and integration tests.

// This is a high-level full-stack implementation example for "Uber-Like Negotiable Service for Mobile Car Washing"
// It combines frontend (React), backend (Express.js), and integrations (Stripe, AWS SES, Google SSO)
// This is just one complex code sample focusing on negotiation flow with key business logic implemented.

// === BACKEND (Node.js with Express.js) ===
// server.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const { v4: uuidv4 } = require('uuid');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const AWS = require('aws-sdk');
const nodemailer = require('nodemailer');

AWS.config.update({ region: 'us-east-1' });
const ses = new AWS.SES();

const app = express();
app.use(cors());
app.use(bodyParser.json());

let offers = {}; // In-memory offer store
let users = {};
let businesses = {};

// === Google SSO Bot Prevention ===
app.post('/auth/google', (req, res) => {
  const { id_token } = req.body;
  // Validate token using Google Auth lib and filter spam based on domain/IP etc
  // If valid, store user in DB or memory
  res.send({ success: true });
});

// === Create Offer ===
app.post('/offer', (req, res) => {
  const { clientId, services, location } = req.body;
  const offerId = uuidv4();
  const offer = { offerId, clientId, services, location, status: 'negotiation', timestamp: Date.now() };
  offers[offerId] = offer;

  // Notify businesses by SES
  const params = {
    Destination: { ToAddresses: ['provider@example.com'] },
    Message: {
      Body: {
        Text: { Data: `New service offer posted: ${JSON.stringify(services)}` },
      },
      Subject: { Data: 'New Car Wash Offer Available!' },
    },
    Source: 'no-reply@yourdomain.com',
  };

  ses.sendEmail(params, (err, data) => {
    if (err) console.error(err);
  });

  res.send({ offerId });
});

// === Counter Offer ===
app.post('/counter-offer', (req, res) => {
  const { offerId, businessId, newPrice, addons } = req.body;
  if (!offers[offerId]) return res.status(404).send('Offer not found');

  offers[offerId].counterOffer = { businessId, newPrice, addons, timestamp: Date.now() };
  res.send({ success: true });
});

// === Accept Offer and Pre-authorize Payment ===
app.post('/accept-offer', async (req, res) => {
  const { offerId, paymentMethodId } = req.body;
  const offer = offers[offerId];
  if (!offer || !offer.counterOffer) return res.status(400).send('Invalid offer');

  const paymentIntent = await stripe.paymentIntents.create({
    amount: offer.counterOffer.newPrice * 100,
    currency: 'usd',
    payment_method: paymentMethodId,
    capture_method: 'manual',
    confirm: true,
  });

  offer.paymentIntentId = paymentIntent.id;
  offer.status = 'in_progress';

  res.send({ success: true, clientSecret: paymentIntent.client_secret });
});

// === Complete Service ===
app.post('/complete-service', async (req, res) => {
  const { offerId, beforeImages, afterImages, proof } = req.body;
  const offer = offers[offerId];
  if (!offer) return res.status(404).send('Offer not found');

  offer.status = 'completed';
  offer.proof = { beforeImages, afterImages, proof };

  // Email client job is done
  // Store to DB for review/profile etc.

  res.send({ success: true });
});

// === Daily Cron Job (Mock Function) ===
const dailyPayouts = () => {
  Object.values(offers).forEach(async (offer) => {
    if (offer.status === 'completed' && offer.paymentIntentId) {
      await stripe.paymentIntents.capture(offer.paymentIntentId);
      offer.status = 'paid';
      // Notify service provider by email
    }
  });
};

app.listen(3001, () => console.log('Backend running on port 3001'));


// === FRONTEND (React Component Example) ===
// components/CreateOffer.js
import React, { useState } from 'react';
import axios from 'axios';

const CreateOffer = () => {
  const [services, setServices] = useState('');
  const [location, setLocation] = useState('');

  const createOffer = async () => {
    const response = await axios.post('http://localhost:3001/offer', {
      clientId: '12345',
      services: services.split(','),
      location,
    });
    alert('Offer ID: ' + response.data.offerId);
  };

  return (
    <div className="p-4 max-w-xl mx-auto">
      <h2 className="text-xl font-bold mb-2">Create Service Offer</h2>
      <input className="border p-2 mb-2 w-full" placeholder="Services (comma-separated)" onChange={e => setServices(e.target.value)} />
      <input className="border p-2 mb-2 w-full" placeholder="Location" onChange={e => setLocation(e.target.value)} />
      <button className="bg-blue-500 text-white px-4 py-2 rounded" onClick={createOffer}>Submit Offer</button>
    </div>
  );
};

export default CreateOffer;


// NOTE: For production, use MongoDB/PostgreSQL for storing users/offers securely.
// Protect endpoints with authentication middleware.
// Use file uploads (like AWS S3) for media proof images.
// Set up Stripe Webhooks for real-time payment event tracking.
// Schedule daily cron jobs with node-cron or serverless functions.
// Implement chat and Google SSO with Firebase or similar.
// Add unit and integration tests.

// This is a high-level full-stack implementation example for "Uber-Like Negotiable Service for Mobile Car Washing"
// It combines frontend (React), backend (Express.js), and integrations (Stripe, AWS SES, Google SSO)
// This is just one complex code sample focusing on negotiation flow with key business logic implemented.

// === BACKEND (Node.js with Express.js) ===
// server.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const { v4: uuidv4 } = require('uuid');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const AWS = require('aws-sdk');
const nodemailer = require('nodemailer');

AWS.config.update({ region: 'us-east-1' });
const ses = new AWS.SES();

const app = express();
app.use(cors());
app.use(bodyParser.json());

let offers = {}; // In-memory offer store
let users = {};
let businesses = {};

// === Google SSO Bot Prevention ===
app.post('/auth/google', (req, res) => {
  const { id_token } = req.body;
  // Validate token using Google Auth lib and filter spam based on domain/IP etc
  // If valid, store user in DB or memory
  res.send({ success: true });
});

// === Create Offer ===
app.post('/offer', (req, res) => {
  const { clientId, services, location } = req.body;
  const offerId = uuidv4();
  const offer = { offerId, clientId, services, location, status: 'negotiation', timestamp: Date.now() };
  offers[offerId] = offer;

  // Notify businesses by SES
  const params = {
    Destination: { ToAddresses: ['provider@example.com'] },
    Message: {
      Body: {
        Text: { Data: `New service offer posted: ${JSON.stringify(services)}` },
      },
      Subject: { Data: 'New Car Wash Offer Available!' },
    },
    Source: 'no-reply@yourdomain.com',
  };

  ses.sendEmail(params, (err, data) => {
    if (err) console.error(err);
  });

  res.send({ offerId });
});

// === Counter Offer ===
app.post('/counter-offer', (req, res) => {
  const { offerId, businessId, newPrice, addons } = req.body;
  if (!offers[offerId]) return res.status(404).send('Offer not found');

  offers[offerId].counterOffer = { businessId, newPrice, addons, timestamp: Date.now() };
  res.send({ success: true });
});

// === Accept Offer and Pre-authorize Payment ===
app.post('/accept-offer', async (req, res) => {
  const { offerId, paymentMethodId } = req.body;
  const offer = offers[offerId];
  if (!offer || !offer.counterOffer) return res.status(400).send('Invalid offer');

  const paymentIntent = await stripe.paymentIntents.create({
    amount: offer.counterOffer.newPrice * 100,
    currency: 'usd',
    payment_method: paymentMethodId,
    capture_method: 'manual',
    confirm: true,
  });

  offer.paymentIntentId = paymentIntent.id;
  offer.status = 'in_progress';

  res.send({ success: true, clientSecret: paymentIntent.client_secret });
});

// === Complete Service ===
app.post('/complete-service', async (req, res) => {
  const { offerId, beforeImages, afterImages, proof } = req.body;
  const offer = offers[offerId];
  if (!offer) return res.status(404).send('Offer not found');

  offer.status = 'completed';
  offer.proof = { beforeImages, afterImages, proof };

  // Email client job is done
  // Store to DB for review/profile etc.

  res.send({ success: true });
});

// === Daily Cron Job (Mock Function) ===
const dailyPayouts = () => {
  Object.values(offers).forEach(async (offer) => {
    if (offer.status === 'completed' && offer.paymentIntentId) {
      await stripe.paymentIntents.capture(offer.paymentIntentId);
      offer.status = 'paid';
      // Notify service provider by email
    }
  });
};

app.listen(3001, () => console.log('Backend running on port 3001'));


// === FRONTEND (React Component Example) ===
// components/CreateOffer.js
import React, { useState } from 'react';
import axios from 'axios';

const CreateOffer = () => {
  const [services, setServices] = useState('');
  const [location, setLocation] = useState('');

  const createOffer = async () => {
    const response = await axios.post('http://localhost:3001/offer', {
      clientId: '12345',
      services: services.split(','),
      location,
    });
    alert('Offer ID: ' + response.data.offerId);
  };

  return (
    <div className="p-4 max-w-xl mx-auto">
      <h2 className="text-xl font-bold mb-2">Create Service Offer</h2>
      <input className="border p-2 mb-2 w-full" placeholder="Services (comma-separated)" onChange={e => setServices(e.target.value)} />
      <input className="border p-2 mb-2 w-full" placeholder="Location" onChange={e => setLocation(e.target.value)} />
      <button className="bg-blue-500 text-white px-4 py-2 rounded" onClick={createOffer}>Submit Offer</button>
    </div>
  );
};

export default CreateOffer;


// NOTE: For production, use MongoDB/PostgreSQL for storing users/offers securely.
// Protect endpoints with authentication middleware.
// Use file uploads (like AWS S3) for media proof images.
// Set up Stripe Webhooks for real-time payment event tracking.
// Schedule daily cron jobs with node-cron or serverless functions.
// Implement chat and Google SSO with Firebase or similar.
// Add unit and integration tests.

IDEATION

Future Explorations - AI

Voice Assistant Integration

·

·

Voice-enabled booking via Alexa or Google Assistant

Drone-Based Pre Inspection

·

·

Use camera drones to preview vehicles for large fleets or premium services

Loyalty Program Gamification

·

·

Points and tiered rewards to incentivize repeat bookings