---
phase: screens
kind: reference
---

# Type Mapping — Entity Attribute → UI Field

This document defines how entity attribute types (from the module's `entité.md`
MCD) map to SmartListView column types and SmartForm field types. Use it as a
lookup table when proposing screens — the mapping is mechanical and should not
require asking the user.

## Column / field type table

| Entity attribute type | SmartListView column type | SmartForm field type   |
|------------------------|---------------------------|------------------------|
| `string`               | `text`                    | `text`                 |
| `string` (long, > 200) | `text` (truncated)        | `textarea`             |
| `int`                  | `number`                  | `number`               |
| `decimal`              | `currency` or `number`    | `currency` or `number` |
| `date`                 | `date`                    | `date`                 |
| `datetime`             | `datetime`                | `datetime`             |
| `bool`                 | `boolean`                 | `boolean`              |
| `enum`                 | `badge`                   | `enum`                 |
| `guid` (FK)            | `lookup`                  | `lookup`               |
| `email` (semantic)     | `text`                    | `email`                |
| `password` (semantic)  | n/a                       | `password`             |

When the column or field type is `lookup`, the `entity` property is mandatory
and must reference an existing `BaDataModelEntity.code`.
When the column or field type is `badge` or `enum`, the `options` property is
mandatory and should mirror the enum values declared on the entity attribute.

---

## Computed attribute rule

If the entity attribute is marked computed in the module's `entité.md` (it
carries a non-empty **Calculé** formula, or a business rule of type `computed`
covers it):

- **SmartForm in `edit` or `detail` mode**: the field MUST have `readonly: true`.
  Optionally note the expression in the field's `computed` property — the
  generated app evaluates it client-side via the business-rule engine.
- **SmartForm in `create` mode**: the field MUST be ABSENT (no value to compute
  from before the entity exists).
- **SmartListView**: the column may appear normally — table cells are read-only
  by nature.

Example:
```json
{ "field": "totalCompensation", "label": "Total comp", "type": "currency", "readonly": true, "computed": "salary + bonusYTD" }
```

---

## Readonly rule

`readonly` is a strict boolean — never a string. For conditional readonly
behavior (read-only on edit but editable on create, or read-only when status =
"approved"), express the logic as a business rule of type `visibility` or
`validation` and let the renderer's business-rule engine apply it.

Valid:   `{ "field": "status", "readonly": false }`
Invalid: `{ "field": "status", "readonly": "onCreate" }`

---

## Lookup field rule

Every SmartForm field, SmartListView column or SmartListView filter field of
type `lookup` must reference an existing entity:

```json
{ "field": "department", "label": "Department", "type": "lookup", "entity": "Department", "required": true }
```

The generated app follows the FK to load the target entity attributes for label
display, and the post-check verifies that the referenced entity exists in the
data model.

---

## SmartKanban auto-detection (mandatory)

For every entity that has an `enum` attribute named `status` with at least 3
options — and that does not belong to a portal/read-only module — propose a
SmartKanban screen. Place it in a dedicated `<entity>-board` section if there
isn't already a board section.

Color guidance for kanban columns:
| Status semantic | Color |
|-----------------|-------|
| draft / pending | `gray` |
| submitted / in progress | `blue` |
| approved / completed | `green` |
| rejected / cancelled | `red` |
| under review / warning | `orange` |

Set `cardFields` to the 3-4 most relevant attributes for at-a-glance
identification (typically: `code`, `name`/`title`, `assignee`, primary date).

Skip when:
- The module is a customer/employee portal (read-only, no workflow).
- The entity is a config/lookup table (no lifecycle).

---

## Filters live inside SmartListView

Filters are NOT a separate screen — they belong inside the SmartListView's
`config.filters{}` block. One section that needs filtering produces exactly
one `SmartListView` screen carrying both the filter bar and the table.

Pattern:
```
section: employees-list
  screen: SmartListView
    config.filters.fields[] (top of page)
    config.columns[]        (table below)
```

The legacy split (a separate filter screen + a table screen for the same
section) is removed and flagged by the audit (SCR-010).

---

## SmartForm placement rule

- **Form in a `*-list` section** = inline create or quick-edit drawer (the user
  stays on the list).
- **Form in a `*-detail` section** = full-page edit (the user navigates to a
  dedicated form). When the entity has incoming 1:N FKs (Client → Invoices),
  also declare `config.relatedTabs[]` so the contextual tabs appear next to
  the field tabs.

Both patterns are valid. Use list-embedded forms for high-frequency entry
(time entries, comments). Use detail-page forms for complex multi-tab entities.

---

## Permission inheritance

When a screen omits its permission, it inherits the section-level permission
from the module's `rbac.md`. When it declares one, the explicit permission wins.
Action buttons (per-action permissions) override the screen permission for that
specific action.

The generated app evaluates these against the current actor's permissions to
gate screens and buttons.
