Skip to content

Repository files navigation

ASI Training Platform

A comprehensive web-based application for delivering defensive driving training courses with automated scoring and certification tracking.

Overview

This application enables users to:

  • Browse available defensive driving courses
  • Take interactive quizzes with 10 questions per course
  • Receive automatic scoring and pass/fail determination (85% threshold)
  • Track course completions and certificates

Architecture

Browser → Frontend (Vue.js/Quasar) → Backend API (Node.js/Express) → PostgreSQL
                                              ↓
                                       Automatic Scoring
                                              ↓
                                    Certificate Tracking

Tech Stack

  • Frontend: Vue.js 3 + Quasar Framework
  • Backend: Node.js + Express
  • Database: PostgreSQL 15
  • Infrastructure: Docker + Terraform
  • Container Runtime: Docker
  • IaC: Terraform with Docker provider
  • Monitoring: Grafana + Prometheus + Loki
  • Logging: Winston with structured JSON logs
  • Metrics: Prometheus client with custom business metrics

Prerequisites

  • Docker 20.10+ (Install Docker)
  • Terraform 1.0+ (Install Terraform)
  • Node.js 18+ and npm (for generating package-lock.json files during initial setup)
  • Git (for cloning the repository)

Note: Node.js/npm is required initially to generate package-lock.json files needed for Docker builds. After setup, all services run in containers.


Installation Instructions

Installing Node.js and npm on Ubuntu

# Method 1: Using NodeSource repository (Recommended for latest LTS)
# Install Node.js 18.x
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

# Verify installation
node --version
npm --version

# Method 2: Using Ubuntu's default repository (may be older version)
sudo apt-get update
sudo apt-get install -y nodejs npm

Installing Docker on Ubuntu

# 1. Update package index
sudo apt-get update

# 2. Install prerequisites
sudo apt-get install -y \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# 3. Add Docker's official GPG key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 4. Set up the repository
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 5. Install Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 6. Add your user to the docker group (to run docker without sudo)
sudo usermod -aG docker $USER

# 7. Log out and back in, or run:
newgrp docker

# 8. Verify installation
docker --version
docker run hello-world

Installing Terraform on Ubuntu

Method 1: Using HashiCorp's Official Repository (Recommended)

# 1. Install prerequisites
sudo apt-get update
sudo apt-get install -y gnupg software-properties-common

# 2. Add HashiCorp GPG key
wget -O- https://apt.releases.hashicorp.com/gpg | \
    gpg --dearmor | \
    sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg

# 3. Verify the key fingerprint
gpg --no-default-keyring \
    --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \
    --fingerprint

# 4. Add the official HashiCorp repository
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
    https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
    sudo tee /etc/apt/sources.list.d/hashicorp.list

# 5. Update and install Terraform
sudo apt-get update
sudo apt-get install -y terraform

# 6. Verify installation
terraform --version

Method 2: Manual Binary Installation (Alternative)

# 1. Download Terraform (check https://www.terraform.io/downloads for latest version)
TERRAFORM_VERSION="1.6.6"
wget https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip

# 2. Install unzip if not already installed
sudo apt-get install -y unzip

# 3. Unzip the binary
unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip

# 4. Move to a directory in your PATH
sudo mv terraform /usr/local/bin/

# 5. Verify installation
terraform --version

# 6. Clean up
rm terraform_${TERRAFORM_VERSION}_linux_amd64.zip

Verify All Prerequisites

# Check Node.js
node --version
# Expected: v18.x.x or higher

# Check npm
npm --version
# Expected: 9.x.x or higher

# Check Docker
docker --version
# Expected: Docker version 20.10.x or higher

# Check Docker Compose
docker compose version
# Expected: Docker Compose version 2.x.x

# Check Terraform
terraform --version
# Expected: Terraform v1.x.x or higher

# Check Git
git --version
# Expected: git version 2.x.x

Quick Start Guide

Option 1: Using Terraform (Recommended)

Terraform manages the entire infrastructure including network, database, backend, and frontend containers.

IMPORTANT: Before running Terraform, you must generate package-lock.json files for dependency management.

# 1. Generate package-lock.json files (required for Docker builds)
cd backend
npm install
cd ../frontend
npm install
cd ..

# 2. Navigate to terraform directory
cd terraform

# 3. Initialize Terraform
terraform init

# 4. Review the plan (optional)
terraform plan

# 5. Apply the configuration
terraform apply

# Type 'yes' when prompted

What this does:

  • Creates a Docker network (asi-network)
  • Launches PostgreSQL container with persistent volume
  • Builds and launches backend API container
  • Builds and launches frontend container
  • Deploys monitoring stack:
    • Grafana dashboard (port 3001)
    • Prometheus metrics collection (port 9090)
    • Loki log aggregation (port 3100)
  • Automatically initializes database schema
  • Seeds 5 courses with 10 questions each
  • Configures Winston logging with Loki integration
  • Sets up Prometheus metrics scraping

Wait time: Initial build takes 2-5 minutes depending on your machine.

Option 2: Using Docker Compose (Alternative)

IMPORTANT: Before running Docker Compose, you must generate package-lock.json files for dependency management.

# 1. Generate package-lock.json files (required for Docker builds)
cd backend && npm install && cd ..
cd frontend && npm install && cd ..

# 2. From project root, start containers
docker-compose up --build -d

# 3. Check logs
docker-compose logs -f

Accessing the Application

Once containers are running:

Production Domains:

Local Development (via localhost):

Note: For local development, use localhost URLs. The application is configured to use production domains (asi.com, api.asi.com) but you'll need to set up DNS/hosts entries or use a reverse proxy for those domains to work locally.

Setting Up Local Domain Names (Optional)

To use the production domain names (asi.com, api.asi.com) on your local machine:

Option 1: Edit /etc/hosts (Linux/Mac)

sudo nano /etc/hosts

# Add these lines:
127.0.0.1 asi.com
127.0.0.1 api.asi.com

Option 2: Use localhost URLs Just use http://localhost:8080 for frontend and http://localhost:3000 for backend API. The application will work fine with localhost.


Monitoring and Observability

The application includes a comprehensive monitoring stack deployed via Terraform:

Monitoring Endpoints:

Key Features:

  • Grafana - Pre-configured dashboards for application metrics and logs
  • Prometheus - Metrics collection (15s scrape interval)
    • HTTP request duration and rates
    • Authentication attempts (login/register success/failure)
    • Database pool connections
    • Error rates and types
  • Loki - Log aggregation with correlation ID tracking
    • Winston structured logging
    • Automatic log shipping from backend
    • 30-day retention
  • Health Checks - Liveness and readiness probes

Quick Start:

# Access Grafana
open http://localhost:3001

# View pre-configured dashboard
# Navigate to: Home → ASI Backend Overview

# Query logs in Grafana
# Click: Explore → Select "Loki" datasource

# Check Prometheus targets
curl http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | {job: .labels.job, health: .health}'

# View backend health
curl http://localhost:3000/health/ready | jq .

Available Metrics:

  • asi_http_request_duration_seconds - API response times
  • asi_http_request_total - Request counts by endpoint
  • asi_auth_attempts_total - Authentication success/failure rates
  • asi_db_pool_connections - Database connection pool status
  • asi_errors_total - Error counts by type and endpoint

Log Queries (LogQL):

# All backend logs
{service="asi-training-backend"}

# Only errors
{service="asi-training-backend"} |= "error"

# Track request by correlation ID
{service="asi-training-backend"} |= "550e8400-e29b-41d4-a716-446655440000"

For detailed monitoring documentation, see monitoring/README.md.

For production deployment considerations, alerting configuration, and integration with CloudWatch/ELK, see docs/MONITORING.md.


Using the Application

Step 1: View Available Courses

  1. Open http://localhost:8080 (or https://asi.com if configured) in your browser
  2. You'll see 5 defensive driving courses:
    • Defensive Driving Basics
    • Weather Conditions and Driving
    • Traffic Laws and Regulations
    • Distracted Driving Prevention
    • Impaired Driving Awareness

Step 2: Start a Course

  1. Click "View Course" on any course
  2. Read the course description and content
  3. Enter a User ID (use 1 for testing)
  4. Click "Start Course"

Step 3: Take the Quiz

  1. Answer all 10 multiple-choice questions
  2. Use "Next" and "Previous" to navigate
  3. Your answers are auto-saved as you go
  4. Click "Complete Course" when finished

Step 4: View Results

  1. See your score (percentage)
  2. Pass/Fail status (85% required to pass)
  3. Certificate number (if passed)
  4. Return to browse more courses

Development Workflow

The application is configured for local development with hot-reload enabled for both backend and frontend.

Hot Reload Configuration

Backend (Node.js/Express):

  • Uses nodemon to automatically restart the server when code changes
  • Watches backend/src/ directory
  • Changes to .js files trigger automatic restart
  • Server typically restarts in 1-2 seconds

Frontend (Vue.js/Quasar):

  • Uses Quasar CLI dev server with Vite
  • Watches frontend/src/ directory
  • Changes automatically reload in browser (HMR - Hot Module Replacement)
  • Nearly instant updates without full page reload

Making Code Changes

  1. Edit backend code:

    # Edit any file in backend/src/
    vim backend/src/controllers/coursesController.js
    
    # Changes are automatically detected
    # Server restarts within 1-2 seconds
    # Check logs: docker-compose logs -f backend
  2. Edit frontend code:

    # Edit any file in frontend/src/
    vim frontend/src/pages/CoursesPage.vue
    
    # Changes automatically appear in browser
    # No manual refresh needed (HMR)
    # Check logs: docker-compose logs -f frontend
  3. Edit configuration files:

    • Changes to quasar.config.js or index.html require container restart
    • Run: docker-compose restart frontend

Volume Mounts

The following directories are mounted from your host to containers:

Backend:

  • ./backend/src/app/src (source code)
  • backend_node_modules volume (prevents host overwrite)

Frontend:

  • ./frontend/src/app/src (source code)
  • ./frontend/index.html/app/index.html
  • ./frontend/quasar.config.js/app/quasar.config.js
  • frontend_node_modules volume (prevents host overwrite)

Viewing Logs

# All containers
docker-compose logs -f

# Specific service
docker-compose logs -f backend
docker-compose logs -f frontend

# Last 50 lines
docker-compose logs --tail=50 backend

Restarting Services

# Restart all services
docker-compose restart

# Restart specific service
docker-compose restart backend
docker-compose restart frontend

# Rebuild after package.json changes
docker-compose up --build -d

Sample Data

The application includes pre-seeded sample data:

Courses (5 total)

Each course includes:

  • Title and description
  • Reading content (200-300 words)
  • 10 quiz questions
  • Multiple choice answers (4 options each)
  • Passing score: 85%

Users

For testing, use user_id: 1 (no authentication required in current implementation)


Stopping the Application

If using Terraform:

cd terraform
terraform destroy
# Type 'yes' when prompted

If using Docker Compose:

docker-compose down

# To also remove volumes:
docker-compose down -v

Troubleshooting

Containers won't start

# Check Docker is running
docker ps

# Check container logs
docker logs asi-backend
docker logs asi-database
docker logs asi-frontend

Database connection errors

# Wait 10 seconds after starting - database needs time to initialize
# Check database is healthy
docker exec asi-database pg_isready -U asi_user

# Restart backend
docker restart asi-backend

Port conflicts

If ports 3000, 5432, or 8080 are in use:

# Stop conflicting services or modify ports in terraform/variables.tf

Terraform errors

# Clean terraform state
cd terraform
rm -rf .terraform terraform.tfstate*
terraform init
terraform apply

Development Workflow

Backend Development (without containers)

cd backend

# Install dependencies
npm install

# Create .env file
cp .env.example .env
# Edit .env with local database URL

# Run database (via docker)
docker run -d -p 5432:5432 \
  -e POSTGRES_DB=asi_training \
  -e POSTGRES_USER=asi_user \
  -e POSTGRES_PASSWORD=${POSTGRES_PASSWORD} \
  postgres:15-alpine

# Start dev server with hot reload
npm run dev

# Backend runs on http://localhost:3000

Frontend Development (without containers)

cd frontend

# Install dependencies
npm install

# Start dev server
npm run dev

# Frontend runs on http://localhost:8080

Project Structure

asi/
├── backend/                    # Node.js/Express API
│   ├── src/
│   │   ├── app.js             # Express application setup
│   │   ├── server.js          # Server startup
│   │   ├── config/
│   │   │   ├── database.js    # PostgreSQL connection pool
│   │   │   └── init-db.js     # Schema creation & seeding
│   │   ├── routes/
│   │   │   ├── health.js      # Health check endpoints
│   │   │   └── courses.js     # Course/quiz routes
│   │   ├── controllers/
│   │   │   └── coursesController.js
│   │   └── middleware/
│   │       └── errorHandler.js
│   ├── Dockerfile
│   ├── .dockerignore
│   ├── package.json
│   └── .env.example
│
├── frontend/                   # Vue.js/Quasar SPA
│   ├── src/
│   │   ├── App.vue
│   │   ├── main.js
│   │   ├── app.css
│   │   ├── layouts/
│   │   │   └── MainLayout.vue
│   │   ├── pages/
│   │   │   ├── CoursesPage.vue
│   │   │   ├── CourseDetailPage.vue
│   │   │   ├── QuizPage.vue
│   │   │   └── ResultsPage.vue
│   │   ├── router/
│   │   │   └── index.js
│   │   └── services/
│   │       └── api.js
│   ├── public/
│   │   └── index.html
│   ├── Dockerfile
│   ├── nginx.conf
│   ├── quasar.config.js
│   └── package.json
│
├── terraform/                  # Infrastructure as Code
│   ├── main.tf                # Provider configuration
│   ├── variables.tf           # Input variables
│   ├── outputs.tf             # Output values
│   ├── network.tf             # Docker network
│   ├── database.tf            # PostgreSQL container
│   ├── backend.tf             # Backend API container
│   ├── frontend.tf            # Frontend Nginx container
│   └── monitoring.tf          # Monitoring stack (Grafana, Prometheus, Loki)
│
├── monitoring/                 # Monitoring Configuration
│   ├── README.md              # Monitoring documentation
│   ├── loki-config.yaml       # Loki server configuration
│   ├── prometheus.yml         # Prometheus scrape targets
│   └── grafana/
│       └── provisioning/
│           ├── datasources/   # Auto-provisioned datasources
│           └── dashboards/    # Pre-configured dashboards
│
├── docs/                      # Documentation
│   ├── asi.md                # Interview context
│   ├── proposal.md           # Product proposal
│   ├── product.md            # Product specifications
│   ├── PUNCHLIST.md          # Implementation checklist
│   └── MONITORING.md         # Production monitoring guide
│
├── docker-compose.yml         # Alternative to Terraform
├── .gitignore
├── Claude.md                  # AI assistant guidelines
└── README.md

API Endpoints

Health Checks

  • GET /health - Liveness probe (returns 200 OK)
  • GET /ready - Readiness probe (checks database connection)

Courses (Implemented ✓)

  • GET /api/courses - List all courses
  • GET /api/courses/:id - Get course details with question count

Enrollments (Implemented ✓)

  • POST /api/courses/:id/start - Create enrollment and get questions
    • Body: { "user_id": 1 }
    • Returns: enrollment details + full quiz questions with answers
  • POST /api/enrollments/:id/answer - Submit answer for a question
    • Body: { "question_id": 5, "answer_id": 21 }
  • POST /api/enrollments/:id/complete - Calculate score and determine pass/fail
    • Returns: score, status (completed/failed), certificate info
  • GET /api/enrollments/:id - Get enrollment details

Authentication (NOT Implemented)

The following endpoints are planned but not yet implemented:

  • POST /auth/register - User registration
  • POST /auth/login - User login
  • POST /auth/refresh - Refresh access token

Certificates (Partially Implemented)

  • Certificate records are created on course completion
  • PDF generation and email functionality are NOT implemented

Implementation Status

✓ Implemented Features

Core Functionality:

  • ✓ Course browsing and listing
  • ✓ Course detail viewing with reading content
  • ✓ Quiz enrollment system
  • ✓ 10-question quizzes per course
  • ✓ Answer submission and tracking
  • ✓ Automatic scoring (correct/total × 100)
  • ✓ Pass/fail determination (85% threshold)
  • ✓ Certificate record generation
  • ✓ Results display

Database:

  • ✓ Complete schema (7 tables)
  • ✓ Sample data seeding (5 courses, 50 questions)
  • ✓ Foreign key relationships
  • ✓ Connection pooling
  • ✓ Health checks

Infrastructure:

  • ✓ Terraform configuration for local Docker
  • ✓ Docker network isolation
  • ✓ Multi-container orchestration
  • ✓ Persistent database volumes
  • ✓ Health checks on all containers
  • ✓ Auto-restart policies

Monitoring and Observability:

  • ✓ Grafana dashboards with pre-configured visualizations
  • ✓ Prometheus metrics collection (15s intervals)
  • ✓ Loki log aggregation with 30-day retention
  • ✓ Winston structured JSON logging
  • ✓ Request correlation IDs for distributed tracing
  • ✓ Custom business metrics (auth, enrollments, quiz scores)
  • ✓ HTTP request metrics (duration, rate, errors)
  • ✓ Database connection pool monitoring
  • ✓ Health check endpoints (liveness and readiness)
  • ✓ Error tracking and classification

Frontend:

  • ✓ Vue.js 3 + Quasar UI components
  • ✓ Responsive design
  • ✓ Multiple page components
  • ✓ API integration
  • ✓ Loading states and error handling
  • ✓ Progress tracking in quiz
  • ✓ Navigation and routing

✗ Not Implemented (Future Phases)

Authentication:

  • ✗ User registration
  • ✗ Login/logout
  • ✗ JWT token generation and validation
  • ✗ Refresh token flow
  • ✗ Protected routes

Certificates:

  • ✗ PDF generation (PDFKit integration)
  • ✗ PDF download endpoint
  • ✗ PDF storage (S3 or local)

Email:

  • ✗ Email functionality
  • ✗ SES integration (AWS)
  • ✗ Mailhog integration (local)
  • ✗ Certificate email delivery

User Management:

  • ✗ User profile pages
  • ✗ User dashboard
  • ✗ Enrollment history

Admin Features:

  • ✗ Admin interface
  • ✗ Course content management
  • ✗ User management
  • ✗ Reporting and analytics

Testing:

  • ✗ Unit tests
  • ✗ Integration tests
  • ✗ E2E tests with Cypress

Production Features:

  • ✗ AWS deployment (ECS, RDS, ALB, S3)
  • ✗ CI/CD pipeline with GitHub Actions
  • ✗ Secrets management (AWS Secrets Manager)
  • ✗ HTTPS/SSL certificates
  • ✗ CloudWatch integration (logs and metrics)
  • ✗ Alerting with PagerDuty/Opsgenie

Database Schema

The application uses 7 tables:

  1. users - User accounts (basic structure, no auth yet)
  2. courses - Course definitions
  3. questions - Quiz questions (10 per course)
  4. answers - Answer choices (4 per question, 1 correct)
  5. enrollments - User course enrollments
  6. user_answers - Individual answer submissions
  7. certificates - Certificate records (no PDF yet)

Database is automatically initialized and seeded on first backend startup.


Testing the Application

Manual Testing Flow

  1. Start the application (via Terraform or Docker Compose)
  2. Wait 30 seconds for database initialization
  3. Open frontend: http://localhost:8080
  4. Select a course from the list
  5. Enter user ID: 1 (or any number)
  6. Start the course and read the content
  7. Take the quiz - answer all 10 questions
  8. Complete the course to see your score
  9. Check results - you need 85% (9/10 or 10/10) to pass

API Testing

Using localhost:

# Health check
curl http://localhost:3000/health

# Get all courses
curl http://localhost:3000/api/courses

# Get course details
curl http://localhost:3000/api/courses/1

# Start a course (creates enrollment)
curl -X POST http://localhost:3000/api/courses/1/start \
  -H "Content-Type: application/json" \
  -d '{"user_id": 1}'

Using production domains (if configured in /etc/hosts):

# Health check
curl https://api.asi.com/health

# Get all courses
curl https://api.asi.com/api/courses

# Get course details
curl https://api.asi.com/api/courses/1

Known Limitations

  1. No authentication - User ID is manually entered (simulated auth)
  2. No PDF certificates - Certificate records created but no PDF files
  3. No email - Email functionality not implemented
  4. Single test user - Use user_id: 1 for all testing
  5. No user persistence - Users not stored (enrollments work with any ID)
  6. No edit/delete - Cannot modify or delete enrollments once created
  7. Local only - Terraform configured for Docker provider, not AWS

Future Enhancements

See docs/proposal.md and docs/product.md for complete product specifications including:

  • Full authentication system with JWT
  • PDF certificate generation and storage
  • Email delivery via SES/Mailhog
  • User registration and profile management
  • Admin interface for content management
  • AWS production deployment
  • CI/CD pipeline with GitHub Actions
  • Comprehensive test coverage
  • Monitoring and observability

Contributing

This is a demonstration project for the ASI Head of Engineering interview. For questions or feedback, please contact the repository owner.


License

Proprietary - American Safety Institute


Additional Resources

About

An full-stack application with front-end, back-end, api, and monitoring built in

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages