im·a·cto

From the log

Back to the log

Passive Income Has a Deploy Path

The page a renter needs is on the internet they don't have yet. Solving that, and the twenty-odd jobs that run while nobody is watching, is what the word passive is actually made of.

You are forty miles past the last bar of cell service. The dish is up, it has sky, the light is on. Your phone finds the network and joins it. Now type your code into the sign-in page, which is a web page, which is on the internet you do not have yet.

That is the whole problem in one sentence, and almost everything interesting about the company I own is downstream of it.

the business, and why I bought the problem

WiFi Without Walls rents Starlink Mini and event WiFi kits. Somebody books dates, a bag shows up, they put a dish under open sky, and they send it back in the same bag when the trip is over. It is one of the companies I’ve run this year. Unlike most of the work I do, I own this one outright, which is the part that made it worth doing at all.

I’ve written before that ownership is the cheapest thing a company can hand you, because the word costs nothing and the cap table costs something. It is easy to say that from the side of the table where you sign other people’s grants. It is more honest to go find out whether you actually want the thing you keep telling people to demand. So I bought the version with no story attached: I hold it, and if it makes money while I’m asleep, that’s mine, and if it breaks on a Saturday, that’s mine too.

The business was running on Booqable, a rental management SaaS, at $130 a month against roughly twenty-five orders a year. Do that division and it stops being a software line item. The tool cost real money to hold a calendar, and it could not touch either of the two things that make this an actual business: the dishes and the boxes. It could not talk to Starlink to turn a service line on when a rental started or off when it ended. It could not buy a shipping label. It could not read how much data somebody burned, which is the one number that decides whether the rental made money.

So the parts that mattered were me, on a laptop, on a Sunday. That is not a business. That is a job with worse hours and a subscription.

what the software actually had to do

The rebuild is a single Next.js app on Cloud Run with one Postgres database. No redis, no worker process, no job queue. The scheduled work is a set of plain idempotent POST routes that Cloud Scheduler hits on a timer, serialized with advisory locks in the database that is already there.

I want to be precise about why, because the temptation ran the other way. At twenty-five orders a year you could build the impressive version of this: queues, workers, a fan-out, retries with exponential backoff, all of it defensible in a design review and all of it a second system to keep alive. Sizing infrastructure to the business you have rather than the one that would look good in a diagram is not modesty. It is the same call I make on client work when the bill turns out to be a design document. Every component you add is something that can be down at 2am for a rental in Utah.

What those routes do is the actual product:

  1. Activate and deactivate. A dish’s Starlink service line comes up on the rental start date and goes down on the end date, without me.
  2. Sync usage. Telemetry every four hours, logged per order, because Starlink reports with a lag and the overage bill has to be built from a record rather than a memory.
  3. Bill overages. Usage past the plan charges the saved card off-session, at the published rate, after the provider finalizes.
  4. Prepare shipments. Labels get bought ahead of the box going out, both directions, return label in the bag.
  5. Check returns. The carrier advances the order, not a human. The first tracking scan past pre-transit moves it to shipped and fires the notification.

There are about twenty of these now, including the ones that send pickup reminders, expire abandoned checkouts, and ask for a testimonial after the fact. None of them are clever. Collectively they are the difference between an asset and a chore.

The one I keep pointing at is the return leg. The first scan of a return label is what stops the late fee clock, so it has to land the moment the carrier sees the bag, not on tomorrow’s batch. Two independent things can see that scan, a webhook and a poll, and whichever gets there first wins while the other becomes a no-op. That is four lines of status guard protecting a customer from being billed for a day they did not keep the kit. Nobody will ever notice it working.

the page has to be on the dish

Back to the campsite. The renter’s phone is on the kit’s WiFi, and the kit’s WiFi has no internet until the renter signs in, and the sign-in page is a web page. If that page is served from our website, the first thing a customer experiences is a spinner over a network they were told would work.

So the page does not live on our website. It lives in the router bolted to the dish. One HTML file: styles inline, core script inline, images embedded, icons drawn as shapes instead of pulled from a font hosted somewhere else. It loads over local WiFi from hardware in the dirt, before a single packet has been to space.

The credential is the last four digits of the phone number on the reservation. Not a password, not a QR code, not an account. A number you can shout across a campsite to four people who are already holding their phones, because that is the actual scene the product happens in.

The generated file is committed to the repository, which is normally a smell. Here it is the point: the exact bytes headed for the routers are visible in code review, and CI re-renders the page and fails if the result differs by a byte from what is checked in. Otherwise the infrastructure ships a stale copy with a clean plan, and the first person to find out is somebody in a canyon.

Two more decisions from the same page, both of which I like more than they deserve. Messaging services get a route past the sign-in gate, so a phone can reach iMessage or WhatsApp before anybody has typed anything, which is the thing you actually want at a campsite where somebody is late. And for a local pickup there is no carrier scan to tell us the customer has the kit, so a successful sign-in on that specific dish, with that rental’s credential, inside the rental dates, is what records the handover. The signal was already there. It just had to be read as one.

the part I’d defend in a room

Every operator in this market rents the same hardware. You cannot win on the dish, because it’s Starlink’s dish and everyone can buy one. What you can own is the twenty seconds where somebody who drove four hours finds out whether this was a good idea.

That surface is a web page, and it has to work when the connection it is selling you does not. Once you see the business that way, the software stops being the booking form bolted on the side and becomes the only part a customer ever touches. Which is the Collective’s whole argument arriving somewhere I did not expect it: a company that rents equipment out of a garage in Denver turns out to be a technology company, not because anyone decided to modernize, but because the product is a connection and a connection is experienced through software or not at all.

There’s a cost to that, and it is the copy. Our own style guide is not a style guide, it’s a list of things I told the team to stop doing, and the summary I actually wrote was “you are OVERLY verbose in explaining things site wide.” A unit test now catches the four shapes of that a machine can see. The rest is judgment, every time, forever.

It shows up as sentences that a marketing person would strike. The how-it-works page opens by telling you to check whether your phone hotspot already does the job, because if it does, you should not rent anything from us. The post about the portal admits the screenshots were captured from the fallback copy rather than a phone in the desert. The scene behind the sign-in page renders local weather, and the copy says out loud that a sunny sky on screen should not decide whether you bring in the chairs. The September update ends by asking customers to tell us when the site and the software disagree, so we can fix whichever one is wrong.

That last line is the one I’d point to if somebody asked what the company believes. It admits, in public, that the documentation and the product can drift apart, and it commits to fixing the guilty one instead of quietly editing the page.

so, passive

The income is passive. Nothing about getting there was. The boxes move themselves and the dishes turn themselves on because somebody sat down and decided what happens when a tracking scan arrives twice, and what a renter sees when the satellite is down, and which of the two possible failures a “credential mismatch” is telling you about.

Volume is free now. I can generate a rental platform in a weekend and so can you. What is not free is knowing that the sign-in page cannot be on the internet, that the return scan has to win a race, and that the honest sentence about the hotspot belongs at the top of the page instead of nowhere. That was maybe a dozen decisions across the whole build, and they’re the entire reason it runs without me.

The dish is still up, forty miles past the last bar of service, and the page loaded. What did it cost to make that boring?

Written with AI assistance. WiFi Without Walls is a company I own; the engineering details here are from its own repository and public site.