Undesk is a mobile app for desk workers with neck, back and wrist pain. Each day you check in, and it gives you a short stretch routine that fits what hurts. It is on TestFlight now.
An adaptive plan, not a fixed programme
Every user gets a four-week plan generated by Claude from their daily check-ins: where it hurts, how much, how long they sat. The plan changes as the check-ins change, so week three can look nothing like week one.
Generation has to be safe to repeat. A user can tap twice, the app can retry on a bad connection, and a job can run twice. I made plan generation idempotent, so the same request always lands on the same plan instead of creating a second one.
Long-running AI jobs
A full plan takes longer than a request should stay open. The API accepts the request, queues the work on BullMQ and returns right away. The app shows progress and picks up the finished plan when the worker is done. A failed job retries without the user doing anything.
Pro access is decided on the server
Undesk has a subscription through RevenueCat. The app never decides on its own whether someone is Pro. The backend keeps the entitlement, and a RevenueCat webhook updates it. I hardened that webhook: it verifies the signature, ignores events it has already processed, and handles events that arrive out of order.
The result is that a modified client cannot unlock Pro, and a renewal or refund shows up in the app without a release.
Production-readiness audit
Before sending the app to TestFlight reviewers I audited the whole stack for production readiness: auth, rate limits, webhook handling, error reporting and data deletion. The audit produced a list of fixes, and I worked through it before shipping.
What I would keep
Queuing the AI work and keeping entitlements on the server cost more time up front than calling the model from the app. Both paid off the first time a job failed or a webhook arrived twice, and nothing visible went wrong for the user.
Where it stands
Undesk runs on iOS and Android and is out on the App Store.





