A full-stack Todo application built with Spring Boot and Vue 3, demonstrating robust software engineering practices including Hexagonal Architecture, BDD/TDD, and dual-track CI/CD pipelines.
The project follows a clean separation of concerns:
frontend/: Vue 3 application (Vite, TypeScript, Pinia).src/main/java/: Spring Boot backend following Hexagonal Architecture.domain/: Pure business logic and domain models (e.g.,Todo,Tag).repository/: Storage interfaces and implementations (memoryvspersistence).service/: Business use cases (TodoService).controller/: REST adapters.config/: Spring configuration classes.
src/test/resources/features/: Cucumber Gherkin feature files (in-memory,database,restful).scripts/: Python automation scripts for E2E testing (auto_test.py).vendor/: Third-party dependencies (e.g.,jh_utils).
Todo/
βββ .github/
β βββ workflows/
β βββ ci.yml # Backend CI: Maven + Cucumber + PostgreSQL
β βββ run_jenkins.yml # Frontend CI: Dockerized Jenkins + Selenium
βββ frontend/
β βββ src/
β β βββ api/ # API client (Axios)
β β βββ router/ # Vue Router configuration
β β βββ stores/ # Pinia state management
β β βββ views/ # Vue pages (Dashboard, TodoList)
β β βββ App.vue # Root component
β β βββ main.ts # Entry point
β βββ vite.config.ts # Vite config (Proxy to backend port 8000)
βββ scripts/
β βββ auto_test.py # E2E Test Script (Selenium + jh_utils)
βββ src/
β βββ main/
β β βββ java/com/todoapp/
β β β βββ config/ # Spring Configuration (Memory/DB profiles)
β β β βββ controller/ # REST Controllers & DTOs
β β β βββ domain/ # Core Domain Models (Hexagonal Core)
β β β βββ repository/ # Repository Interfaces & Implementations
β β β βββ service/ # Business Logic Services
β β β βββ TodoAppApplication.java
β β βββ resources/
β β βββ application.properties # Main configuration
β β βββ schema.sql # Database schema
β βββ test/
β βββ java/com/todoapp/ # Test Steps & Runner
β βββ resources/features/ # Cucumber Feature Files (Gherkin)
βββ vendor/
β βββ jh_utils/ # Third-party utility library (Submodule)
βββ Dockerfile # Jenkins agent image definition
βββ Jenkinsfile # Jenkins pipeline definition
βββ job.xml # Jenkins job configuration template
βββ pom.xml # Maven build configuration
βββ README.md # Project documentation
- Framework: Vue 3 (Composition API)
- Language: TypeScript
- Build Tool: Vite
- State Management: Pinia
- Styling: Modern CSS
- Configuration: The frontend is currently hardcoded to communicate with the backend on port
8000, matching the default backend configuration.
- Framework: Spring Boot 3
- Language: Java 21
- Persistence: Spring Data JDBC
- In-Memory:
ConcurrentHashMapbased implementation for fast testing. - Database: PostgreSQL for production/persistence.
- In-Memory:
- Architecture: Hexagonal Architecture (Ports and Adapters), ensuring the domain logic remains independent of frameworks and databases.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βTodoService β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
βTodo createTodo(String title, String description, java.util.Set<String> tagNames) β
βββββββββββββββββββββββββββββββββββ βTodo updateTodoByTitle(String oldTitle, String newTitle, String description, java.util.Set<String> tagNames)β
βTodo β βvoid deleteByTitle(String title) β
βββββββββββββββββββββββββββββββββββ€ βvoid clearAll() β
βLong id β ββββββββββββββββββββββ βTodo markCompletedByTitle(String title) β
βString title β βDashboardService β βTodo markPendingByTitle(String title) β
βString description β ββββββββββββββββββββββ€ βjava.util.List<Todo> listTodos() β
βboolean completed β βint completedCount()β βjava.util.List<Todo> searchTodos(String query) β
βjava.time.LocalDateTime createdAtβ βint pendingCount() β βjava.util.List<Todo> listTodosBefore(java.time.LocalDateTime before) β
βjava.time.LocalDateTime updatedAtβ ββββββββββββββββββββββ βjava.util.List<Todo> listTodosBefore(java.time.LocalDateTime before, int limit) β
βjava.util.Set<Tag> tags β βjava.util.List<Todo> findByTag(String tag) β
βvoid markCompleted() β βTodo addTags(String title, java.util.Set<String> tagNames) β
βvoid markPending() β βTodo removeTags(String title, java.util.Set<String> tagNames) β
βββββββββββββββββββββββββββββββββββ βint countCompleted() β
| βint countPending() β
| βTodo getByTitle(String title) β
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| |
| |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| βTodoRepository β |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ ββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββ βTodo save(Todo) β βTagRepository β
βTag β βjava.util.Optional<Todo> findById(Long) β ββββββββββββββββββββββββββββββββββββββββββββ€
βββββββββββββ€ βjava.util.Optional<Todo> findByTitle(String) β βTag save(Tag) β
βLong id β βjava.util.List<Todo> findAll() β βjava.util.Optional<Tag> findById(Long) β
βString nameβ βvoid deleteById(Long) β βjava.util.Optional<Tag> findByName(String)β
βββββββββββββ βjava.util.List<Todo> searchByText(String) β βjava.util.List<Tag> findAll() β
βjava.util.List<Todo> findBefore(java.time.LocalDateTime, int)β βvoid deleteAll() β
βjava.util.List<Todo> findByTag(String) β ββββββββββββββββββββββββββββββββββββββββββββ
βvoid deleteAll() β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
View the complete PlantUML diagram (requires a PlantUML viewer).
The project utilizes a dual-track CI/CD strategy to balance speed and reliability:
-
Backend CI (
.github/workflows/ci.yml):- Tool: GitHub Actions.
- Scope: Validates backend business logic and persistence.
- Stack: Maven + Cucumber.
- Profile: Runs with a real PostgreSQL database to ensure data integrity and SQL correctness.
-
Frontend/E2E CI (
.github/workflows/run_jenkins.yml):- Tool: Jenkins (running in Docker).
- Scope: Validates the full application stack (Frontend + Backend) and UI interactions.
- Stack: Jenkins Pipeline (
Jenkinsfile) + Selenium (scripts/auto_test.py). - Profile: Runs the backend in In-Memory mode (
-Dtodo.repository.type=memory) for lightweight, high-speed execution without database overhead.
In addition to automated tests, a comprehensive manual testing campaign was conducted to ensure usability and functional correctness from an end-user perspective.
The following documents provide a complete overview of the manual testing process:
The application uses Spring Profiles to manage different environments:
- Production: Intended to run as a compiled JAR.
- Test Support: The Maven environment fully supports the
testprofile.- Specific interfaces or configurations not meant for production (like the In-Memory repository or test-specific security configs) are strictly guarded by
@Profile("test")to prevent exposure in production environments.
- Specific interfaces or configurations not meant for production (like the In-Memory repository or test-specific security configs) are strictly guarded by
- Properties: Configuration is managed via
application.propertiesand programmaticConfigclasses insrc/main/java/com/todoapp/config/.
This project was developed using Behavior-Driven Development (BDD) and Test-Driven Development (TDD), leveraging Cucumber as the foundation.
- Three Semantic Interfaces:
- In-Memory: For rapid domain logic verification.
- Database: For persistence layer verification.
- Restful: For API contract verification.
- Hexagonal Architecture: The architecture supports swapping these adapters (memory vs database) seamlessly without changing the core domain logic.
- Agenic Coding: The BDD/TDD approach facilitated fast, AI-assisted agentic coding by providing clear executable specifications.
- Refactoring: A distinct "Blue" (Refactor) phase was employed to optimize code structure and quality after getting tests to pass.
This project is licensed under the MIT License - see the LICENSE file for details.