I built a SaaS app called LawnRun from scratch and launched it live at lawnrun.app. It is a route planner for solo lawn care operators. This post covers how I built it, what stack I used, and what Claude Code actually did.
The idea
Solo lawn care guys run routes every day. They have 10, 20, 30 customers spread across a city and they drive between them all day. Most of them just go in whatever order they remember or wrote down on a notepad. There is no easy, cheap software built specifically for a one-person operation. Enterprise landscaping software exists but it costs hundreds a month and is designed for fleets.
The idea was simple: let a user add their customers, see who is scheduled today, and open the most efficient route in Google Maps with one tap.
Stack
- Python / Flask
- SQLite
- Gunicorn
- Nginx
- Ubuntu VPS (GreenCloud)
- Stripe for payments
- OpenRouteService API for route optimization
- Brevo for transactional email
- Progressive Web App (installable on Android and iPhone)
No frameworks, no ORM, no Docker. Just Flask talking directly to SQLite with raw SQL queries. For a single-user-per-account SaaS this is completely fine and keeps the codebase small.
What it does
Users register, start a 7-day free trial, and add their customers. Each customer gets a name, address, phone number, notes, service frequency, and a start date. The frequency options are weekly, every two weeks, every three weeks, once a month, and one-time jobs.
Every day the app checks which customers are scheduled and builds that day’s route. It calls the OpenRouteService API to sort the stops into the most efficient driving order. One button opens the full route in Google Maps with voice navigation.
Users check off jobs as they finish them. A progress bar fills up as stops are completed. When the last job is done it shows a celebration message and tells you when your next route day is.
Route optimization
This was the most interesting part technically. Google Maps API charges per request and gets expensive fast. OpenRouteService has a generous free tier and an optimization endpoint that takes a list of coordinates and returns the optimal visit order.
I geocode each customer address once and cache the coordinates in the database. The route order is also cached for 5 minutes and invalidated whenever the stop list or addresses change. This keeps API calls minimal even when users are actively editing customers.
Payments
Stripe Checkout handles subscriptions. After the trial ends users are redirected to a subscribe page. The whole payment flow is about 40 lines of code. Stripe webhooks update the subscription status in the database when payments succeed, fail, or when a user cancels.
PWA
The app is installable as a Progressive Web App on both Android and iPhone without going through an app store. A service worker caches static assets. On Android, Chrome shows an install prompt automatically after a few visits. On iPhone users can add it to their home screen through Safari’s share menu.
This was surprisingly easy to implement. A manifest.json file, a service worker, and two icon sizes is all it took. The main gotcha was that the service worker has to be served from the root path, not from /static/, or it cannot control the whole app.
Deployment
The app runs on a cheap VPS. Gunicorn serves the Flask app on localhost port 8000. Nginx sits in front as a reverse proxy and handles SSL termination. Certbot handles the Let’s Encrypt certificate and auto-renews it via a systemd timer.
Deploys are just a git pull and a service restart. No CI, no containers, no build step. For a side project at this stage that is the right call.
What Claude Code actually did
Almost everything. I described features in plain English and Claude wrote the code, caught my bugs, fixed the broken parts, and handled things I would have had to look up like the Google Maps deep link format for iOS vs Android or the correct way to structure a Stripe webhook handler.
The parts where I had to think were product decisions: what features to build, how scheduling should work, what the pricing should be, what the copy should say. The implementation was mostly just reviewing what Claude wrote and saying yes or no.
It is a genuinely different way to build software. I am not a professional developer. I can read and understand code but I would not have shipped this in this timeframe writing it myself.
What is next
The app is live and taking real payments. Next steps are getting the first paying customers, collecting feedback, and iterating. The foundation is solid enough to build on.
If you run a lawn care business or know someone who does, check it out at lawnrun.app.