Running-injury triage MVP: a Flask API with a Bayesian inference engine and React (Vite) frontend. Users sign up, run a short symptom questionnaire, and get a probability-weighted triage summary.
- Backend: Python 3, Flask, SQLite (
users), in-memory diagnostic sessions,flask-cors,gunicornfor production - Frontend: React 18, React Router, plain CSS
- Core logic:
bayesian_engine.py,question_selector.py(information-gain–style question ordering)
Do not open your home router, forward ports, or run HOST=0.0.0.0 on your Mac to “show the world.” That exposes your network and is unnecessary. Instead:
- Host the API on a cloud app platform (e.g. Render).
- Host the frontend on a static host (e.g. Vercel).
- Your PC only runs Git push; the public only talks to HTTPS URLs on those services.
- Push this repo to GitHub (already set up for kyangOrange/Runlytics).
- Sign up at render.com → New → Blueprint.
- Connect the repo and apply
render.yaml(or create a Web Service manually: root = repo root, buildpip install -r requirements.txt, startgunicorn -w 2 -b 0.0.0.0:$PORT app:app). - In the service Environment tab, set:
CORS_ORIGINS— after you have a frontend URL (step B), set it to that origin only, e.g.https://your-project.vercel.app(no trailing slash). You can addhttp://localhost:5173too for local dev, comma-separated.FLASK_DEBUG=0(already inrender.yaml).SECRET_KEY— Render can generate this via the blueprint; or paste a long random string yourself. Never commit it to Git.
- Wait for deploy and copy the API URL, e.g.
https://runlytics-api.onrender.com. - Optional: open
https://…/health— should return{"status":"ok"}.
Free tier: the service may sleep after idle time; the first request after sleep can be slow—fine for a demo, mention it in your video if needed.
- Sign up at vercel.com → Add New Project → import the same GitHub repo.
- Set Root Directory to
frontend. - Framework: Vite. Build:
npm run build, output:dist(defaults are usually correct). - Environment variables (must be set before the production build completes):
VITE_API_URL= your Render API URL, e.g.https://runlytics-api.onrender.com(no trailing slash).
- Deploy. Use the https://….vercel.app URL as your public demo link.
- Go back to Render and set
CORS_ORIGINSto that exact Vercel origin if you have not already.
frontend/vercel.json adds SPA routing so React Router paths (e.g. /login) work on refresh.
| Deliverable | Suggestion |
|---|---|
| Demo | Screen recording: sign up → run test → results; say the public URL aloud or show it on screen. |
| Code | This repository (judges clone or browse on GitHub). |
| Privacy | Use fake emails in the demo; remind viewers the app is educational, not medical advice. |
cd Runlytics
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txtIf python is overridden by Conda and errors (e.g. missing Homebrew Python), run the app with the venv interpreter explicitly:
./.venv/bin/python app.pyDefault: http://127.0.0.1:5000 (debug on locally unless FLASK_DEBUG=0).
cd frontend
npm install
npm run devOpen http://localhost:5173 (or the URL Vite prints).
Optional: copy frontend/.env.example to frontend/.env and set VITE_API_URL if the API is not on http://127.0.0.1:5000.
The API allows http://localhost:5173 and http://127.0.0.1:5173 by default. For other origins, set CORS_ORIGINS (comma-separated) when running Flask.
| Variable | Purpose |
|---|---|
SECRET_KEY |
Flask signing key — required for any public deploy; set in the host dashboard, never in Git. |
CORS_ORIGINS |
Comma-separated exact frontend origins (your https://….vercel.app). If unset, local Vite defaults are used. |
PORT |
Listen port (Render sets this automatically). |
HOST |
For python app.py only (default 127.0.0.1). |
FLASK_DEBUG |
Use 0 on the internet. |
DATABASE_NAME |
SQLite filename under the app directory (default runlytics.db). |
Procfile/gunicorn: used by Render and similar hosts.runtime.txt: Python 3.12.8 for broad host compatibility (you can use 3.14 locally).- Sessions are in-memory → restarts or multiple workers can drop active tests; SQLite on free hosts is often ephemeral. Acceptable for a student demo; document for judges.
| Method | Path | Description |
|---|---|---|
GET |
/health |
Health check for monitors |
POST |
/auth/signup |
Body: email, password, display_name, age, biological_sex (female | male | other | prefer_not_say), prior_injury_same_area (boolean), equipment_access (bodyweight | gym), running_experience (beginner | intermediate | experienced). Stored as equipment_bodyweight_only plus running_experience. Profile fields (except name/email) adjust starting priors in bayesian_engine via prior_modifiers.py and experience multipliers in bayesian_engine.py. |
POST |
/auth/login |
Body: { "email", "password" } |
GET |
/user/<user_id>/profile |
Public profile JSON (no password hash). Includes equipment_access (bodyweight | gym) and running_experience. |
PATCH |
/user/<user_id>/profile |
Partial update: any of display_name, age, biological_sex, prior_injury_same_area, equipment_access, running_experience, or legacy equipment_bodyweight_only. Returns updated profile. |
POST |
/session/new |
Body: { "user_id" } — loads user row and builds engine with profile-adjusted priors. |
GET |
/session/<id>/next-question |
Next question or { "complete": true } |
POST |
/session/<id>/answer |
Body: { "symptom", "answer" } (boolean) |
GET |
/session/<id>/triage |
Probabilities + triage text |
This tool is for education / prototyping (including student competitions), not a substitute for professional medical diagnosis or treatment.
Add a license if you plan to open-source the project formally.