Multi-Module Maven Project
data-integration-service/ ← parent POM (Java 21, Quarkus 3.30.6)├── common/ ← shared DTOs (BulkUpsertRequestDTO, BulkUpsertResponseDTO)├── supplier/ ← suppliers + certifications├── product/ ← supplier products + company products├── textile/ ← yarns, fibers, fabrics (extends product)├── purchase/ ← purchase records + status lifecycle├── chemical/ ← chemical products + compliance + purchases├── traceability/ ← traceability records + processing stages├── user/ ← entity-only (User), not wired to REST└── app/ ← runnable Quarkus module (aggregates all above)
Domain modules are libraries — the app module provides the Quarkus runtime and wires them all together.
Layered Architecture
Each domain module follows the same layered pattern:
REST Resource (@Path, /api/v1/...)│Service (business logic, @ApplicationScoped)│Mapper (Entity ↔ DTO)│Entity (PanacheEntity, Hibernate ORM)│PostgreSQL
Dependencies flow only forward. Resources never access Entities directly.
Cross-Module Relations
Modules do not have JPA joins between them. Relations are expressed as Long IDs (supplierId, userId, companyId, productId) with validation in the Service layer. This keeps modules decoupled and independently testable.
API Prefix
All REST endpoints use the prefix /api/v1/:
| Module | Base Path |
|---|---|
| Suppliers | /api/v1/suppliers |
| Supplier Certifications | /api/v1/supplier-certifications |
| Supplier Products | /api/v1/supplier/products |
| Company Products | /api/v1/company/products |
| Textile (Yarns/Fibers/Fabrics) | /api/v1/textile/{yarns,fibers,fabrics} |
| Purchases | /api/v1/purchases |
| Chemicals | /api/v1/chemicals |
| Chemical Purchases | /api/v1/chemical-purchases |
| Traceability Records | /api/v1/traceability |
| Processing Stages | /api/v1/product/traceability |
Entity Design
All entities extend PanacheEntity (Active Record pattern) with public fields:
@Entity@Table(name = "supplier")public class Supplier extends PanacheEntity {@NotBlank public String name;@NotBlank public String category;public String country;@JdbcTypeCode(SqlTypes.JSON)public Map<String, Object> metadata;@PrePersistpublic void prePersist() {if (createdAt == null) createdAt = LocalDateTime.now();if (updatedAt == null) updatedAt = LocalDateTime.now();}@PreUpdatepublic void preUpdate() {updatedAt = LocalDateTime.now();}}
Entity Metadata
Most entities support a metadata field — a jsonb column in PostgreSQL mapped as Map<String, Object>. This allows storing arbitrary key-value pairs without schema changes.
Testing
| Scope | Tool | Database |
|---|---|---|
| Integration test | @QuarkusTest | H2 in-memory |
| Transaction rollback | @TestTransaction | H2 |
| Dev mode | Quarkus Dev Services | PostgreSQL (Docker) |
| Production | — | PostgreSQL (validate only) |
Jandex Bean Indexing
Every domain module must include the Jandex Maven plugin to enable CDI scanning:
<plugin><groupId>io.smallrye</groupId><artifactId>jandex-maven-plugin</artifactId><executions><execution><id>make-index</id><goals><goal>jandex</goal></goals></execution></executions></plugin>