Production-ready REST API for tracking daily habits and streaks. Built with a full DevOps pipeline β containerized, deployed to AWS, monitored with Prometheus + Grafana, and managed with Terraform.
π Live API: https://habittrackerapi.me
π Health Check: https://habittrackerapi.me/health
π Metrics: https://habittrackerapi.me/metrics
π Grafana: https://habittrackerapi.me/grafana/
π API Docs: docs/API.md
| Metric | Value |
|---|---|
| Response Time (cached) | 2-5ms |
| Response Time (uncached) | ~30ms |
| Cache Hit Rate | 85-99% |
| Database Query Reduction | 80% |
| Uptime | 99.9% |
| Peak Load Tested | 1,000+ req/min |
- Node.js + Express
- PostgreSQL (hosted on AWS RDS)
- Redis (caching layer)
- Docker
- Nginx (reverse proxy, rate limiting)
- AWS EC2 + RDS
- Let's Encrypt SSL
- Winston logging + CloudWatch
- Prometheus + Grafana (metrics & dashboards)
- Alertmanager (alerting)
- UptimeRobot monitoring
Authentication
- User registration and login with email/password
- Google OAuth2 social login
- JWT-based authentication (access + refresh tokens)
Habits & Tracking
- Create and manage habits (things you want to build or break)
- Check in daily to track progress
- Calculates current and longest streaks automatically
- Stats endpoint with completion rates and totals
- Prevents duplicate check-ins for the same day
Performance
- Redis caching layer with cache warming
- Cache monitoring and management endpoints
Operations
- Health check (database, cache, memory)
- Application metrics endpoint (JSON + Prometheus format)
- Prometheus scraping every 15s with custom business metrics
- Grafana dashboards for API, Redis, and system metrics
- Alertmanager with email alerts (APIDown, LowDiskSpace, HighErrorRate)
- Structured JSON logging to CloudWatch
- HTTPS with auto-renewed SSL certificates
- Rate limiting (100 req/min per IP)
curl -X POST https://habittrackerapi.me/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "SecurePass123",
"name": "Your Name"
}'curl -X POST https://habittrackerapi.me/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "SecurePass123"
}'curl https://habittrackerapi.me/habits \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"curl -X POST https://habittrackerapi.me/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refreshToken": "YOUR_REFRESH_TOKEN"}'curl -X POST https://habittrackerapi.me/auth/logout \
-H "Content-Type: application/json" \
-d '{"refreshToken": "YOUR_REFRESH_TOKEN"}'# Step 1: Get auth URL
curl https://habittrackerapi.me/auth/google
# Step 2: Open the returned authUrl in browser, login with Google
# Step 3: You'll receive user + tokens in the callback response| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
POST |
/auth/register |
Register new user | No |
POST |
/auth/login |
Login with email/password | No |
POST |
/auth/refresh |
Refresh access token | No |
POST |
/auth/logout |
Logout (revoke refresh token) | No |
POST |
/auth/logout-all |
Logout all devices | Yes |
GET |
/auth/me |
Get current user info | Yes |
GET |
/auth/google |
Initiate Google OAuth | No |
GET |
/auth/google/callback |
Google OAuth callback | No |
| Method | Route | Description | Auth Required |
|---|---|---|---|
GET |
/ |
API info and available endpoints | No |
GET |
/health |
Health check (database, cache, memory) | No |
GET |
/metrics |
Application metrics (JSON) | No |
GET |
/metrics/prometheus |
Prometheus-format metrics | No |
All habit endpoints require authentication.
| Method | Route | Description |
|---|---|---|
POST |
/habits |
Create a new habit |
GET |
/habits |
List all habits |
GET |
/habits/:id |
Get a specific habit |
PUT |
/habits/:id |
Update a habit |
DELETE |
/habits/:id |
Delete a habit (cascades to check-ins) |
POST |
/habits/:id/checkin |
Check in for today |
GET |
/habits/:id/checkins |
Get check-in history |
GET |
/habits/:id/streak |
Get current and longest streak |
GET |
/habits/:id/stats |
Get stats for one habit |
GET |
/habits/stats |
Get stats overview for all habits |
| Method | Route | Description | Auth Required |
|---|---|---|---|
GET |
/cache/stats |
Detailed cache statistics | Yes |
POST |
/cache/clear |
Clear all cache | Yes |
DELETE |
/cache/user/:userId |
Clear your own cache | Yes |
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255),
name VARCHAR(255) NOT NULL,
google_id VARCHAR(255) UNIQUE,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE refresh_tokens (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token VARCHAR(255) UNIQUE NOT NULL,
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE habits (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
description TEXT,
type VARCHAR(50) NOT NULL DEFAULT 'build',
frequency VARCHAR(50) DEFAULT 'daily',
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE check_ins (
id SERIAL PRIMARY KEY,
habit_id INTEGER NOT NULL REFERENCES habits(id) ON DELETE CASCADE,
date DATE NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(habit_id, date)
);The API implements intelligent caching for improved read performance.
Benchmarks (EC2 t3.micro):
- Cached response time: 2-5ms
- Sustained load: 3.25ms avg over 100 requests
- Cache hit rate: 97-99% under load
Cached Endpoints:
GET /habits # 5 min TTL
GET /habits/stats # 5 min TTL
GET /habits/:id/stats # 5 min TTL
GET /habits/:id/streak # 5 min TTL
GET /habits/:id/checkins # 10 min TTLCache Invalidation:
- Creating/updating/deleting habits β Clear user's cache
- Checking in β Clear habit-specific cache
- Smart pattern-based invalidation
Cache Monitoring:
# View cache statistics
curl https://habittrackerapi.me/metrics | jq '{
cache_connected,
cache_hits,
cache_misses,
cache_hit_rate
}'
# Health check includes cache status
curl https://habittrackerapi.me/healthβββ app.js # Express app setup
βββ Dockerfile
βββ docker-compose.yml
βββ routes/
β βββ auth.js # Authentication endpoints
β βββ habits.js # Habit CRUD endpoints
β βββ checkIns.js # Check-in endpoints
β βββ health.js # Health check (DB, Redis, memory)
β βββ metrics.js # JSON + Prometheus metrics
β βββ cache.js # Cache management
βββ middleware/
β βββ auth.js # JWT authentication
β βββ cache.js # Cache middleware + invalidation
βββ db/
β βββ db.js # PostgreSQL connection
β βββ redis.js # Redis connection
βββ utils/
β βββ cache.js # Cache utility
β βββ metrics.js # prom-client metric definitions
β βββ cacheWarming.js # Cache warming
β βββ cacheTTL.js # TTL configuration
β βββ cacheKeys.js # Cache key generator
β βββ logger.js # Winston logger
β βββ requestLogger.js # Request logging
β βββ streak.js # Streak calculation
β βββ tokens.js # JWT token utilities
β βββ googleOAuth.js # Google OAuth2
βββ monitoring/
β βββ docker-compose.yml # Prometheus, Grafana, Alertmanager, exporters
β βββ prometheus/
β β βββ prometheus.yml # Scrape config
β β βββ alerts.yml # Alert rules
β βββ grafana/
β β βββ provisioning/ # Auto-provisioned datasources & dashboards
β β βββ dashboards/ # Dashboard JSON files
β βββ alertmanager/
β βββ alertmanager.yml # Alert routing & email config
βββ scripts/
β βββ loadTest.js # Load testing
β βββ performanceReport.sh # Performance report
βββ docs/
βββ API.md
βββ PERFORMANCE.md # Caching benchmarks
βββ schema.sql
βββ nginx.conf
You need Node.js 18+ and a PostgreSQL database.
git clone https://github.com/oltir06/habit-tracker.git
cd habit-tracker
npm installCreate a .env file (see .env.example):
PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/habits
NODE_ENV=development
JWT_SECRET=your-jwt-secret
JWT_REFRESH_SECRET=your-refresh-secret
JWT_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d
BCRYPT_ROUNDS=10
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_CALLBACK_URL=http://localhost:3000/auth/google/callback
Run the schema from docs/schema.sql against your database, then:
npm startThe API runs at http://localhost:3000.
docker build -t habit-tracker .
docker run -p 3000:3000 --env-file .env habit-trackerRunning on an EC2 t3.micro instance with an RDS PostgreSQL database (db.t4g.micro). The app runs in a Docker container behind Nginx as a reverse proxy, with SSL from Let's Encrypt.
- Domain: habittrackerapi.me
- Nginx handles SSL termination, rate limiting, and security headers
- Logs go to CloudWatch as structured JSON
- UptimeRobot checks
/healthevery 5 minutes with email alerts on downtime - Prometheus scrapes metrics every 15s; Grafana dashboards available at
/grafana - Alertmanager sends email alerts for critical events (API down, high error rate, low disk)
Push to main
β
GitHub Actions
β
Run Tests (Jest)
β
Build Docker Image
β
Push to Docker Hub
β
Deploy to EC2
β
Health Check
β
Production Live
AWS infrastructure is fully managed with Terraform β VPC, EC2, RDS, security groups, and Elastic IP.
cd terraform
terraform init
terraform plan
terraform applyModules: vpc, ec2, rds, security
- HTTPS everywhere via Let's Encrypt
- JWT access tokens (15 min expiration) + refresh tokens (7 days, revocable)
- Bcrypt password hashing (10 rounds)
- Rate limiting at 100 requests/minute per IP
- Security headers (HSTS, X-Frame-Options, X-Content-Type-Options)
- Parameterized SQL queries (no SQL injection)
- Users can only access their own data
- Docker container runs as non-root user
MIT
Built as a portfolio project to demonstrate production-ready API development and cloud deployment skills.