Your smart running companion - A full-stack web application to track your running workouts and monitor your progress.
This project was built by @jannisarndt as a learning journey to explore:
- Data processing and statistics
- Full-stack application development
- Building authentication systems from scratch
- Creating custom APIs
- Frontend development with modern frameworks
- Scaling and deploying production applications
Contributions are welcome! If you have ideas or improvements, feel free to open a PR or reach out.
Contact: support@bttr.sh
- Workout Management - Create, edit, copy, and delete workout sessions
- Interval Tracking - Log individual running intervals with distance and time
- Performance Statistics - Visual charts for distance, speed, and progress over time
- Authentication - Passwordless magic link login and Google OAuth
- Multi-language - English and German support (i18n)
- Responsive Design - Optimized for both desktop and mobile
| Technology | Purpose |
|---|---|
| Next.js 16 | React framework with App Router |
| React 19 | UI library |
| TypeScript | Type safety |
| TailwindCSS 4 | Styling |
| shadcn/ui | UI components |
| Recharts | Data visualization |
| SWR | Data fetching |
| next-intl | Internationalization |
| Technology | Purpose |
|---|---|
| Cloudflare Workers | Serverless edge runtime |
| Hono | Lightweight web framework |
| Drizzle ORM | Database operations |
| Neon | Serverless PostgreSQL |
| better-auth | Authentication |
| Resend | Email delivery |
run-pal/
├── apps/
│ ├── backend/ # Cloudflare Workers API
│ │ ├── src/
│ │ │ ├── index.ts # Main entry point
│ │ │ ├── auth.ts # Authentication config
│ │ │ ├── workouts.ts # Workouts API
│ │ │ ├── intervals.ts # Intervals API
│ │ │ ├── stats.ts # Statistics API
│ │ │ └── db/ # Database schema & client
│ │ └── drizzle/ # Database migrations
│ │
│ └── frontend/ # Next.js application
│ ├── src/
│ │ ├── app/ # Pages (App Router)
│ │ ├── components/ # React components
│ │ ├── hooks/ # Custom hooks
│ │ └── lib/ # Utilities
│ └── messages/ # i18n translations
- Node.js 18+
- pnpm (recommended) or npm
- A Neon database account
- A Resend account (for emails)
- Google OAuth credentials (optional)
cd apps/backend
# Install dependencies
pnpm install
# Configure environment variables
cp .env.example .envFill in your .env file:
BETTER_AUTH_SECRET=your-secret-key
DATABASE_URL=your-neon-connection-string
BETTER_AUTH_URL=http://localhost:8787
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
RESEND_TOKEN=your-resend-api-key
PRODUCTION_URL=https://your-production-url.com
DEVELOPMENT_URL=http://localhost:3000Run the backend:
# Push database schema
pnpm db:push
# Start development server
pnpm devcd apps/frontend
# Install dependencies
pnpm install
# Configure environment variables
cp .env.example .envFill in your .env file:
DATABASE_URL=your-neon-connection-string
BETTER_AUTH_URL=http://localhost:8787
NEXT_PUBLIC_API_URL=http://localhost:8787
NEXT_PUBLIC_BASE_URL=http://localhost:3000Run the frontend:
# Start development server
pnpm devThe app will be available at http://localhost:3000.
| Method | Endpoint | Description |
|---|---|---|
| GET | /workouts |
List all workouts |
| POST | /workouts |
Create a workout |
| GET | /workouts/:slug |
Get workout by slug |
| PUT | /workouts/:slug |
Update workout |
| DELETE | /workouts/:slug |
Delete workout |
| POST | /workouts/:slug/copy |
Duplicate workout |
| Method | Endpoint | Description |
|---|---|---|
| GET | /workouts/:slug/intervals |
List intervals |
| POST | /workouts/:slug/intervals |
Create interval |
| PUT | /workouts/:slug/interval/:id |
Update interval |
| DELETE | /workouts/:slug/interval/:id |
Delete interval |
| Method | Endpoint | Description |
|---|---|---|
| GET | /stats/distance |
Distance per day (7 days) |
| GET | /stats/speed |
Average speed per day |
| GET | /stats/count |
Interval count per day |
| GET | /stats/cumulative-distance |
Cumulative distance |
cd apps/backend
pnpm deployConnect your repository to Vercel and configure the environment variables in the dashboard.
Contributions are appreciated! Here are some ways you can help:
- Report bugs and issues
- Suggest new features
- Submit pull requests
- Improve documentation
This project is open source.
Built by @jannisarndt
Contact: support@bttr.sh