No description
- JavaScript 53.4%
- CSS 23.8%
- Python 22%
- HTML 0.4%
- Dockerfile 0.4%
| .idea | ||
| backend | ||
| frontend | ||
| .env | ||
| docker-compose.yml | ||
| README.md | ||
MedSync — Medication Tracker
A self-hosted medication tracker PWA with bottle scanning via Claude AI, push notifications, and optional SMS alerts.
Stack
| Layer | Tech |
|---|---|
| Backend | Python 3.12 · FastAPI · APScheduler |
| Database | SQLite (via Python stdlib) |
| Frontend | React 18 · Vite · PWA (service worker) |
| Serving | nginx (frontend) · uvicorn (backend) |
| Infra | Docker Compose |
Quick Start
1. Generate secrets
# JWT secret
openssl rand -hex 32
# VAPID keys for push notifications
pip install pywebpush
python -c "from py_vapid import Vapid; v = Vapid(); v.generate_keys(); print('Public:', v.public_key); print('Private:', v.private_key)"
# OR use the web tool: https://vapidkeys.com
2. Configure environment
cp .env.example .env
# Edit .env and fill in all values
3. Build and run
docker compose up -d --build
Frontend: http://localhost:3000
API docs: http://localhost:3001/docs (FastAPI auto-generated Swagger UI)
Environment Variables
| Variable | Required | Description |
|---|---|---|
JWT_SECRET |
✅ | Random secret for signing tokens |
ANTHROPIC_API_KEY |
✅ | For pill bottle scanning |
VAPID_PUBLIC_KEY |
✅ | For browser push notifications |
VAPID_PRIVATE_KEY |
✅ | For browser push notifications |
VAPID_EMAIL |
✅ | mailto:you@domain.com |
TWILIO_ACCOUNT_SID |
➖ | Optional — enables SMS alerts |
TWILIO_AUTH_TOKEN |
➖ | Optional — enables SMS alerts |
TWILIO_FROM_NUMBER |
➖ | Optional — your Twilio phone number |
Android PWA Setup
- Open Chrome on Android and navigate to your server URL
- Tap the ⋮ menu → "Add to Home screen"
- The app installs like a native app with push notification support
- First launch: tap Enable Notifications in the app settings
Project Structure
medsync/
├── docker-compose.yml
├── .env.example
├── backend/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── app/
│ ├── main.py # FastAPI app + lifespan
│ ├── db/
│ │ └── schema.py # SQLite init + context manager
│ ├── routes/
│ │ ├── auth.py # Register, login, profile
│ │ ├── medications.py # CRUD + dose logging
│ │ └── scan.py # Claude Vision bottle scan
│ └── services/
│ ├── auth.py # JWT + bcrypt
│ ├── notifications.py # WebPush + Twilio SMS
│ └── scheduler.py # APScheduler — checks every 5 min
└── frontend/
├── Dockerfile
├── nginx.conf
├── vite.config.js # Vite + PWA plugin
└── src/
├── services/api.js # All API calls
├── contexts/AuthContext.jsx
└── hooks/usePushNotifications.js
Development (without Docker)
Backend:
cd backend
pip install -r requirements.txt
cp ../.env.example .env # fill in values
uvicorn app.main:app --reload --port 3001
# Swagger UI at http://localhost:3001/docs
Frontend:
cd frontend
npm install
npm run dev # proxies /api to localhost:3001
Reverse Proxy (recommended for production)
Put nginx or Caddy in front to add HTTPS — required for:
- Camera access on Android Chrome
- Push notifications (requires secure context)
Example Caddy snippet:
medsync.yourdomain.com {
reverse_proxy localhost:3000
}