Developer Guide
1. Purpose
This guide explains how to implement and extend the Portal Backend at a code-level. It complements the Architectural Overview and describes how Controllers, Services, Assemblers, Mappers, Repositories, and the Domain Model are instantiated for entities like DataPool (will be added in v2.1) or DataSet.
2. Implementation Flow for a New Entity
Introducing a new entity follows a consistent pattern:
- Model (Entity, DTOs, Specifications)
- Data access (Repository, Specification wiring)
- Mapping (MapStruct Mapper)
- Business logic (Service + lifecycle hooks)
- Response construction (Assembler)
- API exposure (Controller)
Each layer reuses shared base components with minimal entity-specific code.
3. Controllers – API Entry
Controllers are thin REST adapters and delegate all logic to Services and Assemblers.
-
Extend
BaseControllerwith generics for: Input DTO, Output DTO, Entity, Specification, ID (usuallyUUID). -
Base CRUD endpoints are provided:
GET /resource– list + filters/paginationGET /resource/{id}– detailPOST /resource– createPUT /resource/{id}– updatePATCH /resource/{id}– partial updateDELETE /resource/{id}– delete
Most controllers only define type parameters and base path. Custom endpoints are added only when required.
4. Assemblers – Response Construction
Assemblers build Output DTOs from entities.
-
Implement
BaseAssemblerwith a template flow:- Optional pre-processing (e.g. load lazy relations)
- Base field mapping via Mapper
- Optional enrichment (computed fields, summaries)
- Optional post-processing (links, formatting)
-
Responsibilities:
- Use Mappers for base field mapping
- Convert relations to Summary DTOs
- Optionally expose
toInputfor PATCH workflows
Assemblers isolate all response shaping logic from controllers and services.
5. Services – Business Logic and Hooks
Services orchestrate repositories, transactions, and domain rules.
- Extend
BaseService, which provides all standard operations. - Override lifecycle hooks only when needed:
Input:
preProcessCreateInputpreProcessUpdateInput
Mapping:
postConvertToEntity
Persistence:
preSavepostSave
Queries:
preProcessQuerypostProcessQueryResult
Load/Delete:
preProcessLoad,postLoadpreProcessDelete,postDelete
Relation handling always belongs in the service layer, never in mappers.
6. Mappers – DTO ↔ Entity Conversion
Mappers perform field-level transformations.
-
Implement
DtoMapper:toEntitytoOutputtoInputupdateEntity
-
MapStruct generates implementations:
- Relation fields are ignored
- Create ignores nulls for optional fields
- Update/PATCH applies explicit nulls
Mappers focus purely on type-safe field copying.
7. Repositories and Specifications – Data Access
Repositories encapsulate all DB operations.
-
Base repositories build on Spring Data JPA and support CRUD + Specifications.
-
Entity-specific repositories extend the base and may define
EntityGraphqueries for eager loading. -
Specifications:
- Shared base specs for
id,createdAt,modifiedAt - Named-entity specs add
name,description, and aqsearch field - Entity-specific specs extend these as needed
- Shared base specs for
Controllers receive specification instances built automatically from query parameters.
8. Domain Model – Entities and DTOs
The domain model defines core structures:
-
Entities:
BaseEntity– id, audit fields, validation hookNamedEntity– addsname,descriptionScopedEntity– adds scope fields- Concrete entities extend these and define relations and additional fields
-
DTOs:
- Input DTOs – client data, relations as IDs
- Output DTOs – full responses with nested summaries
- Summary DTOs – minimal representations for nested relations
Validation occurs at the DTO, service, and optional entity level.
9. Implementation Checklist for a New Entity
- Model
- Create entity (extend appropriate base)
- Define relations and constraints
- Add Input, Output, Summary DTOs
- Data Access
- Create repository
- Create Specification interface
- Mapping
- Implement MapStruct mapper
- Ignore relation fields; define summary mapping
- Business Logic
- Extend service
- Override hooks for relations/validation only as needed
- Response
- Implement assembler with summary generation
- API
- Create controller extending base controller
This sequence ensures all entities integrate consistently with the platform’s architecture.