You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A production-ready, full-stack Student Management web application built with React, FastAPI, and PostgreSQL, fully containerized with Docker Compose, monitored via Prometheus + Grafana, tested with pytest, Jest, and Selenium, and deployed through a GitHub Actions CI/CD pipeline using a self-hosted runner.
JWT tokens are signed with HS256 and include the username as subject
Token is stored in localStorage on the frontend
The Axios interceptor auto-attaches the token to every request
Frontend Pages
Page
Route
Auth Required
Description
Login/Register
/login
No
Toggle between login and registration
Student List
/students
Yes
Table showing all students
Add Student
/add-student
Yes
Form to create a new student record
Unauthenticated users are redirected to /login via PrivateRoute
After login, users are redirected to /students
The Navbar shows navigation links and a Logout button
Database Schema
users Table
Column
Type
Constraints
id
Integer
Primary Key, Auto-increment
username
String(150)
Unique, Not Null
hashed_password
String(255)
Not Null
students Table
Column
Type
Constraints
id
Integer
Primary Key, Auto-increment
name
String(150)
Not Null
age
Integer
Not Null
email
String(255)
Unique, Not Null
Docker Services
Service
Image
Container Name
Port Mapping
Depends On
postgres
postgres:16-alpine
studentapp-db
5432:5432
—
backend
./backend (Dockerfile)
studentapp-api
8000:8000
postgres (healthy)
frontend
./frontend (Dockerfile)
studentapp-ui
3000:80
backend
prometheus
prom/prometheus:v2.53.0
studentapp-prometheus
9090:9090
backend
grafana
grafana/grafana:11.1.0
studentapp-grafana
3001:3000
prometheus
pgadmin
dpage/pgadmin4:latest
studentapp-pgadmin
5051:80
postgres (healthy)
Volumes
Volume
Purpose
pgdata
PostgreSQL data persistence
promdata
Prometheus time-series data
grafdata
Grafana config and dashboards
pgadmindata
pgAdmin configuration
Docker Commands
# Start all services
docker-compose up --build
# Start in detached mode
docker-compose up -d --build
# View logs
docker-compose logs -f
# View specific service logs
docker-compose logs -f backend
# Stop all services
docker-compose down
# Stop and remove volumes
docker-compose down -v
# Rebuild a single service
docker-compose up --build backend
# Check service status
docker-compose ps
# Clean up dangling images
docker image prune -f
Running Tests
Backend Unit Tests (pytest)
9 tests covering authentication and student CRUD operations.
Add success, duplicate email, unauthorized access, list students, list unauthorized
Tests use an in-memory SQLite database (no Docker needed).
Frontend Unit Tests (Jest)
10 tests across 4 test suites covering UI rendering, form submission, and error handling.
# Run via Docker
docker run --rm -w /app -v "${PWD}/frontend:/app" node:18-alpine \
sh -c "npm install --legacy-peer-deps && npx react-scripts test --watchAll=false --verbose"# Run locallycd frontend
npm install --legacy-peer-deps
npm test
Test File
Tests
Description
App.test.js
1
Renders login page when not authenticated
LoginPage.test.js
3
Renders form, shows error on failure, toggles login/register
AddStudentPage.test.js
3
Renders form, submits successfully, shows error on failure
StudentListPage.test.js
3
Renders heading, shows students in table, empty message
End-to-End Tests (Selenium)
6 tests covering the complete user workflow through a real browser.
Prerequisite: The application must be running (docker-compose up)
# Run with visible browsercd selenium
pip install selenium pytest
python -m pytest test_e2e.py -v
# Run headless (CI mode) — set in conftest.py# opts.add_argument("--headless")
Test
Description
test_register_new_user
Registers a new user, redirects to /students
test_logout
Clicks Logout, redirects to /login
test_login_existing_user
Logs in with registered user
test_login_invalid_credentials
Shows error message for bad credentials
test_add_student
Fills form, submits, sees success message
test_student_list_shows_added_student
Verifies the added student appears in the table
Monitoring & Observability
Prometheus Metrics
The backend auto-instruments every HTTP request via custom middleware.
Metric
Type
Labels
Description
http_requests_total
Counter
method, endpoint, http_status
Total HTTP requests
http_request_duration_seconds
Histogram
method, endpoint
Request latency distribution
auth_login_total
Counter
status (success/failure)
Login attempts
student_created_total
Counter
—
Students created
student_total_count
Gauge
—
Current student count
Scrape config: Prometheus scrapes backend:8000/metrics every 15 seconds.
Grafana Dashboard
Auto-provisioned on startup with 25+ panels across 5 rows:
Row
Panels
System Health
CPU Usage gauge, Memory Usage gauge, Disk Usage gauge, CPU/Memory time-series
API Performance
Request Rate (RPS), Latency p50/p95/p99, Error Rate %, Endpoint bar chart, Status Code pie chart
⚠ Security Note: Change all default passwords before deploying to production.
Troubleshooting
Build & Runtime Issues
Problem
Solution
Frontend build fails with ajv error
Ensure ajv@^8.12.0 is in package.json dependencies
Frontend build fails with Node 20
Use node:18-alpine in frontend/Dockerfile
422 error shows [object Object]
Error handling extracts .msg from array-format FastAPI errors
docker-compose up version warning
Remove version: "3.9" from docker-compose.yml (deprecated)
Port 5050 conflict for pgAdmin
pgAdmin is mapped to 5051 instead
Backend tests need database
Tests use in-memory SQLite — no database required
Selenium tests fail without app
Start the app first: docker-compose up -d
Jest Cannot find module @testing-library/dom
Add @testing-library/dom@^10.4.0 to devDependencies
Jest Cannot use import statement (axios)
Add transformIgnorePatterns: ["node_modules/(?!axios)/"] to Jest config in package.json
CI/CD Pipeline Issues (Windows / PowerShell)
Problem
Solution
NativeCommandError on docker build / docker-compose up
Docker writes progress to stderr. PowerShell treats stderr as error. Fix: set $ErrorActionPreference = 'SilentlyContinue' before the command and check $LASTEXITCODE manually. See ci.yml for examples
grep not found on Windows runner
Windows has no grep. Replace with Select-String, e.g. docker images | Select-String "student-app"
$GITHUB_WORKSPACE empty on Windows
Use ${{ github.workspace }} in workflow YAML — it's a GitHub expression resolved before the shell runs, not a shell variable
pytest-asyncio deprecation warning in Selenium tests
Add asyncio_default_fixture_loop_scope = function to selenium/pytest.ini. This is caused by pytest-asyncio being installed system-wide from backend dependencies
Selenium / E2E Issues
Problem
Solution
Chrome not visible during E2E tests
The runner must run interactively (via run.cmd), not as a Windows service. Services run in Session 0 with no desktop. Stop the service → start run.cmd manually
How to switch runner to interactive mode
Stop-Service "actions.runner.<name>" (elevated) → cd <runner-dir> → .\run.cmd
How to switch back to service mode
Close the run.cmd terminal → Start-Service "actions.runner.<name>" (elevated)
E2E tests fail — app not running
The e2e.yml workflow builds and starts services automatically. If running locally: docker-compose up -d first, then pytest selenium/ -v
Git dubious ownership — detected dubious ownership in repository
Run git config --system --add safe.directory '*' in an elevated terminal. Also create C:\ProgramData\Git\config with [safe]\n\tdirectory = *
Runner shows offline on GitHub
Check if the runner service is running: Get-Service actions.runner.*. Start with: Start-Service <service-name> or manually with run.cmd
Runner registered to wrong repo
Check .runner file: Get-Content <runner-dir>\.runner -Raw. Re-register with config.cmd remove then config.cmd --url <repo-url> --token <token>
Multiple repos need a runner
Option 1: Register runner at org level. Option 2: Create separate runner folders per repo
No Python 3.12 found + registry error
Self-hosted runners can't install Python via actions/setup-python. Remove the action and use system-installed Python (python --version to verify)
Docker Access is denied in runner
Add the runner's service account to the docker-users group (elevated): net localgroup docker-users "NT AUTHORITY\SERVICE" /add. Then restart the runner service
Docker build fails in CI
Ensure Docker Desktop is running, the runner service account is in docker-users, and restart the service after group change
error during connect: ... docker client must be run with elevated privileges
Runner service user lacks Docker access. Fix: add Users to docker-users group → restart runner service
Useful Diagnostic Commands
# Check runner service statusGet-Service actions.runner.*# Check which repo a runner is registered toGet-Content<runner-dir>\.runner -Raw
# Check docker-users group membership
net localgroup docker-users
# Check system Git safe directory config
git config --system --list |Select-String"safe"# Verify Docker access
docker ps
# Check runner process ownerGet-Process Runner.Listener -ErrorAction SilentlyContinue
# Start runner service (elevated)Start-Service"actions.runner.christopher-pb-StudentAppRepo.YY282381"# Stop runner service and switch to interactive mode (visible browser)Stop-Service"actions.runner.christopher-pb-StudentAppRepo.YY282381"
cd D:\KJC\action-runner-2\actions-runner-win-x64-2.332.0
.\run.cmd# View runner logsGet-ChildItem<runner-dir>\_diag\*.log |Sort-Object LastWriteTime -Descending |Select-Object-First 5# Check if app is healthyInvoke-WebRequest-Uri http://localhost:8000/api/health -UseBasicParsing
Invoke-WebRequest-Uri http://localhost:3000-UseBasicParsing
# View Docker Compose service status
docker-compose ps
docker-compose logs --tail=20 backend