Skip to main content
Physio Xpert, Medical SaaS for Physiotherapists
In Progress
SAAS

Case study

Physio Xpert, Medical SaaS for Physiotherapists

A rehabilitation platform in production, designed and built solo for physiotherapists. A clinical assessment raises medical flags, those flags drive which exercises are prescribed, and every session adjusts the difficulty to the patient's tolerance. A Java/Spring Boot API, a Next.js practitioner back-office and a React Native patient app on iOS and Android.

Duration
Since September 2025
Team
1 person
Status
In Progress
Share on TwitterShare on LinkedInShare on FacebookCopy link
View Live

By the numbers

4,658

Automated tests

Java API, run verified

310

API routes

All under /api/v1

HDS

Hosting

Scalingo, French region

The context

Physio Xpert is a rehabilitation platform for physiotherapists, running in production at app.physio-xpert.com. The practitioner runs a clinical assessment, the platform derives medical flags from it, those flags drive the prescribed exercises, and the patient completes their sessions from a mobile app, reporting tolerance after each exercise.

I designed and built all of it solo since September 2025: the API, the practitioner back-office, the patient mobile app, the data schema, the hosting and the test suite. Three constraints explain nearly every technical decision that follows.

Clinical logic has to evolve without a redeployment. Alert criteria follow practice, not release cycles: they live as data, editable by practitioners themselves from the back-office.

This is health data. Certified hosting, encryption, explicit consent and access traceability form a regulatory frame that is set at design time, not at delivery.

One developer, over time. Every piece has to stay understandable and changeable by a single person five years from now, which rules out over-engineering as much as shortcuts.

The clinical decision chain

This is the piece to understand first: everything else in the architecture exists so that this chain stays correct, traceable and editable without a redeployment.

From clinical assessment to the next session

practitioner

Clinical assessment

An assessment whose content is configured, not coded.

platform

Decision engine

Answers are matched against the clinical criteria in force.

platform

Medical flags

Red flags (contraindication) and yellow flags (caution).

platform

Exercise prescription

Flags filter and weight the proposed programme.

patient

Guided session

The session runs on mobile, with tolerance feedback.

Tolerance feedback loops back into progression: the next session is stepped up, held or eased. It is a loop, not a funnel: the same patient goes through this cycle at every session.

Two properties of this chain shaped the rest of the work. First, one link is configured, not coded: a practitioner can change their assessments and alert criteria without me deploying anything. Second, the output of the last link feeds back into the first: progression is not a pure function of an initial assessment, it is a state machine accumulating the patient’s history.

Where it started, and why that changed

The product did not begin on the stack it runs on today. The first version was a React + Supabase MVP: a managed database, authentication and access rules provided by the platform, and a front-end talking straight to that database. To validate the clinical decision chain with practitioners, it was the shortest path, and it did its job.

What ended that arrangement was not a technical limit, it was the regulatory frame. As soon as the platform handles real patient records, hosting has to be HDS-certified, and health data requires timestamped consent, explicit retention and a complete access log. Those requirements belong to the server answering every request, not to a client. A front-end querying the database directly has nowhere to put them.

So the migration was not a code move, it was a complete rewrite of the application engine. Everything that lived in Supabase, the schema, the access rules and the clinical decision logic, was rewritten behind a Java / Spring Boot API on a PostgreSQL hosted at Scalingo, the single entry point for both clients. What stayed is the interface: the practitioner back-office is still React, and adding the patient mobile app extended the front-end rather than replacing it.

Carrying out that switch solo, on a product already in use, was the most instructive part of the project. It also explains the shape of the architecture today: if both interfaces only ever talk to the API, it is because the opposite was tried and could not hold up on health data.

The technical choices

API

Java and Spring Boot

End-to-end strong typing and an ecosystem whose maintenance and documentation will still be there in ten years: two properties that matter more than concision on a health product.

Boundaries

Modular monolith, a single process

Every business module owns a boundary, enforced at build time: a forbidden dependency breaks compilation instead of going to review. The isolation of microservices, without their operational cost for a team of one.

Clinical logic

Configured, not coded

Assessments and alert criteria are versioned data, edited from the back-office and effective immediately. The product stops depending on my release cycles.

Data hosting

Off Supabase, database behind the API

The MVP queried Supabase from the front-end. Timestamped consent, retention and an access log belong server-side: HDS compliance forced the schema and the access rules back behind the API.

Mobile

React Native and Expo

The patient app displays exercises and collects tolerance feedback: nothing that demands native. One codebase for iOS and Android halves the surface to maintain.

The architecture that follows

Overview
Scalingo · HDS-certified · French regionversioned migrationswritten on every readPractitioner back-officeNext.js · React · TypeScriptPatient appReact Native · iOS and AndroidVersioned REST APIJava · Spring Boot · modular monolithPostgreSQLversioned schema · encrypted recordsAccess logevery record read traced
Scroll the diagram horizontally.
Both interfaces only ever talk to the API: neither reaches the database.

All 310 API routes live under /api/v1. The back-office and the mobile app update at different rhythms, and an app installed on a phone does not redeploy with a git push: API versioning is not a theoretical precaution here.

What the test suite covers

Working solo changes the method: with no reviewer, the only thing that can contradict a line of reasoning is a test. Coverage is therefore not spread evenly: it is concentrated where a silent mistake would have clinical or regulatory consequences.

Golden

Progression and training load

The most sensitive piece: it decides whether a patient steps up or eases off. It is locked down by reference corpora replayed on every run, one of them covering 19,440 transitions. Any divergence breaks the suite; the new expected behaviour has to be justified explicitly.

Unit

Clinical criteria evaluation

Every comparison operator and every combination of answers has to produce the expected flag, including degraded cases: a missing answer, an out-of-range value, a criterion referencing a question that was removed from the assessment.

Integration

Authorisation, route by route

Authorisation is declared explicitly on each route rather than inferred from the presence of a token. One test per route checks that a practitioner unrelated to the record is refused, not merely that an authenticated user is accepted.

Integration

Persistence and migrations

Tests run against a real PostgreSQL started in a container, not an in-memory database that would accept queries production rejects. The schema is rebuilt from scratch on every run: a migration that fails to replay is caught before it ships.

Integration

GDPR lifecycle

Consent collection and withdrawal, soft deletion, effective purge once retention expires, completeness of the access log. These are verifiable requirements, so they are verified.

E2E

Back-office journeys

In a real browser: login, record creation, running an assessment, reading the flags it raised, prescription. The full journey, not isolated screens.

Build

Module boundaries

Allowed dependencies between business modules are declared and enforced at compilation. A shortcut taken on a Friday evening does not compile.

The volume is not the argument, quotable as it is: 4,658 tests on the API, whose actual execution I verified rather than just counting. The argument is that none of these areas can change behaviour silently.

What health data demands

Compliance is not a layer added before going live, it is a set of constraints written into the earliest migrations. Consent is explicit, timestamped data rather than a ticked box; deletion is soft, with a 30-day retention window; every read of a patient record is logged. These requirements belong in the schema because an audit log added afterwards leaves a historical gap nothing can fill. Hosting follows the same logic: the platform runs on Scalingo, HDS-certified, in a French region. A certification is a legal prerequisite, settled before it is an infrastructure choice.

The same principle applies to external dependencies. A monitoring tool will happily ship a name or a clinical answer inside an error context, so sensitive data is scrubbed before anything is sent, at the source rather than by filtering downstream.

Where the product stands

The platform is in production and still evolving: a 310-route API covered by 4,658 tests, a practitioner back-office, a patient mobile app on iOS and Android, and hosting on Scalingo, HDS-certified, in France, all maintained by a single person.

Opening it to patients is still ahead. That is also why this page quotes no usage metric: there is none yet, and a volume number in its place would only measure what I produced.

The central bet holds up over time: practitioners evolve their assessments and alert criteria without going through me. That is exactly what the decision engine was meant to make possible.

What the client says

Brought in to develop our health application MVP (React + Supabase) and bring it into compliance, he showed remarkable technical rigour and autonomy on a demanding subject: a rehabilitation app handling health data, with every security and compliance constraint that implies. […] Nathan was a genuine build partner on this project, not merely a contractor. I recommend him without reservation.
Nicolas, private-practice physiotherapistClient review, 29 August 2026 · translated from French

The interface

Patient app home screen, with ongoing records and the session of the day
The patient's records, one per body area, each starting with an assessment
Morning check-in, with sliders for stiffness, pain and sleep quality
Session setup step, available equipment and manageable positions
Generated session, seven exercises matched to the current phase
Patient progression screen, with phases cleared and pain evolution

The patient app opens on the day's session and the four-phase journey

One record per body area, and each one starts with a clinical assessment

The morning tolerance feedback: it automatically tunes the intensity of the session

Before prescribing, the session asks for available equipment and manageable positions

The session the engine produces, matched to the phase, the duration and the declared equipment

Progression reads phase by phase, driven by the patient's tolerance feedback

1 / 6

Lessons LearnedLessons Learned

Design

Compliance is a design constraint

Design

With health data, consent, traceability and retention belong in the schema from the earliest migrations. Bolted on afterwards, they leave gaps no patch can fill.

Design

Configure what moves, code what doesn't

Design

Clinical logic evolves at the pace of practice, not of releases. Expressing it as data rather than code makes the product independent of its developer.

Process

Solo, tests replace the reviewer

Process

With nobody to challenge a line of reasoning, the test suite becomes the only safeguard. It deserves the same care as the code it protects.

Navigation

Articles

Projects

Actions