Instruction file imported from communitiesuk/prsdb-webapp (
.github/instructions/models.instructions.md). Copyright stays with the author.
Models Instructions
The models/ package has three categories, each serving a different layer of the application.
DataModels (models/dataModels/)
Represent core business data, often serialised to/from the database or external APIs.
@Serializable
data class AddressDataModel(
val singleLineAddress: String,
val uprn: Long? = null,
val postcode: String? = null,
) {
companion object {
fun fromAddress(address: Address) = AddressDataModel(...)
}
}
Conventions:
- Use
data class(immutable) - Add
@Serializablewhen stored as JSON (e.g. in journey data) - Include companion factory methods (
fromEntity,fromAddress) for conversion from entities - Can contain domain logic methods (e.g.
isPastExpiryDate()) updateModels/subdirectory holds change-tracking models for update journeys. These use plaindata class(NOT@Serializable) as they represent deltas, not persisted data. Example:PropertyOwnershipUpdateModel,PropertyComplianceUpdateModel,LandlordUpdateModel
RequestModels (models/requestModels/)
Bind user form submissions. Implement the FormModel interface.
class RentAmountFormModel : FormModel {
@ValidatedBy(
constraints = [
ConstraintDescriptor(
messageKey = "forms.rentAmount.error",
validatorType = PositiveBigDecimalValidator::class,
),
],
)
var rentAmount: String = ""
}
Conventions:
- Implement
FormModelinterface (providestoPageData()) - Use
varfields (mutable for form binding) - Validation via
@ValidatedBywithConstraintDescriptorentries formModels/subdirectory for web form modelssearchModels/subdirectory for search/filter models extendingSearchRequestModel
ViewModels (models/viewModels/)
Transform data for Thymeleaf template rendering. Display-only.
data class SummaryListRowViewModel(
val fieldHeading: String,
val fieldValue: Any?,
val action: SummaryListRowActionViewModel? = null,
)
Conventions:
- Use immutable
data class - No validation — these are purely for display
- Subdirectories:
formModels/(UI components like radios, selects, checkboxes),summaryModels/(includingpropertyComplianceViewModels/),emailModels/,taskModels/,filterPanelModels/,searchResultModels/ - ViewModels are passed to templates and accessed via
${model.property} - Use
RadiosViewModel/SelectViewModel<T>for form UI components
Summary
| Aspect | DataModels | RequestModels | ViewModels |
|---|---|---|---|
| Layer | Database / Domain | User Input | Display |
| Mutability | Immutable (val) |
Mutable (var) |
Immutable (val) |
| Validation | Business logic methods | @ValidatedBy annotations |
None |
| Base | None (data classes) | FormModel interface |
None |
| Serialisation | @Serializable |
N/A | N/A |