← All projects

Forma

A model that is not allowed to invent facts

Status Pre-production, and the banner in the app says so.


The problem

A weekly training and nutrition plan living in a spreadsheet cannot react to last week's body composition, to a run that finished at eleven at night in an Alicante summer, or to a change in shopping prices.

Forma connects body composition, training, nutrition and the cost of the weekly shop into one loop, and tries to answer a single question: what should I do this week, given what happened last week.


The boundary around the model

A language model generates the plan. It never states a fact. The API publishes a catalog of foods, each with macros somebody measured, and an imported plan may only reference identifiers from that catalog. Anything else is rejected at import time.

The reasoning is written into the format document in one sentence: the macros of a food are something a person measures, not something a model estimates. The model gets to compose. It does not get to assert.


A domain that does not know about frameworks

The backend is hexagonal, with the domain kept free of framework types and the infrastructure held at the adapter boundary. Persistence is JDBC over PostgreSQL with Flyway migrations and deliberately no ORM, a decision recorded in an architecture decision record rather than left to be rediscovered later.

Sixty-odd migrations in, that choice still holds, which is the only evidence that matters about an architectural decision.


Measured, not typed in

Body measurements arrive through a Withings OAuth integration rather than manual entry, because a number you have to retype is a number you stop recording. A weekly insights service turns those raw metrics into small adjustments, in the hundred-calorie range, instead of dramatic plan rewrites.


How it is built

Thirteen architecture decision records, a specification per story kept in the repository, and a React 19 front end covered by Vitest unit tests and Playwright end-to-end runs, all gated in continuous integration.


Stack

Java 21Spring Boot 3HexagonalPostgreSQL 17FlywayReact 19TypeScriptViteVitestPlaywrightDocker Compose

Written up on the lab