
I have professional experience with Java Spring Boot in enterprise environments, but I wanted to challenge myself to build something completely from the ground up β no existing codebase to reference, no senior dev to ask. Just me, the docs, and a blank IntelliJ window. π
This is a production-ready Task Manager REST API that covers the complete lifecycle of a backend service. Built, tested, secured, containerized, deployed, and monitored. The kind of thing you'd see in enterprise environments, just without the 47 approval tickets to deploy it. π
π Live API: https://lm-task-manager-api.up.railway.app
π Swagger UI: https://lm-task-manager-api.up.railway.app/swagger-ui/index.html
β€οΈ Health Check: https://lm-task-manager-api.up.railway.app/actuator/health
π Technical Document: https://docs.google.com/document/d/1GVApxweT1_Df0EEk2T8ut4kvhGUatpz-WFF-VNHtlmQ/edit?usp=sharing
| Category | Technology |
|---|---|
| Language & Framework | Java 21, Spring Boot 3.5.13 |
| Database | MongoDB Atlas (cloud-hosted NoSQL) |
| Caching | Redis (Railway-hosted, in-memory) |
| Build Tool | Gradle |
| Containerization | Docker (multi-stage build) |
| Deployment | Railway (cloud platform) |
| CI/CD | GitHub Actions |
| Code Quality | SonarCloud (All A grades β yes, really) |
| API Docs | Swagger UI / OpenAPI 3.0 |
| Testing | JUnit 5, Mockito, Spring Boot Test |
| Logging | SLF4J with Logback |
| Monitoring | Spring Boot Actuator, Railway Observability |
The API follows a clean layered architecture β the same pattern used in enterprise Java development, except this time I actually understand every layer because I built it myself. π
HTTP Request β Controller β Service β Repository β MongoDB Atlas
β
Redis Cache
- Controller: Handles incoming HTTP requests and response formatting
- Service: Contains business logic and cache management
- Repository: Abstracts all database operations using Spring Data MongoDB
- Redis: Caches frequently accessed data so MongoDB isn't getting hammered on every request
Cache Miss β First Request
Cache Hit β Subsequent Request
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/tasks | Get all tasks |
| GET | /api/tasks/{id} | Get task by ID |
| POST | /api/tasks | Create a new task |
| PUT | /api/tasks/{id} | Update a task |
| DELETE | /api/tasks/{id} | Delete a task |
| GET | /actuator/health | Health check |
You can test every endpoint interactively through the Swagger UI without needing Postman. Pretty neat.
SonarCloud flagged several real vulnerabilities during development, all of which were fixed. This is exactly what enterprise security scanning tools do on every pull request β turns out those flags are there for good reason. π
DTO Pattern: Prevents mass assignment attacks where a clever client could send an ID in the request body and overwrite someone else's data.
Log Injection Prevention: User input is sanitized before logging. Without this, someone could inject fake log entries by hiding newline characters in their request. Yeah, people actually do that.
PATH Hijacking Prevention: System commands use absolute paths instead of relying on the PATH variable. Another one I learned the hard way via SonarCloud.
Environment Variables: No secrets hardcoded anywhere. MongoDB URI and Redis URL live in environment variables, consistent with how secrets are managed in production environments.
Every push to main triggers the full pipeline automatically. No manual deploys, no "works on my machine" moments.
Push to main
β GitHub Actions: build + test + JaCoCo coverage report
β SonarCloud: quality and security analysis (All A grades)
β Railway: automatic deployment via Dockerfile
Same concept as enterprise CI/CD pipelines β automated quality gates before anything reaches production. πͺ
Prerequisites: Java 21, Docker, MongoDB Atlas account
1. Clone the repository:
git clone https://github.com/Luis-Morenoo/task-manager-api.git
cd task-manager-api2. Copy the example config and fill in your credentials:
cp src/main/resources/application.yaml.example src/main/resources/application.yaml3. Run with Gradle:
./gradlew bootRun4. Or run with Docker:
docker build -t task-manager .
docker run -p 8080:8080 -e MONGODB_URI=your_uri_here task-managerSwagger UI opens automatically when the service starts. No hunting for the URL.
Two layers of tests β because one layer is not enough and zero layers is how you find out about bugs in production. π
Unit Tests: Mockito mocks out the database entirely. Tests run in milliseconds and verify every service method in isolation using the Arrange-Act-Assert pattern.
Integration Tests: MockMvc fires real HTTP requests through the full stack against a live MongoDB Atlas instance. Includes a security test that proves the API ignores client-provided IDs even when someone tries to sneak one in.
# Run all tests
./gradlew test
# Run with coverage report
./gradlew test jacocoTestReportsrc/
βββ main/
β βββ java/com/luis/taskmanager/
β β βββ controller/ # HTTP request handlers
β β βββ service/ # Business logic + caching
β β βββ repository/ # MongoDB data access
β β βββ model/ # Database entity (Task)
β β βββ dto/ # Data Transfer Objects (TaskRequest)
β β βββ OpenApiConfig.java # Swagger UI configuration
β β βββ TaskManagerApplication.java
β βββ resources/
β βββ application.yaml.example
βββ test/
βββ java/com/luis/taskmanager/
βββ TaskServiceTest.java # Unit tests
βββ TaskControllerIntegrationTest.java # Integration tests
Working in enterprise Java environments gives you a lot of exposure β reading production code, understanding distributed systems, working within established pipelines. But building something completely from scratch is a different challenge entirely.
This project forced me to understand every layer deeply. Writing tests from scratch gave me a new appreciation for automated test suites I had previously just run and hoped for green. π SonarCloud flagged real security vulnerabilities I wouldn't have caught on my own. Docker finally made the containerization concepts I had seen in production click. And deploying with a CI/CD pipeline I built myself made the whole end-to-end picture come together.
Building something real and owning every decision is one of the best ways to grow as an engineer. πͺ
π Full Technical Documentation β detailed architecture, security analysis, and testing documentation

