Last Week
Last week was about building a real “front door” for Shokken: the product website. The layout, content, and overall structure are in a good place, but I still need the assets that make it feel real—screenshots and a short demo video that show the app in motion.
On the app side, the theme is still the same: the alpha builds are usable, I’m shipping updates, and testing keeps surfacing bugs and rough edges that I didn’t anticipate. That’s good progress, but it also makes it easy to fall into the trap of “just one more feature” instead of locking the build down and pushing toward a public release.
The Week the iOS Builds Stopped Shipping
This week came with an annoying but predictable constraint: iOS updates are paused.
It’s not because I stopped working on the iOS side, but because Apple temporarily removed my ability to sign and publish builds while my developer account transitions from an individual account to an organization account. Until that migration finishes, I can’t ship new TestFlight builds or App Store updates.
Android is still moving forward normally, so the project isn’t stalled—but it does change the rhythm. When one platform is frozen by process instead of engineering, it forces you to focus on the things that benefit both platforms: reducing bugs, tightening product scope, and getting the “business infrastructure” in place so the app can be released without accidentally setting money on fire.
Two Features That Forced Me to Act Like a Business
I added two major pieces of functionality this week, and both of them have the same motivation: cost control.
RevenueCat paywall (billing guardrails)
Shokken’s core workflow isn’t free for me to run. The whole point is that the system sends messages on behalf of restaurants, and those messages cost real money at scale. Before I can release the app publicly, I need a reliable way to collect payment and put usage behind a subscription boundary.
So I wired in a RevenueCat-powered paywall. This is one of those integrations that looks simple at the “add SDK” layer, but gets fiddly when you’re doing it across two app stores and you want it to behave correctly for real users. I’ve done it before, and it still wasn’t trivial this time.
QR code “self-join” (and why it’s not just a UI feature)
I also implemented a QR-code-based join flow: instead of the host manually entering a guest’s information on a tablet, the restaurant can display a QR code and guests can scan it to enroll themselves on the waitlist.
The reason I hesitated on this feature wasn’t the implementation effort—it’s mostly “a few tables and some backend plumbing” when you already have the waitlist system built. The real concern is what happens when you expose a public entry point into a system that can trigger paid operations.
In Shokken’s case, adding someone to a waitlist can trigger SMS. If the join link is public, then anyone can hit it: a bored teenager, a competitor, or a malicious script. That turns a nice convenience feature into a potential denial-of-service problem and (worse) a cost-amplification problem.
I ended up shipping the first version anyway, but I approached it as a security-and-cost design problem, not a “make a QR code” problem. I’m aiming for low friction for real guests, with a couple layers of defense-in-depth so abuse is annoying and expensive to sustain.
The Commitment: Freeze the Features
This week made something obvious: I have to stop rewarding myself with feature work.
Feature creep is fun, and it’s easy to justify (“users will love this”), but it’s also a way to delay the scary part: freezing the scope, polishing what’s already there, and letting real restaurants judge whether the product is actually useful.
So I’m making a promise to myself (and to early users): after RevenueCat and QR self-join, that’s it for the initial public release. From here on out, the job is to squash bugs, improve polish, and make the core workflow reliable.
What does it mean in English?
This week was about the difference between building an app and running a product.
When you ship something into the real world, “nice-to-have” features can become liabilities if they open up new ways for strangers to consume your resources. A QR code looks like a convenience feature, but if it can trigger paid SMS, it’s also a doorway that needs guardrails.
The same is true for billing: you can’t treat payments as “later” once real usage is on the table. Cost control isn’t optional infrastructure—it’s part of what makes the product safe to operate.
And most importantly: shipping requires saying “no” to yourself. The app doesn’t need infinite features. It needs a stable, polished, testable slice that real restaurants can try without drama.
Nerdy Details
Apple account migration is a build pipeline dependency
The Apple developer account transition is operational work, but it affects engineering directly because signing is part of the build pipeline. When Apple disables signing during the migration window, iOS distribution just stops. There’s no clever workaround: you wait.
That’s frustrating, but it’s also a useful forcing function. It pushes me toward platform-agnostic improvements (bug fixes, backend hardening, content polish) and away from “just ship another build and hope it’s fine”.
Billing is a safety mechanism, not a growth lever
The billing work isn’t about monetization in the abstract—it’s about preventing accidental unlimited usage while I’m still learning what real usage looks like.
If Shokken sends SMS, then Shokken has variable costs. Any feature that can trigger messages is effectively a lever that can move my monthly bill. That’s why the paywall has to exist before public release: it lets me put a hard boundary around “this is allowed” versus “this could bankrupt me if someone hits it hard enough.”
QR join: a public endpoint that can trigger paid side effects
The QR join flow changes the threat model because it creates a public URL that can be invoked without a host standing there to apply judgment.
The two main risks are:
- Availability risk: someone can spam the join endpoint and create noise or overload.
- Cost risk: if each join triggers an SMS or other paid work, the attacker doesn’t need to “hack” anything—they just need to click a link a lot.
The challenge is that the obvious mitigations add friction. If you add too many hoops, guests get frustrated and hosts end up doing manual work anyway. So the design goal becomes: keep it low friction for legitimate users, but add enough layered checks that abuse is hard to scale.
This is one of those features where the first version matters less than the monitoring and iteration afterward. Once real restaurants try it, I’ll learn what “normal” traffic looks like and what kinds of abuse are realistic, and I can tune the guardrails accordingly.
Next Week
Next week is mostly about polish and presentation: recording the feature videos for the website, getting screenshots in place, and continuing the bug-fix grind as more testers try the app.
I’m also waiting on Apple to finish the organization migration so iOS updates can resume. In the meantime, I’m using the pause as an excuse to breathe a little and focus on making the existing feature set reliable instead of expanding it.