DapurPlan helps a restaurant forecast servings, calculate ingredient needs, and review preparation plans.
- Frontend and app backend: Next.js in
web/(login, SQLite database, recipes, sales, inventory and approvals). - ML backend: FastAPI in
src/dapurplan/api.py(loads the saved Random Forest pipeline and predicts servings).
Use two separate terminals and keep both running. Start each terminal in the
main DapurPlan folder, where pyproject.toml and the web folder are located.
Install Node.js 22, Python 3.12 and uv. The local setup was tested with Node.js
22.12.0 and Python 3.12.8. Verify these model files are inside model/:
sales_forecast_pipeline.joblibrequirements.txttraining_report.jsonexample_input.json
Install frontend dependencies:
cd web
npm install
cd ..Create the Python environment only if it does not already exist, then install backend dependencies from the project root:
if (!(Test-Path "venv/Scripts/python.exe")) {
uv venv --python 3.12 venv
}
uv pip install --python venv/Scripts/python.exe -r requirements-dev.txtYou only need to install dependencies again when they change.
From the main DapurPlan folder:
cd web
npm run devOpen http://127.0.0.1:4000.
Demo accounts:
- Owner: username
owner, password123. - Staff: username
staff, password123.
These are fixed prototype accounts, not production account management.
Open another terminal in the main DapurPlan folder:
$env:PYTHONPATH = "src"
.\venv\Scripts\python.exe -m uvicorn dapurplan.api:app --host 127.0.0.1 --port 8000Wait for Application startup complete before generating a forecast.
You do not need to activate the environment because the command calls its Python directly.
- API documentation: http://127.0.0.1:8000/docs.
- Service health: http://127.0.0.1:8000/health.
The frontend calls FastAPI from the Next.js server. Its default address is
http://127.0.0.1:8000. To change it, set FORECAST_API_URL in web/.env.local
and restart the frontend. This address must not use a NEXT_PUBLIC_ variable.
- Sign in at http://127.0.0.1:4000.
- Save complete sales for seven consecutive days for all five menu items.
- Open Tomorrow’s plan, generate a forecast, review preparation and shopping, then save a draft or approve as owner.
Recipes, sales, stock and plans persist in web/data/dapurplan.sqlite.
There is no automatic stock deduction when a plan is approved.
Stop each server with Ctrl+C in its terminal. Saved database records remain.
If npm run dev reports a missing package.json, run it inside web/.
If forecasting reports that the model service is unavailable, check Terminal 2.
If a port is already in use, check whether that server is already running before
starting another copy.
With the backend running, open another terminal in the project root:
Invoke-RestMethod -Uri http://127.0.0.1:8000/predict -Method Post -ContentType 'application/json' -Body (Get-Content model/example_input.json -Raw)Or open /docs, expand POST /predict, choose Try it out, paste
model/example_input.json, then Execute. The body accepts one to five distinct menu items.
Exact input columns: item, day_of_week, sales_yesterday, sales_last_week,
average_previous_7_days. Monday=0 through Sunday=6, verified against the team's
training notebook (date.dt.dayofweek). Inputs are relative to the target date:
for tomorrow, yesterday is today's completed sales, last week is target date minus
7 days, and the average uses the 7 completed calendar days before the target date.
Historical missing data must not silently become zero. The service accepts prepared
features only; Next.js builds them from saved database records. Sold-out flags are not
features of this saved model.
Output predicted_servings is a non-negative decimal, matching notebook clipping.
The app rounds preparation defaults up to whole servings and lets the owner adjust them before approval.
model_id is the artifact's SHA-256. synthetic_model identifies whether the saved
forecast used synthetic-only training data; the checked-in model reports true.
Its test MAE is 3.088 on synthetic regular-demand data, not verified restaurant
performance. After successful local retraining, saved forecasts identify the real-data
model used at that time.
The full fitted preprocessing pipeline is used. Model libraries match the export's
model/requirements.txt; incompatible scikit-learn versions fail at startup.
The export recorded Python 3.13.16; this local service is tested with Python 3.12.8.
Only load the trusted team artifact: joblib files can execute Python during loading.
This service is bound to loopback and has no deployed authentication/CORS integration. Add service authentication before external hosting. Never expose it publicly as-is. Frontend login and owner approval remain in the Next.js app.
The checked-in model is trained on synthetic data and is not a validated restaurant forecast. To retrain locally, collect at least 84 complete, non-demo sales days in the SQLite database, then run from the repository root:
.\venv\Scripts\python.exe scripts\train_forecast.py --database web\data\dapurplan.sqliteTraining reads the database in read-only mode, excludes imported demo-provenance days, incomplete days and sold-out observations, and validates chronologically against a last-week baseline. The model is replaced only when the Random Forest improves validation MAE by at least 5% without materially regressing any menu; otherwise the validated baseline is saved. The report includes the selected model and model-artifact hash. Restart FastAPI after retraining. With fewer than 84 complete days the command stops without changing the existing model.
$env:PYTHONPATH = "src"
.\venv\Scripts\python.exe -m unittest discover -s tests -vTests compare HTTP responses against direct pipeline predictions, validate five-item batches, reject invalid inputs, check clipping/non-finite outputs and missing-model startup. No sales records, stock or trained parameters are changed by these tests.