Conversation
…enting REST controller code
…ustments to integrate with spring-boot
…rop database after shutdown of application
…index.html with dynamic pageTitle
…d password from k8s secret with fallback for dev
WalkthroughReplaces the simple Java app with a Spring Boot pet-adoption service: adds controllers (REST + web), service layer, JPA entity/repository, DTOs, security, Thymeleaf UI, MySQL config, Docker/Docker Compose, Jenkins pipeline, updated POM, and new tests; removes the old App and its tests. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Browser
participant WebController
participant PetRestController
participant PetService
participant PetRepository
participant MySQL
User->>Browser: GET /
Browser->>WebController: GET /
WebController->>Browser: index.html + CSRF
Browser->>PetRestController: POST /pets (JSON + CSRF)
PetRestController->>PetService: adopt(pet)
PetService->>PetRepository: save(pet)
PetRepository->>MySQL: INSERT
MySQL-->>PetRepository: generated id
PetService->>PetRestController: PetDTO
PetRestController->>Browser: 200 OK, PetDTO
sequenceDiagram
actor Client
participant Browser
participant SpringSecurity
participant WebController
Client->>Browser: GET /pets
Browser->>SpringSecurity: request /pets
SpringSecurity-->>Browser: allow (GET permitted) or redirect to /login
Browser->>WebController: GET /login (when redirected)
WebController->>Browser: login.html
Browser->>SpringSecurity: POST /login (creds + CSRF)
SpringSecurity->>SpringSecurity: Authenticate via InMemoryUserDetails (env password)
SpringSecurity-->>Browser: Redirect /
sequenceDiagram
actor Dev
participant Git
participant Jenkins
participant Maven
participant Docker
participant Registry
participant SSH
participant Kubernetes
Dev->>Git: Push branch
Git->>Jenkins: Trigger
Jenkins->>Maven: mvn -DskipTests package
Maven-->>Jenkins: jar
Jenkins->>Docker: docker build (multi-stage)
Docker->>Registry: push images (tag & latest)
Jenkins->>SSH: scp manifests
SSH->>Kubernetes: kubectl apply & rollout wait
Kubernetes-->>Jenkins: rollout status
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (15)
src/main/resources/application.yml (2)
10-11: Consider environment-specific profiles for production deployment.The
ddl-auto: updatesetting automatically modifies the database schema, which can be risky in production (unintended schema changes, data loss). Additionally,show-sql: trueexposes queries in logs, which may include sensitive data and increases log volume.Consider creating separate profile configurations:
src/main/resources/application-prod.yml:
spring: jpa: hibernate: ddl-auto: validate show-sql: falsesrc/main/resources/application-dev.yml:
spring: jpa: hibernate: ddl-auto: update show-sql: true
16-18: Consider reducing logging verbosity for production.DEBUG level logging for
org.springframework.webcan produce excessive log output and may expose sensitive request/response details in production environments.Consider using INFO level for production or leverage Spring profiles:
logging: level: org.springframework.web: ${LOGGING_LEVEL:INFO}.dockerignore (1)
1-4: LGTM!The exclusion patterns appropriately prevent build artifacts, logs, and VCS files from bloating the Docker build context.
Consider adding these common patterns for Spring Boot projects:
*.md *.iml .mvn mvnw mvnw.cmddocker-compose.yml (3)
1-1: Consider removing the deprecated version field.The Compose file
versionfield has been deprecated since Docker Compose v1.27.0 and is ignored by modern versions.Apply this diff:
-version: '3.8' services:
6-8: Consider using a stronger password even for local development.The hard-coded password "password" is very weak. While acceptable for local development in a learning environment, consider using a slightly stronger value to reinforce good habits.
Based on learnings
Example:
environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-dev_password_123} MYSQL_DATABASE: pet
3-12: Consider adding a health check for improved reliability.Adding a health check ensures the MySQL container is ready to accept connections before dependent services start.
mysql: image: mysql:9.0 container_name: pet-mysql environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: pet ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5Jenkinsfile (3)
7-31: Consider externalizing hard-coded values to Jenkins credentials or parameters.The environment section contains hard-coded IP addresses, repository URLs, and infrastructure paths. While functional, externalizing these to Jenkins credentials store or build parameters would improve flexibility and security.
188-209: Consider security improvements for SSH-based deployment.The deployment uses SSH as root with
StrictHostKeyChecking=no, which bypasses host key verification and operates with elevated privileges. While functional, consider:
- Using a dedicated service account instead of root
- Enabling strict host key checking with known_hosts
- Alternatively, using
kubectldirectly from Jenkins with a kubeconfig
172-176: Consider adding error handling and cleanup for Docker builds.The Docker build uses
--no-cachewhich ensures fresh builds but can be slow. Consider using cache for faster builds in a CI environment, and add error handling for failed builds.stage('Build Docker Image') { steps { script { try { sh 'docker build -t ${DOCKER_IMAGE} -f Dockerfile .' } catch (Exception e) { sh 'docker system prune -f' throw e } } } }pom.xml (2)
16-28: Remove or populate empty metadata sections.The POM contains empty license, developers, and SCM sections. These should either be populated with actual information or removed to keep the POM clean.
Apply this diff to remove empty sections:
<description>exercise2025</description> <url/> - <licenses> - <license/> - </licenses> - <developers> - <developer/> - </developers> - <scm> - <connection/> - <developerConnection/> - <tag/> - <url/> - </scm> <properties>
31-31: Consider removing explicit Lombok version.The Lombok version is explicitly set in properties (1.18.42) and also in the maven-compiler-plugin's annotationProcessorPaths (lines 89-93). Since Spring Boot parent already manages Lombok version, the explicit version in properties is redundant.
<properties> <java.version>25</java.version> - <lombok.version>1.18.42</lombok.version> </properties>Then update the annotationProcessorPaths to use the managed version:
<annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> - <version>1.18.42</version> </path> </annotationProcessorPaths>Dockerfile (1)
1-13: Multi-stage build and non-root runtime look solid; ensure tests run in CI, not just skipped hereThe Dockerfile is well-structured and follows good practices (builder stage + non-root user). Just make sure your Jenkins pipeline (or another CI step) runs the Maven test suite before building/publishing this image, since
-DskipTestshere would otherwise hide failing tests.src/main/resources/templates/login.html (1)
1-143: Login template is solid; consider a small UX/accessibility tweakThe page is well-structured and wired correctly for the
/loginPOST and CSRF handling. As a small enhancement, you might:
- Add a logout/success message block (e.g.,
th:if="${param.logout}") so users see confirmation after logging out.- Mark the
.errorcontainer with something likearia-live="polite"to help screen readers announce login errors.These are nice-to-have improvements; the current template is already perfectly usable.
src/main/resources/templates/index.html (1)
224-239: Consider adding validation for empty ID input.The functions
getPet,feedPet,playPet, andreleasePetdon't validate whether the ID field is empty before making API calls. This could result in malformed requests (e.g.,/pets/instead of/pets/{id}).Consider adding a simple check:
function getPet() { const id = document.getElementById('id').value; + if (!id) { + document.getElementById('response').textContent = '⚠️ Please enter a Pet ID'; + return; + } fetchApi('GET', `/${id}`); }Apply similar validation to
feedPet,playPet, andreleasePet.src/main/java/org/example/entity/Pet.java (1)
32-39: Consider using JPA lifecycle callbacks for audit timestamps.While the current field initialization works, the best practice for JPA audit timestamps is to use lifecycle callbacks to ensure timestamps are set during persistence operations:
- private LocalDateTime createdAt = LocalDateTime.now(); + private LocalDateTime createdAt; - private LocalDateTime updatedAt = LocalDateTime.now(); + private LocalDateTime updatedAt; + @PrePersist + public void prePersist() { + createdAt = LocalDateTime.now(); + updatedAt = LocalDateTime.now(); + } + @PreUpdate public void preUpdate() { updatedAt = LocalDateTime.now(); }This ensures timestamps reflect actual persistence timing rather than object instantiation.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (25)
.dockerignore(1 hunks).gitignore(1 hunks)Dockerfile(1 hunks)Jenkinsfile(1 hunks)docker-compose.yml(1 hunks)pom.xml(1 hunks)src/main/java/org/example/App.java(0 hunks)src/main/java/org/example/Exercise2025Application.java(1 hunks)src/main/java/org/example/config/SecurityConfig.java(1 hunks)src/main/java/org/example/controller/PetRestController.java(1 hunks)src/main/java/org/example/controller/WebController.java(1 hunks)src/main/java/org/example/dto/PetDTO.java(1 hunks)src/main/java/org/example/entity/Pet.java(1 hunks)src/main/java/org/example/exception/PetNotFoundException.java(1 hunks)src/main/java/org/example/repository/PetRepository.java(1 hunks)src/main/java/org/example/service/PetService.java(1 hunks)src/main/resources/application.yml(1 hunks)src/main/resources/templates/index.html(1 hunks)src/main/resources/templates/login.html(1 hunks)src/test/java/org/example/AppIT.java(0 hunks)src/test/java/org/example/AppTest.java(0 hunks)src/test/java/org/example/Exercise2025ApplicationTest.java(1 hunks)src/test/java/org/example/controller/PetRestControllerTest.java(1 hunks)src/test/java/org/example/entity/PetRepositoryTest.java(1 hunks)src/test/java/org/example/service/PetServiceTest.java(1 hunks)
💤 Files with no reviewable changes (3)
- src/test/java/org/example/AppIT.java
- src/test/java/org/example/AppTest.java
- src/main/java/org/example/App.java
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: jennymakki
Repo: fungover/exercise2025 PR: 204
File: src/main/java/org/example/config/SecurityConfig.java:19-24
Timestamp: 2025-11-16T13:56:11.263Z
Learning: The repository fungover/exercise2025 is an exercise/learning project where hard-coded credentials and other shortcuts for ease of testing are acceptable and intentional.
📚 Learning: 2025-11-16T13:56:11.263Z
Learnt from: jennymakki
Repo: fungover/exercise2025 PR: 204
File: src/main/java/org/example/config/SecurityConfig.java:19-24
Timestamp: 2025-11-16T13:56:11.263Z
Learning: The repository fungover/exercise2025 is an exercise/learning project where hard-coded credentials and other shortcuts for ease of testing are acceptable and intentional.
Applied to files:
src/main/java/org/example/Exercise2025Application.javapom.xmlsrc/test/java/org/example/Exercise2025ApplicationTest.java
📚 Learning: 2025-11-21T16:16:54.741Z
Learnt from: LolloGro
Repo: fungover/exercise2025 PR: 211
File: src/main/resources/templates/listOfBooks.html:11-12
Timestamp: 2025-11-21T16:16:54.741Z
Learning: In the repository fungover/exercise2025, the Author DTO uses NotEmpty validation on firstName and lastName fields, and BookDto uses NotNull validation on the author field. This validation architecture ensures that books always have complete author information, making null-safety checks in Thymeleaf templates unnecessary.
Applied to files:
pom.xml
📚 Learning: 2025-09-10T14:02:54.365Z
Learnt from: alfredbrannare
Repo: fungover/exercise2025 PR: 66
File: src/test/java/org/example/service/WarehouseTest.java:1-21
Timestamp: 2025-09-10T14:02:54.365Z
Learning: In the fungover/exercise2025 project, static mocking of LocalDateTime.now() works successfully with the existing Mockito setup without requiring mockito-inline dependency.
Applied to files:
src/test/java/org/example/Exercise2025ApplicationTest.java
🔇 Additional comments (19)
.gitignore (1)
3-3: LGTM!Adding
*.imlis appropriate for excluding IntelliJ IDEA module files from version control.src/main/resources/application.yml (1)
3-5: LGTM!Using environment variables for database credentials is a security best practice.
src/main/java/org/example/Exercise2025Application.java (1)
1-13: LGTM!Standard Spring Boot application entry point with correct configuration.
src/test/java/org/example/Exercise2025ApplicationTest.java (1)
1-13: LGTM!The context load test provides a baseline verification that the Spring application context starts successfully with all configured beans.
pom.xml (3)
51-56: MySQL connector version is compatible.Verification confirms that mysql-connector-j 9.0.0 is compatible with Spring Boot 3.5.6 and MySQL 9.0. MySQL Connector/J 9.0.0 supports MySQL Server 8.0 and later, and Spring Boot 3.x is fully compatible with the Connector/J 9.x driver using the com.mysql:mysql-connector-j coordinates. No changes needed.
5-10: I need to verify whether Spring Boot 3.5.6 specifically exists and is stable. The initial search indicates 3.5.0 is the latest stable as of May 2025, but I need to check if 3.5.6 has been released since then.
Spring Boot 3.5.6 exists and is stable for production use.
Spring Boot 3.5.6 was released and is available from Maven Central on September 18, 2025. It includes ~43 bug fixes, documentation improvements, and dependency upgrades, making it suitable for production environments. The version choice is appropriate.
30-31: No action needed — Java 25 is stable and fully supported.Java 25 was released as General Availability (GA) on September 16, 2025 and is the current Long-Term Support (LTS) release. Spring Boot 3.5.6 is documented as compatible with Java 17–25. The specified version is stable, supported by Spring Boot 3.5.6, and appropriate as the current LTS for the project.
docker-compose.yml (1)
4-4: No compatibility issues found — MySQL 9.0 is supported.MySQL 9.0 is compatible with Connector/J 9.0.0 (which supports MySQL 8.0 and later), and Spring Boot 3.5.x supports the MySQL Connector/J 9.x driver. The configuration is sound.
src/main/java/org/example/repository/PetRepository.java (1)
1-6: Repository definition is clean and idiomaticThe
PetRepositoryinterface is minimal and correctly set up for standard CRUD viaJpaRepository<Pet, Long>. No issues here.src/main/java/org/example/dto/PetDTO.java (1)
1-7: DTO shape looks appropriate for the current API
PetDTOcaptures the core identity, state (hunger/happiness), and timestamps needed for the REST responses. It’s a good fit for the service and controller usage described; no changes needed right now.src/main/java/org/example/exception/PetNotFoundException.java (1)
1-11: 404 exception mapping for missing pets is appropriate
PetNotFoundExceptioncleanly encapsulates the not-found case with an HTTP 404 via@ResponseStatusand a helpful message including the id. This aligns well with the service and REST API behavior.src/main/resources/templates/index.html (1)
1-243: LGTM! Well-structured UI with proper CSRF handling.The template provides a clean, user-friendly interface with proper CSRF token integration and comprehensive pet management capabilities. The fetchApi wrapper correctly handles both JSON and text responses.
src/main/java/org/example/controller/WebController.java (1)
7-20: LGTM! Clean and straightforward MVC controller.The controller correctly handles view routing for the index and login pages, with proper use of Spring's Model to pass attributes to the template.
src/main/java/org/example/entity/Pet.java (1)
9-30: LGTM! Well-structured entity with proper validation.The entity definition is clean with appropriate Jakarta validation constraints and sensible defaults for hunger and happiness levels.
src/test/java/org/example/service/PetServiceTest.java (1)
14-57: LGTM! Comprehensive service layer test coverage.The test class effectively covers all service operations including happy paths, exception scenarios, and state mutations (feed/play). The assertions correctly verify the business logic.
src/test/java/org/example/entity/PetRepositoryTest.java (1)
11-31: LGTM! Clean repository persistence tests.The tests appropriately verify basic CRUD operations and ID generation using the DataJpaTest slice with a real database configuration.
src/test/java/org/example/controller/PetRestControllerTest.java (1)
22-73: LGTM! Thorough controller test coverage with proper mocking.The test class effectively validates all REST endpoints with appropriate use of MockMvc and mocked service dependencies. The security filter bypass is appropriate for focused controller unit testing.
src/main/java/org/example/controller/PetRestController.java (1)
13-50: LGTM! Clean REST controller with proper validation and status codes.The controller follows RESTful conventions with appropriate HTTP methods, validates input on the adopt endpoint, and delegates business logic to the service layer. The use of ResponseEntity ensures correct status code handling.
src/main/java/org/example/service/PetService.java (1)
13-62: LGTM! Well-designed service layer with proper transactional boundaries.The service implementation correctly manages transactions for write operations, handles exceptions appropriately with PetNotFoundException, and implements clean business logic for pet care actions (feeding reduces hunger, playing increases happiness). The DTO mapping is complete and accurate.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…public GET requests on /pets/** endpoints
Pull Request Type
Please check the type of change your PR introduces:
Description
This PR introduces the Pet Adoption Service application from scratch, based on the kappsegla/spring-boot template branch, implementing a RESTful web service with Spring Boot, JPA for MySQL, Spring Security, Thymeleaf for UI, and additional containerization and deployment features. The Jenkinsfile with the CI/CD pipeline is included in the repository commits.
Key Features
REST API: Endpoints for adopting, listing, retrieving, feeding, playing with, and releasing pets, using DTOs, validation, and exception handling.
Persistence and Patterns: Entity with JPA, Repository interface for data access, Service layer with transactions, and DTO for API responses.
Security: Form-based authentication with BCrypt-encoded passwords, denying public access to REST endpoints for mutations while securing the web UI; supports environment variables for secrets.
Web UI: Thymeleaf templates for login and index pages with interactive JavaScript for API calls.
Configuration and Ops: application.yml for datasource, Dockerfile for multi-stage build, docker-compose.yml for local MySQL setup, and Jenkinsfile for CI/CD pipeline integration.
Deployment (Extra): Jenkins pipeline (via committed Jenkinsfile) for checkout, Maven build, Kubernetes manifest generation (Deployment, Service, HPA, Ingress), Docker image build/push, and deployment to HA Kubernetes cluster with secrets for MySQL and app password.
How Has This Been Tested?
JUnit 5 Tests: Unit tests for REST controller (MockMvc), service, repository, and application context; integration tests for security (authenticated vs. unauthenticated access).
Manual Testing: Verified API endpoints via curl/Postman (e.g., POST /pets, GET /pets/{id}), UI interactions (adopt, feed, play, release via form), login functionality, and error handling (e.g., invalid inputs, non-existent pets).
Local and Deployed Mode: Executed locally using docker-compose for MySQL integration, incorporating fallback datasource configurations; verified deployment to Kubernetes through the Jenkins pipeline, with operational access at https://spring-pet-adoption.ekedala-services.se/ (e.g., /pets endpoint delivers JSON data, and the /login form functions with live demo credentials: petuser/petpass123).
For local development testing in Linux/WSL, run these commands in two separate terminal windows in your project directory:
docker compose upmvn spring-boot:runUse these credentials on the login-screen: petuser/petpass.
To shut down and clean up containers afterwards, run:
docker compose downScreenshots (if appropriate)
Linked issues
This PR closes issue #193
Summary by CodeRabbit
New Features
Chores
Tests
✏️ Tip: You can customize this high-level summary in your review settings.