Author: Félix Vandenbroucke · 2026
Task management application built in pure Java, with no framework or external dependency. Two modes: interactive terminal and dark mode web interface with a REST API. JSON persistence with atomic writes, 217 tests, GitHub Actions CI.
- Create, edit, delete tasks with title, description, due date, status and priority
- Priorities LOW / MEDIUM / HIGH with colored pills in the UI
- Statuses TODO / DOING / DONE with list view and Kanban board (drag & drop between columns)
- Colored due dates: orange if ≤ 3 days away, red if overdue
- Filters by status, live search, global progress bar in sidebar
- CSV export in one click
- Keyboard shortcuts:
nnew task ·Ctrl+Entersave ·Escapeclose - Full console mode with interactive menus
| Layer | Technology |
|---|---|
| Backend | Java 21, com.sun.net.httpserver (JDK built-in) |
| Frontend | HTML / CSS / vanilla JS, zero framework |
| Persistence | Hand-rolled JSON with atomic writes |
| Tests | Hand-rolled framework, zero external dependency |
| CI | GitHub Actions |
taskmanager/
├── src/
│ ├── Main.java entry point - console and web modes
│ ├── Task.java data model, JSON serialization, CSV export
│ ├── TaskManager.java CRUD, persistence, statistics
│ ├── ConsoleUI.java terminal interface
│ └── ApiServer.java multi-threaded REST HTTP server
├── tests/
│ ├── TaskManagerTest.java 129 assertions - business logic
│ └── ApiServerTest.java 88 assertions - HTTP integration
├── web/
│ ├── index.html HTML structure
│ ├── style.css styles (dark mode, kanban, animations)
│ └── app.js frontend logic (API calls, render, drag & drop)
├── .github/workflows/ci.yml GitHub Actions CI pipeline
├── Dockerfile multi-stage container build
├── Makefile task automation (build, test, run)
├── data/ folder mapped for persistence
│ └── tasks.json auto-saved data
└── README.md
Java 17 or higher (uses switch expressions).
java -version
javac -version# Build
make build
# Console mode
make run
# Web mode → http://localhost:8080
make web
# Custom port
make web PORT=3000Without Make:
mkdir -p out
javac -d out src/Task.java src/TaskManager.java src/ConsoleUI.java src/ApiServer.java src/Main.java
java -cp out taskmanager.Main --webdocker build -t taskmanager .
# Run the container and map the data directory so your tasks are saved permanently
# On Mac/Linux:
docker run -p 8080:8080 -v "$(pwd)/data:/app/data" taskmanager
# On Windows (PowerShell):
docker run -p 8080:8080 -v "${PWD}/data:/app/data" taskmanagermake jar
java -jar TaskManager.jar --web| Method | Endpoint | Description |
|---|---|---|
GET |
/api/tasks |
List all tasks |
GET |
/api/tasks?status=TODO |
Filter by status (TODO/DOING/DONE) |
POST |
/api/tasks |
Create a task |
PUT |
/api/tasks/{id} |
Update a task (partial fields supported) |
DELETE |
/api/tasks/{id} |
Delete a task |
GET |
/api/stats |
Stats by status |
GET |
/api/export |
Export all tasks as CSV |
GET |
/ |
Serves the frontend |
JSON body for POST / PUT:
{
"title": "Task name",
"description": "Optional details",
"dueDate": "2026-06-15",
"status": "TODO",
"priority": "HIGH"
}- Multi-threaded HTTP server:
FixedThreadPoolwith daemon threads handles REST requests in parallel without blocking the JVM, enabling clean server shutdown and reliable test teardown. - Atomic persistence: write-to-temp strategy - data is written to a
.tmpfile thenATOMIC_MOVEd to the final file, preventing any corruption on crash. - Lightweight Docker image: multi-stage build using
eclipse-temurin:21-jdk-alpineto compile, theneclipse-temurin:21-jre-alpinefor the final image - only the JRE and the JAR ship. - CI with timeouts: GitHub Actions pipeline with 5-minute timeouts per step and separate unit/integration test jobs.
217 assertions, zero external dependency.
# Run all
make test
# Unit tests only (Task, TaskManager)
make test-unit
# Integration tests only (HTTP, REST API)
make test-apiWithout Make:
javac -cp out -d out tests/TaskManagerTest.java tests/ApiServerTest.java
java -cp out taskmanager.TaskManagerTest
java -cp out taskmanager.ApiServerTestIntegration tests spin up a real HTTP server on a random free port and fire real HTTP requests - no mocks. Returns exit code 0 if all pass, 1 otherwise (CI-compatible).
Updated automatically after every add, edit or delete. Atomic write: data goes to a .tmp file first, then moves to the final file - no data loss on crash.
[
{"id":1,"title":"Set up the environment","description":"Install JDK 21","dueDate":"2025-02-28","status":"DONE","priority":"HIGH"},
{"id":2,"title":"Write unit tests","description":"Cover Task and TaskManager","dueDate":"2025-03-10","status":"DOING","priority":"MEDIUM"},
{"id":3,"title":"Write documentation","description":"README and Javadoc","dueDate":"2025-03-15","status":"TODO","priority":"LOW"}
]Fields: id, title, description, dueDate (ISO format: YYYY-MM-DD), status, priority.
Files without a priority field load with MEDIUM as default (backward compatible).
