Skip to content

Latest commit

 

History

History
511 lines (360 loc) · 11.7 KB

File metadata and controls

511 lines (360 loc) · 11.7 KB

ASAP

ASAP — Server

Node.js + Express + TypeScript API for the Applied Strength & Advancement Platform. A self-hosted, data-driven workout tracker built for serious lifters.

API Reference · Deployment

Tech Stack

  • Node.js - Runtime environment
  • Express - Web framework
  • TypeScript - Type safety
  • Prisma - ORM and database toolkit
  • PostgreSQL - Database
  • JWT - Authentication
  • bcrypt - Password hashing

Project Structure

src/
├── controllers/         # Request handlers
│   ├── auth.controller.ts
│   ├── exercise.controller.ts
│   ├── session.controller.ts
│   └── weight.controller.ts
├── routes/             # API routes
│   ├── auth.route.ts
│   ├── exercise.route.ts
│   ├── session.route.ts
│   └── weight.route.ts
├── middleware/         # Custom middleware
│   └── auth.middleware.ts
├── utils/              # Utilities
│   ├── prisma.ts       # Prisma client instance
│   └── seed.ts         # Database seeding
└── index.ts            # Application entry point

prisma/
├── schema.prisma       # Database schema
└── migrations/         # Database migrations

data/
└── exercises.json      # Exercise library data

Development

Prerequisites

  • Node.js 18+
  • PostgreSQL 14+
  • Yarn

Setup

  1. Install dependencies
yarn install
  1. Set up environment variables

Create a .env file in the server directory:

DATABASE_URL=postgresql://postgres:12345@localhost:5432/asap
JWT_SECRET=change_this_to_a_long_random_secret
PORT=3000
NODE_ENV=development
TOKEN_EXP=7d
FRONTEND_DOMAIN=http://localhost:5173
  1. Set up database

Run Prisma migrations:

npx prisma migrate dev

Generate Prisma Client:

npx prisma generate
  1. Seed the database (optional)
npx prisma db seed
  1. Start development server
yarn dev

The API will be available at http://localhost:3000

Available Scripts

  • yarn dev - Start development server with hot reload
  • yarn build - Build for production
  • yarn start - Start production server
  • npx prisma db seed - Seed database with exercise data
  • npx prisma studio - Open Prisma Studio (database GUI)
  • npx prisma migrate dev - Create and apply migrations

Database Schema

Core Models

User

  • Authentication and profile data
  • Email, password (hashed), username
  • Links to sessions, exercises, and weight logs

UserProfile

  • Extended user information
  • Height, weight, fitness goals
  • One-to-one with User

WorkoutSession

  • Individual workout records
  • Name, date, duration, total volume
  • Contains multiple exercise entries

ExerciseEntry

  • Exercise performed in a session
  • Links to GlobalExercise or custom exercise
  • Contains multiple sets

Set

  • Individual set data
  • Weight, reps, RPE, rest time
  • Belongs to ExerciseEntry

GlobalExercise

  • Exercise library
  • Name, category, muscle groups, equipment
  • Can be used across all users

WeightLog

  • Body weight tracking over time
  • Weight in kg, date, optional notes

Relationships

User
├── UserProfile (1:1)
├── WorkoutSessions (1:many)
├── ExerciseEntries (1:many - custom exercises)
├── WeightLogs (1:many)
└── Routines (1:many)

WorkoutSession
└── ExerciseEntries (1:many)
    └── Sets (1:many)

GlobalExercise
└── ExerciseEntries (1:many - references)

API Routes

Authentication

  • POST /api/auth/signup - Register new user
  • POST /api/auth/signin - Login user
  • POST /api/auth/logout - Logout user

Exercises

  • GET /api/exercises - List all exercises
  • GET /api/exercises/:id - Get exercise by ID
  • POST /api/exercises - Create custom exercise (protected)
  • PUT /api/exercises/:id - Update custom exercise (protected)
  • DELETE /api/exercises/:id - Delete custom exercise (protected)

Sessions

  • GET /api/sessions - List user sessions (protected)
  • GET /api/sessions/:id - Get session details (protected)
  • POST /api/sessions - Create new session (protected)
  • PUT /api/sessions/:id - Update session (protected)
  • DELETE /api/sessions/:id - Delete session (protected)
  • GET /api/sessions/stats/calendar - Calendar stats (protected)

Weights

  • POST /api/weights - Log body weight (protected)
  • GET /api/weights/history - Get weight history (protected)

Profile

  • GET /api/profile - Get user profile (protected)
  • PUT /api/profile - Update profile (protected)
  • PUT /api/profile/username - Update username (protected)

Progress

  • GET /api/progress/heatmap - Workout activity heatmap by year / trailing 365 days
  • GET /api/progress/metrics - KPI card metrics (consistency, active days, streak, volume)
  • GET /api/progress/volume - Volume progression or weight tracking time-series

Routines

  • GET /api/routines - List routines
  • GET /api/routines/:id - Get routine details
  • POST /api/routines - Create routine
  • PUT /api/routines/:id - Update routine
  • DELETE /api/routines/:id - Delete routine

Personal Bests

  • GET /api/pbs - List PB records
  • GET /api/pbs/:exerciseId - PBs for an exercise
  • POST /api/pbs/sync - Full PB sync
  • POST /api/pbs/check-session/:sessionId - Check one session for new PBs
  • DELETE /api/pbs/:exerciseId - Delete all PBs for exercise
  • DELETE /api/pbs/:exerciseId/:metric - Delete one PB metric

See API Documentation for detailed endpoint specifications.

Authentication

The API uses JWT (JSON Web Tokens) for authentication.

Flow

  1. User registers via /api/auth/register
  2. User logs in via /api/auth/login - receives JWT token
  3. Client includes token in Authorization header for protected routes
  4. Middleware validates token and attaches user to request

Protected Routes

All routes except authentication (/api/auth/signup, /api/auth/signin, /api/auth/logout) require authentication.

Include the token in the Authorization header:

Authorization: Bearer <token>

Middleware

The authenticateToken middleware in middleware/auth.middleware.ts:

  • Validates JWT token
  • Extracts user ID from token
  • Attaches user data to request object
  • Returns 401 if token is invalid or missing

Database Migrations

Creating a Migration

npx prisma migrate dev --name migration_name

This will:

  1. Create a new migration SQL file
  2. Apply it to the database
  3. Regenerate Prisma Client

Applying Migrations

npx prisma migrate deploy

Use this in production environments.

Reset Database

npx prisma migrate reset

⚠️ This will delete all data!

Seeding

The seed script (prisma/seed.ts) populates the database using Faker:

  • Users: Creates dev (dev@asap.local) and devadmin (devadmin@asap.local) with password password123.
  • Exercises: Ensures foundational exercise library exists.
  • Workouts: ~110 realistic workout sessions across the last 365 days (Push, Pull, Legs, Full Body) with progressive overload.
  • Weight Logs: ~50 body weight logs over the year.

Run seeding manually:

yarn seed

Note: Seeding is never run automatically when the server connects or starts up. It only runs when you explicitly execute yarn seed.

Prisma Studio

Visual database browser for development:

npx prisma studio

Opens at http://localhost:5555

Building for Production

Docker Build

docker build -t asap-server .
docker run \
  --name asap-server \
  --link asap-db:db \
  -e DATABASE_URL="postgresql://postgres:postgres@db:5432/asap" \
  -e JWT_SECRET="change_this_to_a_long_random_secret" \
  -e TOKEN_EXP="7d" \
  -e FRONTEND_DOMAIN="http://localhost" \
  -e NODE_ENV="production" \
  -e PORT=3000 \
  -p 3000:3000 \
  asap-server

Manual Build

yarn build
yarn start

The built files will be in the dist/ directory.

Environment Variables

Variable Description Default
DATABASE_URL PostgreSQL connection string Required
JWT_SECRET Secret key for JWT signing super-secret-key-change-this
PORT Server port 3000
NODE_ENV Environment mode used by config/build behavior development
TOKEN_EXP JWT token expiration 7d
FRONTEND_DOMAIN Allowed CORS origin(s), comma-separated if multiple Required for browser clients

Error Handling

The API uses standard HTTP status codes:

  • 200 - Success
  • 201 - Created
  • 400 - Bad Request (validation error)
  • 401 - Unauthorized (missing/invalid token)
  • 403 - Forbidden (insufficient permissions)
  • 404 - Not Found
  • 500 - Internal Server Error

Error responses follow this format:

{
  "error": "Error message here"
}

Validation

Request validation is handled in controllers:

  • Required fields are checked
  • Data types are validated
  • Business logic constraints are enforced

Example validations:

  • Email format and uniqueness
  • Positive numbers for weight/reps
  • Valid date formats
  • User ownership of resources

Performance Considerations

Database Queries

  • Use Prisma's select to fetch only needed fields
  • Implement pagination for large result sets
  • Use include carefully to avoid N+1 queries

Example Optimized Query

const sessions = await prisma.workoutSession.findMany({
  where: { userId },
  select: {
    id: true,
    name: true,
    performedAt: true,
    _count: {
      select: { exerciseEntries: true },
    },
  },
  orderBy: { performedAt: "desc" },
  take: 20, // Pagination
});

Testing

Manual API Testing

Use tools like:

  • Postman - Import API collection
  • curl - Command-line testing
  • Thunder Client - VS Code extension

Example curl Commands

Register

curl -X POST http://localhost:3000/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"password123","username":"testuser"}'

Login

curl -X POST http://localhost:3000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"password123"}'

Get Exercises (requires token)

curl http://localhost:3000/api/exercises \
  -H "Authorization: Bearer YOUR_TOKEN_HERE"

Deployment

With Docker Compose

The server is automatically deployed with the full stack:

docker-compose up -d

Standalone Deployment

  1. Set environment variables
  2. Run migrations: yarn prisma migrate deploy
  3. Build: yarn build
  4. Start: yarn start

Database Backup

Regular backups recommended:

pg_dump -U postgres workout_db > backup.sql

Security Best Practices

  • ✅ Passwords are hashed with bcrypt
  • ✅ JWT tokens for stateless authentication
  • ✅ Environment variables for secrets
  • ✅ Input validation on all endpoints
  • ✅ CORS configured for frontend origin

License

This project is licensed under the GPLv3 License — see LICENSE for details.

Contributing

See the CONTRIBUTING for contribution guidelines.

License

MIT