@PortalEntity — entity registration
Class-level annotation — registers a JPA entity with the portal and configures its appearance in the sidebar navigation.
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class PortalEntity(
val label: String,
val labelKey: String = "", // i18n key, e.g. "entity.customer"
val module: String,
val group: String = "",
val groupKey: String = "", // i18n key for sidebar group heading
val icon: String = "table",
val order: Int = 0,
val description: String = "",
val descriptionKey: String = "", // i18n key for description
val tabs: KClass<out PortalTab> = NoTabs::class,
val allowCreate: Boolean = true,
val allowDelete: Boolean = true,
val allowEdit: Boolean = true,
val pageSize: Int = 25,
val softDelete: Boolean = false,
val auditLog: Boolean = false
)NoTabs — a framework-internal sentinel class (dev.quatrion.portal.annotation).
Represents a flat, single-page form with no tabs. No manual import required.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
label | String | — | Human-readable entity name shown in the sidebar, page headers, and breadcrumbs |
labelKey | String | "" | i18n key for label. When non-empty, replaces label in the UI |
module | String | — | Module name (must match ModuleDef.name) |
group | String | "" | Optional sidebar group — entities with the same group are collapsed under a heading |
groupKey | String | "" | i18n key for the sidebar group heading |
icon | String | "table" | Lucide icon name (e.g. "users", "package", "shopping-cart") |
order | Int | 0 | Sort position within the module / group — lower values appear first |
description | String | "" | Optional longer description shown as a page subtitle |
descriptionKey | String | "" | i18n key for description |
tabs | KClass<out PortalTab> | NoTabs::class | Enum implementing PortalTab that defines the form tabs |
allowCreate | Boolean | true | Whether to show the “Create” button |
allowDelete | Boolean | true | Whether to show the “Delete” action |
allowEdit | Boolean | true | Whether to show the “Edit” button / inline edit |
pageSize | Int | 25 | Default number of rows per page in the entity table |
softDelete | Boolean | false | When true, delete sets deleted = true. Entity must have a deleted: Boolean = false field |
auditLog | Boolean | false | When true, CRUD operations are recorded in the audit log |
Examples
Simple entity without tabs:
@Entity
@Table(name = "country")
@PortalEntity(
label = "Country",
module = "CRM",
icon = "globe",
order = 1,
description = "Country dictionary"
)
class Country { ... }Entity with tabs, group, and pagination:
@Entity
@Table(name = "customer")
@PortalEntity(
label = "Customer",
module = "CRM",
group = "Sales",
icon = "users",
order = 1,
tabs = CustomerTab::class,
pageSize = 50
)
class Customer { ... }Entity with soft-delete and audit log:
@Entity
@Table(name = "invoice")
@PortalEntity(
label = "Invoice",
module = "Finance",
icon = "file-text",
softDelete = true,
auditLog = true
)
class Invoice {
// ...
var deleted: Boolean = false // REQUIRED when softDelete = true
}Read-only entity (no create or delete):
@Entity
@Table(name = "audit_log")
@PortalEntity(
label = "Audit Log",
module = "System",
icon = "list",
allowCreate = false,
allowEdit = false,
allowDelete = false
)
class AuditLog { ... }Last updated on