Italian-aware meal tracking from a photo. Install on iPhone via Safari "Add to Home Screen". Family-sized (3–4 users), self-hosted on Railway.
License at a glance (Foodiy is source-available, not open-source — see LICENSE for the binding text):
Tier Who it's for Users/deployment What's required Personal You + friends/family fewer than 10 Tell me you're running it (one-line email or GitHub issue). Community Development Forks, collaboration, beta/staging fewer than 25 Tell me when you materially change or publish changes. Stay non-commercial. Commercial Any paid/revenue/business use, incl. commercial enhancements — Pre-approval required. I must be both informed AND included as a participating party (attribution, revenue share, equity, or negotiated terms). All contact: [email protected] (subject prefix
[FOODIY-FSAL]for notifications,[FOODIY-FSAL COMMERCIAL REQUEST]for commercial).
npm install
cp .env.example .env # fill in OPENAI_API_KEY, JWT_SECRET, etc.
# Point DATABASE_URL at a local Postgres (Docker: docker run -p 5432:5432 -e POSTGRES_PASSWORD=x postgres:16)
npm run db:migrate # creates the schema
npm run devOpen http://localhost:3000 — you'll hit the first-run setup (needs ADMIN_SETUP_TOKEN from .env).
- Fork/push this repo to GitHub.
- Create a new Railway project → "Deploy from GitHub repo".
- Add a Postgres plugin — Railway auto-wires
DATABASE_URL. - Add a Volume — mount path
/data, size ~5GB. - Set env vars in the Railway service settings:
JWT_SECRET—openssl rand -base64 32OPENAI_API_KEYOPENAI_MODEL(optional; defaults togpt-5.4)UPLOADS_DIR=/data/uploadsADMIN_SETUP_TOKEN=<anything>— used only for first-user registration
- Deploy. Railway reads
railway.jsonand runsnpm ci && prisma generate && next build→npm start(which runsprisma migrate deploybeforenext start). - Open the public URL on iPhone Safari → Share → Add to Home Screen.
- First login: go to
/login, enter your name, a 4–8 digit PIN, and yourADMIN_SETUP_TOKEN. You become the admin. - Add family members:
/loginshows login-only thereafter; admin can add new users through their own settings flow (or directly viaPOST /api/auth/setupwhile logged in as admin). - Unset
ADMIN_SETUP_TOKENafter initial setup (no longer used by live paths).
You asked to keep photos forever. UPLOADS_DIR=/data/uploads is on the mounted volume, survives redeploys, and stays private (no bucket to leak). Photos are served through /api/images/[filename] with an owner-check so one family member can't see another's plates.
See CLAUDE.md for the full map. High-level:
- Next.js 15 App Router (TypeScript) — one codebase, SSR pages + API routes.
- Postgres + Prisma — users, meals, ingredients, diets, favorites.
- OpenAI —
gpt-5.4(configurable) for photo analysis and diet parsing. System prompt biases toward CREA / Italian standards. - CREA nutrition data — ~80 Italian staples seeded in
src/lib/nutrition/crea-data.ts; fuzzy-match ingredient names, blend with LLM estimates. - Transparent scoring — each meal is scored 0–10 vs. the active diet with a reason breakdown. Formula in
src/lib/nutrition/scoring.ts. - Meal grouping — 75-min rolling window folds snaps into the same breakfast/lunch/dinner.
npm run dev # local dev
npm run build # prisma generate + next build
npm start # prisma migrate deploy + next start
npm run db:migrate # prisma migrate dev (create migrations locally)
npm run db:studio # Prisma Studio GUI
npm run typecheck # tsc --noEmit
sharpfails on install: Railway's Nixpacks includes libvips. If self-hosting elsewhere, installlibvips-dev.pdf-parsetest file error: fixed by importing frompdf-parse/lib/pdf-parse.js— don't revert.- OpenAI model 404: change
OPENAI_MODELenv var to a SKU that exists for your key (e.g.gpt-4o). - "invalid setup token" on first login:
ADMIN_SETUP_TOKENisn't set in Railway env, or was cleared. Set it, redeploy, then try again.
Pull requests and issues are welcome. By submitting a contribution you agree that your contribution becomes part of Foodiy under the same FSAL terms.
How to pick a tier:
- Personal tier (friends & family, < 10 users per deployment) — free. Just notify me once you deploy or fork:
- Open a GitHub issue titled
[FSAL Notification], or - email
[email protected]with subject[FOODIY-FSAL]. - Include: your name/handle, a link to your fork (if any), which tier, and a one-line description of use.
- Open a GitHub issue titled
- Community Development tier (forks, collaboration, dev/beta, < 25 users per deployment) — free. Notify me on first fork and each time you publish material changes. Keep it non-commercial while in this tier.
- Commercial tier (any paid use, business use, or commercial improvement) — requires prior written approval and inclusion of me as a participating party in the arrangement (attribution, revenue share, equity, or other negotiated terms). Send a request to
[email protected]with subject[FOODIY-FSAL COMMERCIAL REQUEST]describing intended use, scale, entity, and proposed inclusion terms.
Any derivative work must keep the LICENSE file and include this attribution: Based on "Foodiy" by Filippo Mattia Menghi — https://github.com/Cyberfilo/foodiy — licensed under FSAL v1.1.