One typed data layer, two front ends
The website and the app share the same queries and types, so the data model can't quietly drift out of sync between them — a change lands in both or fails the build.
Access enforced in the database
Row-level security decides who can read what, so members-only content stays locked however it's reached rather than relying on the interface to hide it — while anyone can still browse the library and see what they'd be paying for.
Subscriptions that survive the edge cases
Membership state is driven by Stripe's signed webhooks, and a failed payment keeps access through the grace window instead of locking someone out mid-recovery — only a genuinely ended subscription takes it away.
Free tasters, whenever he wants
Any single class, plan or programme can be switched to free and back again, so Rees can open up a sample of the library without anything being rebuilt.
An admin area he runs himself
Every condition, class and exercise plan is created, edited and deleted by Rees — his own images and video, his own words — with no developer in the loop to publish.