14 KiB
Task Manager — Dockerized Web Application
A modern task management web application deployed using Docker containers. The application consists of 5 services running in isolated containers, communicating over virtual networks, with persistent storage for data durability.
Table of Contents
- Description
- Prerequisites
- Architecture
- Services
- Networks
- Volumes
- Container Configuration
- Quick Start
- Usage Instructions
- Viewing the Application
- Example Workflow
- Sources
- AI Usage Declaration
Description
Task Manager is a full-stack web application for creating, managing, and tracking tasks. Users can:
- Create tasks with a title and optional description
- Mark tasks as completed or reopen them
- Delete tasks they no longer need
- Filter tasks by status (All / Active / Completed)
- View statistics including total, active, and completed task counts
- Manage the database via Adminer web interface
The application uses a modern dark-themed UI served by Nginx, a Node.js/Express REST API backend, PostgreSQL for persistent data storage, and Redis for response caching.
Prerequisites
To deploy and run this application, you need:
| Software | Minimum Version | Purpose |
|---|---|---|
| Linux | Any modern distribution | Host operating system |
| Docker | 20.10+ | Container runtime |
| Docker Compose | v2.0+ (plugin) | Multi-container orchestration |
| bash | 4.0+ | Running management scripts |
Verify installation:
docker --version # Docker version 20.10+
docker compose version # Docker Compose version v2.0+
bash --version # GNU bash, version 4.0+
Architecture
┌─────────────────────────────────────────────────────────┐
│ Docker Host │
│ │
│ ┌──────────────── frontend-net ──────────────────┐ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Nginx │ │ Adminer │ │ │
│ │ │ (frontend) │ │ (DB UI) │ │ │
│ │ │ :5000→:80 │ │ :5001→:5000│ │ │
│ │ └──────┬──────┘ └──────┬──────┘ │ │
│ │ │ │ │ │
│ └─────────┼────────────────────────┼──────────────┘ │
│ │ │ │
│ ┌─────────┼────────────────────────┼──────────────┐ │
│ │ │ backend-net │ │ │
│ │ ┌──────▼──────┐ │ │ │
│ │ │ Node.js │ │ │ │
│ │ │ (api) │ │ │ │
│ │ │ :3000 │ │ │ │
│ │ └──┬──────┬───┘ │ │ │
│ │ │ │ │ │ │
│ │ ┌──▼────┐ ┌▼─────────┐ ┌──────▼──────┐ │ │
│ │ │ Redis │ │PostgreSQL │ │ (Adminer │ │ │
│ │ │ :6379 │ │ :5432 │ │ connects) │ │ │
│ │ └───────┘ └───────────┘ └─────────────┘ │ │
│ │ 📦 📦 │ │
│ │ redisdata pgdata │ │
│ └─────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
Services
1. Frontend (Nginx)
- Container name:
taskapp-frontend - Image: Custom (built from
frontend/Dockerfileusingnginx:alpine) - Port:
5000(public) →80(container) - Role: Serves the static HTML/CSS/JS frontend and acts as a reverse proxy, forwarding
/api/requests to the Node.js backend - Networks:
frontend-net,backend-net
2. API (Node.js / Express)
- Container name:
taskapp-api - Image: Custom (built from
api/Dockerfileusingnode:20-alpine) - Port:
3000(virtual, not exposed to host) - Role: REST API server providing CRUD operations for tasks. Connects to PostgreSQL for data persistence and Redis for response caching
- Networks:
backend-net
3. PostgreSQL Database
- Container name:
taskapp-postgres - Image:
postgres:16-alpine - Port:
5432(virtual, not exposed to host) - Role: Primary relational database storing all task data
- Volume:
taskapp-pgdatamounted at/var/lib/postgresql/data - Networks:
backend-net - Initialization:
db/init.sqlis automatically executed on first run to create thetaskstable
4. Redis Cache
- Container name:
taskapp-redis - Image:
redis:7-alpine - Port:
6379(virtual, not exposed to host) - Role: In-memory cache for API responses. Reduces database load by caching task list queries for 30 seconds. Configured with append-only persistence
- Volume:
taskapp-redisdatamounted at/data - Networks:
backend-net
5. Adminer (Database Web Interface)
- Container name:
taskapp-adminer - Image:
adminer:latest - Port:
5001(public) →5000(container) - Role: Web-based database management tool. Allows direct SQL queries, table browsing, and data export
- Networks:
frontend-net,backend-net
Networks
| Network Name | Driver | Connected Services | Purpose |
|---|---|---|---|
taskapp-frontend-net |
bridge | frontend, adminer | Isolates user-facing services |
taskapp-backend-net |
bridge | frontend, api, postgres, redis, adminer | Connects backend services for internal communication |
Why two networks?
- Services on
frontend-netare publicly accessible - Services on
backend-nethandle internal communication - The
frontendandadminerservices bridge both networks since they need public access while communicating with backend services
Volumes
| Volume Name | Mount Point | Service | Purpose |
|---|---|---|---|
taskapp-pgdata |
/var/lib/postgresql/data |
postgres | Persists database files across container restarts |
taskapp-redisdata |
/data |
redis | Persists Redis append-only file for cache durability |
Data persistence: Stopping and restarting the application (./stop-app.sh then ./start-app.sh) preserves all data. Only ./remove-app.sh deletes the volumes.
Container Configuration
All containers are configured with:
- Restart policy:
unless-stopped— containers automatically restart on failure or system reboot - Health checks: PostgreSQL and Redis have health checks; the API and frontend wait for healthy dependencies before starting
- Dependencies:
docker composeensures services start in the correct order:- PostgreSQL + Redis (database layer)
- API (depends on healthy postgres and redis)
- Frontend + Adminer (depends on api and postgres respectively)
- Environment variables: Database credentials and connection parameters are passed via environment variables in
docker-compose.yaml
Quick Start
# 1. Prepare the application (build images, create networks/volumes)
./prepare-app.sh
# 2. Start the application
./start-app.sh
# 3. Open in browser
# Task Manager: http://localhost:5000
# Adminer: http://localhost:5001
Usage Instructions
Preparing the application
./prepare-app.sh
This script builds the custom Docker images (frontend, api), and creates the required networks and volumes.
Starting the application
./start-app.sh
Starts all 5 containers in detached mode. Prints the URLs for accessing the application.
Stopping the application
./stop-app.sh
Stops all containers without removing data. Your tasks and database state are preserved in the persistent volumes.
Restarting after stop
./start-app.sh
Simply run the start script again. All your data will be intact.
Removing the application
./remove-app.sh
⚠️ Warning: This removes ALL traces of the application including:
- All containers
- All networks
- All persistent volumes (data is lost)
- All locally built images
Viewing the Application
Task Manager (Main Application)
- URL: http://localhost:5000
- Features: Create, complete, delete, and filter tasks
Adminer (Database Management)
- URL: http://localhost:5001
- Login credentials:
- System: PostgreSQL
- Server:
postgres - Username:
taskuser - Password:
taskpass - Database:
taskmanager
Example Workflow
# Prepare the application
$ ./prepare-app.sh
=============================================
Preparing Task Manager Application...
=============================================
[1/3] Building Docker images...
✓ Images built successfully
[2/3] Creating networks...
✓ Networks created
[3/3] Creating volumes...
✓ Volumes created
=============================================
✓ Application prepared successfully!
Run ./start-app.sh to start the application
=============================================
# Start the application
$ ./start-app.sh
=============================================
Starting Task Manager Application...
=============================================
[1/2] Starting containers...
[2/2] Waiting for services to be ready...
=============================================
✓ Application is running!
🌐 Task Manager: http://localhost:5000
🗄️ Adminer (DB): http://localhost:5001
=============================================
# Open http://localhost:5000 in a web browser and work with the application
# Create tasks, mark them complete, delete them, etc.
# Stop the application (data is preserved)
$ ./stop-app.sh
=============================================
Stopping Task Manager Application...
=============================================
✓ Application stopped.
Data is preserved in persistent volumes.
Run ./start-app.sh to restart.
# Start again - all tasks are still there!
$ ./start-app.sh
# When done, remove everything
$ ./remove-app.sh
=============================================
Removing Task Manager Application...
=============================================
✓ Application completely removed.
Sources
- Docker Documentation — https://docs.docker.com/
- Docker Compose Documentation — https://docs.docker.com/compose/
- Nginx Docker Image — https://hub.docker.com/_/nginx
- Node.js Docker Image — https://hub.docker.com/_/node
- PostgreSQL Docker Image — https://hub.docker.com/_/postgres
- Redis Docker Image — https://hub.docker.com/_/redis
- Adminer Docker Image — https://hub.docker.com/_/adminer
- Express.js Documentation — https://expressjs.com/
- node-postgres (pg) Documentation — https://node-postgres.com/
- Node Redis Client — https://github.com/redis/node-redis
Project Structure
z1/
├── docker-compose.yaml # Main orchestration configuration
├── prepare-app.sh # Build images, create networks/volumes
├── start-app.sh # Start all services
├── stop-app.sh # Stop without data loss
├── remove-app.sh # Remove all traces
├── README.md # This documentation
├── frontend/ # Nginx + Static frontend
│ ├── Dockerfile # Nginx container build
│ ├── nginx.conf # Nginx configuration
│ └── public/
│ ├── index.html # Task Manager HTML
│ ├── style.css # Styles (dark theme)
│ └── app.js # Frontend JavaScript
├── api/ # Node.js REST API
│ ├── Dockerfile # API container build
│ ├── package.json # Node.js dependencies
│ ├── server.js # Express API server
│ └── db.js # PostgreSQL connection
└── db/
└── init.sql # Database initialization