Skip to main content

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:

  1. Model (Entity, DTOs, Specifications)
  2. Data access (Repository, Specification wiring)
  3. Mapping (MapStruct Mapper)
  4. Business logic (Service + lifecycle hooks)
  5. Response construction (Assembler)
  6. 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 BaseController with generics for: Input DTO, Output DTO, Entity, Specification, ID (usually UUID).

  • Base CRUD endpoints are provided:

    • GET /resource – list + filters/pagination
    • GET /resource/{id} – detail
    • POST /resource – create
    • PUT /resource/{id} – update
    • PATCH /resource/{id} – partial update
    • DELETE /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 BaseAssembler with a template flow:

    1. Optional pre-processing (e.g. load lazy relations)
    2. Base field mapping via Mapper
    3. Optional enrichment (computed fields, summaries)
    4. Optional post-processing (links, formatting)
  • Responsibilities:

    • Use Mappers for base field mapping
    • Convert relations to Summary DTOs
    • Optionally expose toInput for 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:

  • preProcessCreateInput
  • preProcessUpdateInput

Mapping:

  • postConvertToEntity

Persistence:

  • preSave
  • postSave

Queries:

  • preProcessQuery
  • postProcessQueryResult

Load/Delete:

  • preProcessLoad, postLoad
  • preProcessDelete, postDelete

Relation handling always belongs in the service layer, never in mappers.


6. Mappers – DTO ↔ Entity Conversion

Mappers perform field-level transformations.

  • Implement DtoMapper:

    • toEntity
    • toOutput
    • toInput
    • updateEntity
  • 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 EntityGraph queries for eager loading.

  • Specifications:

    • Shared base specs for id, createdAt, modifiedAt
    • Named-entity specs add name, description, and a q search field
    • Entity-specific specs extend these as needed

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 hook
    • NamedEntity – adds name, description
    • ScopedEntity – 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

  1. Model
  • Create entity (extend appropriate base)
  • Define relations and constraints
  • Add Input, Output, Summary DTOs
  1. Data Access
  • Create repository
  • Create Specification interface
  1. Mapping
  • Implement MapStruct mapper
  • Ignore relation fields; define summary mapping
  1. Business Logic
  • Extend service
  • Override hooks for relations/validation only as needed
  1. Response
  • Implement assembler with summary generation
  1. API
  • Create controller extending base controller

This sequence ensures all entities integrate consistently with the platform’s architecture.