An enterprise-grade Java microservice designed to ingest, score, and relationally map inbound marketing leads. Built with Java 26 and Spring Boot 4.0, this project demonstrates modern Domain-Driven Design (DDD), strict schema validation, database migration management, and secure observability.
- Domain-Driven Design (DDD): Packaged by feature rather than by layer, ensuring high cohesion, low coupling, and strict encapsulation of domain logic.
- Deterministic Schema Management: Disables Hibernate's risky
ddl-autogeneration in favor of Flyway, ensuring all database schema changes are immutable, version-controlled, and CI/CD ready. - Atomic Relational Persistence: Leverages Spring Data JPA and
@Transactionalto guarantee atomicity acrossLead,Attribution, andLeadScoreentity insertions. - Immutable DTOs: Utilizes modern Java
recordtypes combined with Jakarta Validation to enforce strict runtime boundaries and input sanitization at the controller layer. - Distributed-Ready Identifiers: Replaces traditional auto-incrementing integers with UUIDs across all entities to support database sharding and asynchronous event-driven queues (e.g., Kafka).
- Secure Observability: Isolates Spring Boot Actuator telemetry and health checks to a dedicated management port, preventing public information disclosure while enabling Kubernetes readiness/liveness probes.
- Language: Java 26
- Framework: Spring Boot 4.0.x
- Persistence: Spring Data JPA / Hibernate
- Database: SQLite
- Migrations: Flyway 12.x
- Validation: Jakarta Bean Validation
- Tooling: Gradle, Lombok
The codebase strictly adheres to Package-by-Feature to isolate business domains:
src/main/java/com/yourdomain/marketingapi/
├── core/ # Global configurations and exception handlers
├── lead/ # The Lead Domain (High Cohesion)
│ ├── dto/ # Immutable Request/Response Records
│ ├── score/ # Decoupled Scoring Engine (@Component)
│ ├── LeadController.java # HTTP routing and validation
│ ├── LeadService.java # Transactional orchestration
│ └── LeadRepository.java # Data access
- JDK 26+
- Gradle 9.4.0
- Clone the repository and navigate to the project root.
- Ensure you have a clean slate (this custom task drops any existing local SQLite databases):
./gradlew clean
- Boot the application:
Note: On startup, Flyway will automatically execute
./gradlew bootRun
V1__Create_lead_tables.sqlto construct the database before Spring Boot accepts traffic.
Ingests a new lead, executes the scoring engine, and persists the relational data.
Request:
curl -X POST http://localhost:3000/leads \
-H "Content-Type: application/json" \
-d '{"email": "director@enterprise.com", "firstName": "John", "lastName": "Smith", "jobTitle": "Director of Engineering", "employees": 1200, "source": "LinkedIn"}'To prevent public exposure of internal infrastructure, Spring Boot Actuator is mapped to a secondary management port.
Health Check (Liveness/Readiness):
curl http://localhost:3001/actuator/healthFlyway Migration Status:
curl http://localhost:3001/actuator/flyway- Why Flyway over Hibernate DDL? Relying on Hibernate's
ddl-auto=updatecan cause catastrophic schema drifts and table locks in production. By combining Flyway withspring.jpa.hibernate.ddl-auto=validate, the application guarantees the Java domain model perfectly matches the physical database schema before starting. - Why Isolate the Scoring Engine? By extracting the lead scoring logic into a standalone
@Component, the business rules can be rigorously unit-tested without loading the Spring Application Context or mocking database connections. - Why Constructor Injection? Avoided
@Autowiredfields in favor of constructor injection to ensure components remain immutable and easily instantiable in test environments.
Developed as a demonstration of Java architecture and Spring Boot 4.0 best practices.