Why this one is worth reading
Banny is a consumer health app in a category most engineers never touch, and the temptation is to describe the product. The part worth an interview is narrower than that: it is what happens when a Flutter app needs authority it cannot have from Dart.
The process boundary
Apple's Screen Time stack is not an API you call. It is a set of app extensions the system loads into their own processes, at times of its choosing, with your app nowhere in the picture. Three of them matter here.
DeviceActivityMonitor is called when a scheduled interval ends. Banny uses it to lift a timed block: the app applies the shield and schedules the interval, and when the interval elapses the system wakes the extension, which clears the ManagedSettingsStore itself. The app does not need to be running, backgrounded, or even installed in memory.
ShieldConfiguration renders what a user sees when they open a blocked app.
ShieldAction decides what happens when they press a button on that screen.
None of these can talk to Flutter. There is no engine in those processes and no method channel to reach. So the contract between the app and its extensions is a shared App Group: the app writes the shield mode and the end timestamp into group user defaults, and the extensions read and clear them. That is a deliberately small surface, and it is the only one that survives the app not existing at the moment the work needs to happen.
Availability, not deployment target
Family Controls needs iOS 16. Raising the project's deployment target to match would have been the quick fix and would have shut out every device below it, for a capability most sessions never invoke.
Every Family Controls call is gated behind an availability check instead. The app compiles and installs on the older target, and on a device that cannot enforce a shield the feature simply is not offered. The rest of the product is unaffected.
The assessment is the product
Recovery programmes that hand everyone the same thirty days are wrong for almost everyone, and visibly arbitrary to anyone who thinks about it for a second.
Banny's onboarding is a branching questionnaire across four axes: physical, mental, social and lifestyle. Its answers feed a scorer that sets the programme length anywhere from fourteen to sixty days against a twenty-one day baseline, weighted by factors with a stated rationale. The programme then moves through phases with different emphases rather than repeating the same daily prompt.
The engineering point is that the number is computed, which means it can be explained to a user and revised against outcomes. A hardcoded thirty can only be defended.
Two codebases, one Supabase project
The Flutter app and a Next.js 16 platform share one Supabase Postgres project with auth and row-level security. The web side carries the marketing site, the content hub and an admin dashboard; the app carries the programme itself. Keeping one database behind both means content written once appears in both places, and means there is no second source of truth to drift.
Around that: RevenueCat for subscriptions and the paywall, PostHog for product analytics, Firebase for analytics and Crashlytics, scheduled local notifications for the daily programme, and three locales at launch.