Our product
360nutri
A calorie and macro tracker for people who want a food diary they will actually keep, where you photograph the plate instead of typing the meal in.
Point a phone at a meal and 360nutri returns estimated calories, protein, carbohydrate, fat, fibre, sugar and sodium, with the ingredients it thinks it saw and a confidence score. The log feeds a daily dashboard, a searchable history you can correct, and meal suggestions built from what you have eaten recently. The hosted backend it points at is currently unreachable, so the live site is dormant rather than trading.
What it does
- Photo analysis returning calories, macros, ingredients, category and a confidence score
- Rear camera capture or file upload
- Daily dashboard with calorie target, macro split, logging streak and health score
- Meal history with search, filtering, sorting, editing and deletion
- Meal suggestions generated from your profile and recent meals
- Recipe library filtered by cuisine, meal type, difficulty, dietary label and time
- Hourly recipe generation on a database cron, with an off switch held in a table
- Five step onboarding plus profile settings for targets, allergens and goals
- Row level security scoping every meal and profile to its owner
- Account deletion that removes meals, profile and the auth record
Food diaries fail in the first fortnight, and not because people stop caring. They fail because logging a sandwich means searching a list of eleven thousand sandwiches and choosing the one that is nearest. Do that three times a day and you are finished by Thursday. 360nutri asked whether a photograph could replace the search box: point a phone at the plate, get calories and macros back, correct anything that looks wrong, and move on. It worked well enough to be worth writing about, and the hosted backend behind it no longer resolves, so this entry is an account of a product that is off rather than one you can sign up for.
Why it exists
The bargain in any food log is between effort and accuracy, and most products get the balance backwards. They insist on precision the user cannot supply, then lose the user entirely. Two seconds of effort with an honest margin of error beats thirty seconds of effort with a number that looks exact and was wrong anyway, because the second kind of entry never gets made at all.
A model looking at a plate cannot see the oil in the pan or the sugar stirred through the sauce. That limit is not a defect to hide; it is the thing the interface has to be built around. So every analysis comes back with a confidence score, every field is editable before it is saved, and nothing is written to the log until the person confirms it. The audience was British from the start, down to the language: en-GB throughout the interface and in the model prompts, because a nutrition app that logs fiber to a user in Leeds has told them it was built for somewhere else.
How it works
The app is a React single-page application. All the interesting work happens in edge functions, and the whole product comes down to three paths that call a model at three different rhythms.
| Path | When the model runs | What it returns | What limits it |
|---|---|---|---|
| Photo analysis | on demand, once per meal logged | calories, protein, carbohydrate, fat, fibre, sugar, sodium, ingredients, category, confidence | nothing, it runs whenever a meal is logged |
| Meal suggestions | when the user asks | ideas fitting their calorie target, dietary preferences and allergens | a daily click cap counted in the browser |
| Recipe library | hourly, on a database cron | new recipes written into Postgres | a switch held in a control table |
The analysis path in full:
photo -> edge function -> vision model, asked for a structured breakdown
<- calories, six macros, ingredients[], category, confidence
user reviews, edits any field, confirms
-> meal row in Postgres, protected by row level security
-> image in object storage alongside it
Around that sit the ordinary parts of a consumer app, all finished: five-step onboarding covering physical stats, activity level, dietary preferences and goals; a dashboard with the day's calories against target, a macro split, a logging streak and a health score; a history view that searches, filters, sorts, edits and deletes; profile settings for allergens and targets; a cookie banner; and a web manifest so it installs on a phone home screen. Account deletion runs through a Postgres function that removes the meals, the profile and the auth record, rather than setting a flag on a row and calling it gone.
The decision that shaped it
The first decision was to keep every model call on the server, in an edge function, and to enforce ownership in the database rather than in the client. The API key never reaches the browser. The prompt can be changed without shipping a new bundle. The response can be validated before the app ever sees it. Row level security on every user table means a meal row is readable only by the account that owns it, which is a guarantee the database makes rather than a promise a query is supposed to keep. What it costs is a network hop on the critical path, a function invocation billed per analysis, and no possibility of logging a meal offline.
The second decision was to generate the recipe library ahead of time on an hourly schedule instead of on request. A model call per page view is a bill that grows with curiosity; a model call per hour is a bill you can forecast. The same reasoning shows up wherever a model sits on a write path, which is why atHeartbeat can skip its moderation call entirely and why Jonosakti runs a small instruct model rather than a large one for the same four jobs. We took the opposite view here: accuracy on the plate is the whole product, so the analysis path uses a capable vision model and pays for it, while the recipes, which nobody is measuring, run cheaply on a clock. The general shape of that arithmetic, unit by unit, is in which parts of a timeline actually cost money.
The switch that stops the recipe job lives in a table rather than in a deployment, so it can be turned off from an admin screen at three in the morning without a build. That was a good instinct. It also put the content pipeline inside the same hosted project as the database, the auth and the functions, which turned out to be the decision that mattered most, though not in the way we intended.
Where it stands today
Archived, and the reason is worth being precise about.
The front end is deployed and loads perfectly. The sign-in card appears exactly where it should. Type an email address, press the button, and nothing happens, because the hosted project the bundle points at returns NXDOMAIN on public DNS. Sign-in, photo analysis, meal suggestions and the recipe list all fail for any visitor today. We do not know whether the project was deleted, paused under a dormancy policy, or migrated somewhere and never repointed, and that uncertainty is itself the finding: nobody had written down which account held it or what the dormancy rules were. The hourly recipe job lived inside the same project, so the content pipeline went with everything else and no separate signal existed for the content having stopped. The last commit is from October 2025. Nothing alerted anyone. We found out by looking, and then wrote it up in what breaks first when you stop maintaining a side project.
Other things worth stating plainly. There is no marketing site: the domain serves the app shell straight into a sign-in card, so all the public positioning lives in meta tags. The canonical URL, the Open Graph tags and the sitemap point at a .app domain rather than the .com the app is actually served from, which is the sort of drift that only surfaces when somebody audits. Nothing was ever charged for, and the structured data in the page head declares a price of zero in pounds. The accuracy of the calorie estimates is unmeasured; the confidence value in each row comes from the model itself and is not an independent check. Several documents in the repository describe the app as production ready and fully verified. Those were written by the people who built it and we are not treating them as evidence.
What this says about how we work
The failure here was not engineering, it was ownership, and it changed how we hand work over.
Every project we run now has an inventory file kept with the code: which registrar holds the domain, which card renews it, which account owns the database, what the dormancy policy is, and one command that proves the backing services are genuinely reachable. A check that fetches the homepage and asserts a 200 will pass forever on a static front end, no matter what has died behind it. The useful check touches the dependencies and asserts on what comes back.
The second habit is deciding a project's status rather than drifting into it. Maintained, frozen, or archived on purpose. The state you get by default is the bad one: still running, still accepting sign-ups, half the features broken, nobody watching. When we hand over a build we say which of those three it is going to be on day one, and how we scope and price work reflects the difference, because a frozen project and a maintained one are not the same commitment dressed differently.
The engineering lesson is smaller and still holds. In a small consumer app the decisions that matter are rarely about the framework. They are about where the model call happens, who is allowed to read a row, and whether the expensive thing runs on a schedule or on demand.
What we wrote about building it
More of the same kind
- ObjectifyA hosted backend that gives developers a typed database, authentication, file storage and AI inference behind one REST API.
- DMARC EngineEmail authentication for companies that need DMARC enforced on their domain without blocking their own mail.
- ConsonasA CRM for organisations of roughly two to two hundred people who want customer tracking without an administrator to run it.
Want something like this?
Tell us the shape of the problem and we will tell you honestly whether we are the right people for it.
Start a conversation