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 DataSpace 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.