Personal Fitness Tracker
One API behind three front ends — members, trainers and admin — on hosting that cannot run Node
- 40+REST endpoints, under one OpenAPI contract
- 20database entities behind members, trainers and admin
- 0Node processes on the server — the member app is static
Challenge
Three audiences needed different views of the same data. A member logs a workout and watches a chart move. A trainer answers that member's question and adjusts their plan. An admin publishes the routine both of them are looking at. Building three applications would have meant writing the rules about who may see and change what three times, and keeping them in step forever. The hosting made it harder. Shared hosting runs PHP and MySQL and nothing else — no Node process, no background worker, no container. That rules out the way a Next.js application is normally deployed, and it is not a constraint you can design around later. Payment was the third problem. A membership gate that lives in the interface is not a gate: the API is still there, and anyone who has opened developer tools can call it. Two providers had to be supported, and both had to be verified somewhere a browser cannot reach.
Solution
The API came first, and everything else is a client of it. Forty-plus REST endpoints in PHP over MySQL, described in one OpenAPI document, so the member app, the admin panel and any future mobile client read the same contract rather than each inventing their own. Roles — admin, trainer, member — are enforced at that layer, once. The member app is Next.js 16, built as a static export. It compiles to files, which is precisely what shared hosting is good at serving, so it needs no Node process at runtime. CI builds it and copies the output into the PHP application's public directory, so a deployment is one bundle rather than two coordinated ones. The admin panel is PHP, running where PHP already runs. Content, users, categories, classes, challenges, moderation and settings are managed there, with TOTP available on admin accounts. Stripe Checkout and PayPal both settle server-side, through webhooks the browser never touches, and the membership gate is checked in the API on every protected request. The interface hides what a non-member cannot use; the API is what actually refuses it.
