NutriCare is a Next.js and Express application for pantry tracking, confirmed meal logging, nutrition estimates, alerts, and doctor-supervised nutrition plans for actively linked hospital patients.
- Windows PowerShell
- Node.js 20 or newer
- PostgreSQL, or a Supabase PostgreSQL connection string
- Python virtual environment with PaddleOCR and PaddlePaddle only when receipt OCR is required
Open PowerShell in the repository root:
Set-Location .\backend
npm.cmd install
Copy-Item .env.example .env
notepad .envSet these values in backend\.env:
DATABASE_URL=postgresql://USER:PASSWORD@HOST:5432/DATABASE
DATABASE_SSL=true
JWT_SECRET=replace-with-a-long-random-secret
PORT=3002
PYTHON_EXECUTABLE=C:/path/to/.venv/Scripts/python.exeUse DATABASE_SSL=false for a local PostgreSQL server that does not use TLS. PYTHON_EXECUTABLE is optional unless OCR is used. Do not commit .env.
Apply every unapplied numbered migration:
npm.cmd run migrateStart the backend:
npm.cmd startThe backend is available at http://localhost:3002. Verify it in another PowerShell window:
Invoke-RestMethod http://localhost:3002/healthFor automatic restarts during backend development, use npm.cmd run dev. On Windows, use npm.cmd start if node --watch leaves a stale child process on port 3002.
Open a second PowerShell window in the repository root:
Set-Location .\frontend
npm.cmd install
Copy-Item .env.local.example .env.local
npm.cmd run devThe frontend is available at http://localhost:3000 and expects this value in frontend\.env.local:
NEXT_PUBLIC_API_BASE_URL=http://localhost:3002From the repository root:
py -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install paddleocr paddlepaddleSet PYTHON_EXECUTABLE in backend\.env to the absolute path of .venv\Scripts\python.exe, then restart the backend.
OCR suggestions are review-only. A receipt can suggest a purchased food name and package quantity, but it never confirms consumption. The patient must edit or confirm the food name, consumed quantity, and unit in the meal journal before nutrition totals are updated.
On Vercel, receipt OCR uses an OpenAI-compatible vision API because the Node service does not include the local PaddleOCR runtime. Set OPENAI_API_KEY in Vercel Environment Variables (and optionally OPENAI_VISION_MODEL or OPENAI_BASE_URL). Locally, OCR_PROVIDER=auto continues to use PaddleOCR; set it to vision to use the hosted provider instead.
Plate photo recognition uses the same vision configuration. Restart or redeploy after changing these variables, then use Recognize plate in the meal journal. Receipt products, recognized foods, quantities, and portion weights are suggestions that the patient must review before saving.
- Register one
hospital_patientaccount and onedoctoraccount. - Copy the patient user ID shown in the patient interface.
- Sign in as the doctor and link that patient on
/doctor. - Select the linked patient and manage conditions, daily limits, avoid foods, and foods to consume more often.
- Sign in as the patient and open
/dashboardto view the read-only care plan and current daily totals. - Log a meal with a manually confirmed quantity and unit.
- Open
/notificationsas the patient or doctor to view saved alerts.
Daily boundaries use the patient browser's IANA timezone when supplied during meal logging, with UTC as the database default. Daily-limit warnings are deduplicated per recipient, limit, and local date.
All application API routes use the /api prefix so their URLs do not collide
with frontend pages such as /doctor, /meals, and /notifications.
| Method | Route | Access |
|---|---|---|
GET |
/api/doctor/patients |
Doctor |
POST |
/api/doctor/link-patient |
Doctor; hospital patients only |
GET |
/api/doctor/patients/:patientId/plan |
Actively linked doctor |
PUT |
/api/doctor/patients/:patientId/conditions |
Actively linked doctor |
POST |
/api/doctor/patients/:patientId/limits |
Actively linked doctor |
PATCH |
/api/doctor/patients/:patientId/limits/:limitId |
Owning, actively linked doctor |
DELETE |
/api/doctor/patients/:patientId/limits/:limitId |
Owning, actively linked doctor |
POST |
/api/doctor/patients/:patientId/recommendations |
Actively linked doctor |
PATCH |
/api/doctor/patients/:patientId/recommendations/:recommendationId |
Owning, actively linked doctor |
DELETE |
/api/doctor/patients/:patientId/recommendations/:recommendationId |
Owning, actively linked doctor |
GET |
/api/supervision |
Hospital patient, own plan only |
GET |
/api/supervision/daily-totals |
Hospital patient, own totals only |
PUT |
/api/supervision/timezone |
Hospital patient |
POST |
/api/ocr/check-foods |
Hospital patient; possible-purchase check only |
POST |
/api/food-gallery |
Authenticated; save own plate photo and recognition results |
GET |
/api/food-gallery |
Authenticated; view own saved food photos |
GET |
/api/food-gallery/patient/:patientId |
Doctor with an active link to the patient |
POST |
/api/meals |
Authenticated; supervision calculation is automatic for hospital patients |
Legacy /api/doctor/nutrition-targets and /api/doctor/check-nutrition routes remain available for compatibility. New supervision plans use /api/doctor/patients/:patientId/*, and meal logging performs checks automatically.
Keep the migrated backend running on port 3002. In another PowerShell window:
Set-Location .\backend
npm.cmd run test:supervisionThe integration test registers temporary accounts, verifies the complete doctor/patient flow, confirms cumulative sodium totals and notification deduplication, checks OCR possible-purchase wording, tests unauthorized 403 responses, and deletes the temporary accounts in finally.
Run static backend and frontend checks:
Set-Location .\backend
Get-ChildItem .\src -Recurse -Filter *.js | ForEach-Object { node --check $_.FullName }
Set-Location ..\frontend
npm.cmd run lint
npx.cmd tsc --noEmit
npm.cmd run buildThe bundled USDA-derived database calculates calories, protein, carbohydrates, fat, fibre, sugar, and sodium for matched foods. Ingredient limits are calculated from confirmed meal item quantities when the logged unit is compatible with the limit unit, such as tablespoons of oil converted to millilitres. Custom limits remain stored and visible even when the local food database has no matching calculated metric.
Nutrition results are estimates for informational and supervision support. NutriCare records doctor-entered conditions and guidance; it does not diagnose patients or make unsupported medical claims.