A personal medication tracking web application built with SvelteKit, designed for quick dose logging, live timers, adherence analytics, and inventory management. Server-first architecture with a dark-mode glassmorphism UI.
user_idIntl.DateTimeFormat| Layer | Technology |
|---|---|
| Framework | SvelteKit with Svelte 5 runes |
| Styling | Tailwind CSS v4 — dark-mode-first, glassmorphism design system |
| Database | PostgreSQL via Neon serverless driver |
| ORM | Drizzle ORM with type-safe schema |
| Auth | Lucia v3 + Arctic for OAuth |
| Validation | Zod |
| Resend | |
| PDF Export | PDFKit |
| Password Hashing | Argon2 via @node-rs/argon2 |
| Testing | Vitest + Playwright |
| Deployment | Vercel (via @sveltejs/adapter-vercel) |
git clone https://github.com/yourusername/medication-tracker.git
cd medication-tracker
npm install
Create a .env file in the project root:
# Required
DATABASE_URL=postgresql://user:password@host/database?sslmode=require
# Email (required for verification, password reset, and reminders)
RESEND_API_KEY=re_xxxxxxxxxxxxx
EMAIL_FROM="MedTracker <[email protected]>"
# OAuth (optional — app works with email/password only)
GOOGLE_CLIENT_ID=xxxxxxxxxxxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxx
GITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxxx
GITHUB_CLIENT_SECRET=xxxxxxxxxxxxx
# Cron endpoint protection (required if using scheduled reminders)
CRON_SECRET=a-random-secret-string
Push the schema to your database:
npx drizzle-kit push
To generate migration files (for version-controlled migrations):
npx drizzle-kit generate
npm run dev
The app runs at http://localhost:5173.
npm run build
npm run preview # preview locally
# Run all unit tests
npx vitest run
# Run a specific test file
npx vitest run tests/unit/time.test.ts
# Run in watch mode
npx vitest
src/
├── routes/
│ ├── +page.svelte # Landing page
│ ├── auth/ # Login, register, password reset, OAuth callbacks
│ ├── (app)/ # Authenticated route group (auth guard in layout)
│ │ ├── dashboard/ # Main dashboard with quick log + timeline
│ │ ├── medications/ # Medication list, detail, create/edit
│ │ ├── log/ # Full dose history with pagination + filters
│ │ ├── analytics/ # Streaks, adherence, heatmap, hourly chart
│ │ └── settings/ # Profile, appearance, notifications, data, security
│ └── api/
│ └── export/ # PDF/CSV export endpoint
├── lib/
│ ├── server/ # Server-only code (never imported from client)
│ │ ├── db/schema.ts # Drizzle table definitions
│ │ ├── auth/ # Lucia setup, OAuth providers
│ │ ├── analytics.ts # Streak, adherence, heatmap, hourly queries
│ │ ├── doses.ts # Dose query helpers
│ │ ├── audit.ts # Audit log with JSONB diff tracking
│ │ ├── email.ts # Resend email helpers
│ │ ├── export-csv.ts # CSV export generation
│ │ └── preferences.ts # User preferences CRUD
│ ├── components/ # Svelte 5 components (runes syntax)
│ │ ├── ui/ # Reusable primitives (GlassCard, Input, Modal, Toast, Tooltip)
│ │ ├── MedicationForm.svelte # Dual-colour picker, pattern grid, tooltips
│ │ ├── MedicationCard.svelte # Medication list item with pattern rendering
│ │ ├── QuickLogBar.svelte # One-tap dose logging strip
│ │ ├── TimelineEntry.svelte # Dose timeline item with live timer
│ │ ├── Heatmap.svelte # 90-day activity heatmap
│ │ └── AdherenceChart.svelte # Per-medication adherence bars
│ ├── utils/
│ │ ├── validation.ts # All Zod schemas
│ │ ├── medication-style.ts # Pattern rendering utility (CSS backgrounds)
│ │ └── time.ts # Time formatting helpers
│ └── types.ts # Shared TypeScript types
└── app.css # Tailwind v4 theme + design tokens
The UI uses a dark-mode glassmorphism design system built with Tailwind CSS v4 custom theme tokens:
glass / glass-border / glass-hover — frosted glass surfaces with backdrop blursurface / surface-raised / surface-overlay — layered surface elevationtext-primary / text-secondary / text-muted — typographic hierarchyaccent / success / warning / danger — semantic colour paletteAll components use Svelte 5 runes ($props(), $state(), $derived(), $effect()).
The app is configured for Vercel deployment via @sveltejs/adapter-vercel. Set all environment variables in your Vercel project settings.
For scheduled medication reminders, configure a Vercel Cron Job pointing to /api/cron/reminders with the CRON_SECRET header.
MIT