Last Week
Last week I went through Apple’s second iOS rejection line by line and separated the feedback into concrete buckets: metadata cleanup, legal links, pricing explanation, short-duration paid access, account deletion, and general release-readiness debt. By the end of that pass, the shape of the work was clear. Most of the review items had either a direct fix or a direct answer, and the one large product requirement, account deletion, had already turned into real implementation work across the app and backend.
That should have put me in a simple position this week: submit the next binary and keep moving. Instead, this week became about the thing sitting underneath the review itself. I have fixed the review items, but I have not yet sent Apple the next build, because the missing infrastructure around release control is now the real blocker.
The Missing Layer Between Backend And Binary
This week was about configuration management.
In plain terms, I finally hit the point where feature flags stopped being a nice future improvement and became an immediate operational need. Android is already live on Google Play. iOS is still waiting on App Store approval. Apple has already sent two rejections, and the second one contained six more serious issues. I have addressed those issues, but while doing that work I was also building another feature: AI menu recognition.
That is where the problem shows up.
The app needs to ship some changes for review, such as account deletion. The backend for new work can move as fast as I can build and test it. But the mobile binaries cannot. They have to go through store review, and every new binary creates another approval cycle. Without configuration management, anything compiled into the app is either present or absent. There is no clean remote switch to say, “this feature is in the binary, but do not show it yet.”
So even though the App Store fixes are largely done, I am still not in a good position to submit if another in-progress feature is only half ready. That is the release-management lesson of the week: unfinished features do not only create product risk. They can also delay unrelated shipping work when the platform controls the release gate.
What does it mean in English?
The backend and the app store do not move at the same speed.
If I change server code, I can usually deploy it quickly. If I change the mobile app, I have to build a new binary and wait for Apple or Google to approve it. That means I need a way to hide unfinished features even if some of their code is already inside the app.
Without that, I end up with two bad options. I can delay the release until every in-progress feature is ready, even if only one small fix actually matters. Or I can hardcode a feature off, submit the build, and then come back later with yet another store submission just to turn it on. Neither option is efficient, and both make it harder to react quickly if a new feature turns out to be buggy after launch.
Configuration management solves that problem. It lets the app ask the server which features should be visible right now, so I can ship more safely and change course faster.
Nerdy Details
Mobile releases run on two different clocks
The core mismatch is simple: the backend and the binaries have different release mechanics.
In Shokken’s case, the backend lives on Supabase. If I make a backend change and it passes the level of testing and release review I am comfortable with, I can ship that change immediately. There is no App Store reviewer involved in that step. Server-side code can move on my schedule.
The mobile apps do not work that way. Once a binary is built and distributed through Google Play or the App Store, the stores become part of the release pipeline. Google was comparatively straightforward. Apple has been much more stringent, and even after the first approval, every later update still becomes another submission event. It may be faster than the original review, but it is not instant.
That means the system naturally wants to drift out of sync. The backend can be ready before the front end. The front end can be ready before the backend. If there is no configuration layer sitting between those two pieces, then every rollout becomes tightly coupled. The app either exposes the feature or it does not. There is not much room in the middle.
App Review exposed the exact weak spot
The current App Store review cycle made that weakness obvious.
One of Apple’s required fixes was account deletion. That is not a single-button cosmetic change. It needs UI in the app so the user can initiate the deletion flow, and it needs backend logic that verifies the authenticated request and performs the deletion correctly. In my case that means both front-end work and server-side work, including an RPC or edge-function path to carry out the destructive part safely.
That work is done.
At the same time, I have also been building AI menu recognition. The goal is straightforward: instead of asking a restaurant to hand-enter its menu, I want the host to be able to photograph one or more menu pages and have the backend turn those images into a structured menu that can be shown to guests while they wait.
That has obvious product value. Guests can browse the menu before they are seated. Restaurants get a better chance of keeping people engaged while they wait. If customers already know what they want, table turnover can improve because less time is spent studying the menu after being seated.
The catch is implementation scope. The feature is not trivial. It spans mobile capture and upload work on the front end, parsing and transformation work on the backend, and a presentation model that is actually usable once the results come back. In the transcript I described that backend effort as being comparable in complexity to the main waitlist-processing logic, and that is the right way to think about it. It is not a tiny side experiment.
Hardcoding a feature off is not a real release strategy
Right now the AI menu feature is not finished enough to be something I want exposed in a production review build.
Without configuration management, the obvious workaround is to go into the app code and hardcode the feature off. That would let me create a cleaner binary for App Review sooner. The problem is that this only pushes the pain forward.
Once the AI menu feature is actually ready, I would need to touch the mobile code again just to turn the feature on. That creates another binary. Another binary means another submission. If Apple or Google needs to re-review the update, I am back in the same approval loop just to expose functionality that may already be live and stable on the backend.
It gets worse if the first production rollout has a bug. If I discover that the backend needs to be disabled temporarily, I can shut the server-side portion down quickly. But without a remote flag, the app UI can still show the entry point. From the user’s perspective, that is the worst possible state: a visible feature that predictably fails.
That is why feature flags matter. They are not only for staged rollouts and A/B tests. They are also kill switches. They let me say, “hide this until the server is ready,” or “turn this off everywhere while I fix the backend,” without waiting on another store approval cycle.
Remote config changes the release model
The model I want is straightforward.
When the app launches, it should fetch a small configuration payload from the backend. That payload answers questions such as whether AI menu recognition is available, whether an experiment should be visible, or whether a rollout should stay limited. The app then renders only the features that are currently enabled.
That creates a much healthier release pipeline:
- I can ship dormant code inside an approved binary without exposing it immediately.
- I can enable a feature only after the backend is fully ready.
- I can disable a broken feature quickly without forcing users through a dead path.
- I can reduce the number of store submissions that exist only to flip a feature from off to on.
In other words, configuration management decouples “included in the binary” from “enabled for users.” That distinction is extremely valuable in mobile development because the binary and the backend do not share the same release latency.
Build it myself or buy the boring part
I resisted doing this earlier because it is one more system to implement and one more thing to pay for.
In principle, I could build a simple version myself. Since the backend already uses Supabase, I could store feature-state records in a table and have the app read them. For a very small setup, that might work. But existing configuration providers solve a lot of annoying details quickly: dashboarding, rollout controls, targeting, auditing, and the general ergonomics of not turning a homemade flag table into yet another permanent subsystem I have to maintain.
ConfigCat is the obvious candidate right now. It is not the only way to do this, but it is the solution I already have in mind because it gives me the operational shape I need without forcing me to invent the whole thing from scratch while I am also trying to get iOS out the door.
So the current order of operations is clear. First, finish the AI menu work enough that the build I submit is coherent. Second, send the updated iOS binary to Apple with the review items addressed. Third, put configuration management in place so future features do not keep colliding with the release process this way.
Next Week
Next week should be about getting the next iOS submission out cleanly. That means finishing the AI menu recognition work enough to avoid shipping a half-ready path, packaging the review fixes into the new binary, and sending Apple the next submission.
Once that is in motion, configuration management becomes the next infrastructure task. I do not want every future release to depend on whether unrelated in-progress features happen to be finished at the same time. Feature flags are no longer optional polish. At this point they are part of shipping the app responsibly.