# UI: Resource Structure Cards

> Reference for step-03b-ui.md — exact JSON formats for section resources (SmartTable, SmartForm) and wireframes.

## specification.sections[] (with resources)

```json
{
  "code": "list",
  "labels": { "fr": "Liste", "en": "List", "it": "Elenco", "de": "Liste" },
  "route": "/business/{app}/{module}",
  "icon": "list",
  "permission": "business.{app}.{module}.read",
  "wireframe": "{module}-list",
  "useCases": ["UC-{PREFIX}-001", "UC-{PREFIX}-002"],
  "businessRules": ["BR-VAL-{PREFIX}-001"],
  "resources": [
    {
      "code": "{module}-grid",
      "type": "SmartTable",
      "entity": "{MainEntity}",
      "permission": "business.{app}.{module}.read",
      "columns": ["name", "status", "createdAt"],
      "columnDefs": [
        { "field": "code", "label": {"fr": "Code", "en": "Code"}, "format": "text", "sortable": true, "filterable": true, "clickAction": "navigate:detail" },
        { "field": "name", "label": {"fr": "Nom", "en": "Name"}, "format": "text", "sortable": true, "filterable": true },
        { "field": "status", "label": {"fr": "Statut", "en": "Status"}, "format": "badge", "sortable": true, "filterable": true, "colorMap": "stateMachine:{Entity}" },
        { "field": "createdAt", "label": {"fr": "Créé le", "en": "Created"}, "format": "date-relative", "sortable": true }
      ],
      "actions": ["view", "edit", "delete"],
      "rowActions": [
        { "action": "view", "icon": "eye", "permission": "business.{app}.{module}.read" },
        { "action": "edit", "icon": "edit", "permission": "business.{app}.{module}.update", "showWhen": {"status": ["draft"]} },
        { "action": "delete", "icon": "trash", "permission": "business.{app}.{module}.delete", "confirm": true }
      ],
      "filters": ["status", "dateRange"],
      "defaultSort": { "field": "createdAt", "direction": "desc" },
      "defaultPageSize": 20,
      "emptyState": { "icon": "inbox", "message": {"fr": "Aucun enregistrement", "en": "No records"}, "createAction": true }
    }
  ]
}
```

**MANDATORY for SmartTable:** `columnDefs`, `rowActions`, `defaultSort`, `emptyState`

## SmartForm resource (for create/edit sections)

```json
{
  "code": "{module}-form",
  "type": "SmartForm",
  "entity": "{MainEntity}",
  "permission": "business.{app}.{module}.create",
  "fields": [
    { "name": "code", "component": "Input", "required": true, "validation": "Unique, auto-generated" },
    { "name": "name", "component": "Input", "required": true },
    { "name": "type", "component": "Select", "required": true, "source": "EntityTypeEnum" },
    { "name": "description", "component": "TextArea", "required": false },
    { "name": "parentId", "component": "EntitySelect", "source": "ParentEntity", "required": true },
    { "name": "startDate", "component": "DatePicker", "required": true },
    { "name": "isActive", "component": "Toggle", "default": true }
  ],
  "formLayout": {
    "type": "tabs",
    "tabs": [
      { "code": "general", "label": {"fr": "Général", "en": "General"}, "fields": ["code", "name", "type", "description"] },
      { "code": "details", "label": {"fr": "Détails", "en": "Details"}, "fields": ["parentId", "startDate", "isActive"] }
    ]
  }
}
```

**MANDATORY for SmartForm:** `fields` with `component` type, `formLayout`

## Detail Page section (reached from list click)

> **RULE:** The detail page is NOT a sidebar navigation entry. It is reached by clicking a row in the `list` section. Its route includes `:id` parameter. Every module with a `list` section MUST have a companion detail page.

```json
{
  "code": "detail",
  "labels": { "fr": "Détail", "en": "Detail", "it": "Dettaglio", "de": "Detail" },
  "route": "/business/{app}/{module}/:id",
  "icon": "file-text",
  "permission": "business.{app}.{module}.read",
  "wireframe": "{module}-detail",
  "navigation": "hidden",
  "useCases": ["UC-{PREFIX}-002"],
  "businessRules": ["BR-VAL-{PREFIX}-001"],
  "resources": [
    {
      "code": "{module}-detail-header",
      "type": "DetailHeader",
      "entity": "{MainEntity}",
      "permission": "business.{app}.{module}.read",
      "fields": ["code", "name", "status"],
      "actions": [
        { "action": "edit", "icon": "edit", "permission": "business.{app}.{module}.update", "showWhen": {"status": ["draft"]} },
        { "action": "delete", "icon": "trash", "permission": "business.{app}.{module}.delete", "confirm": true }
      ],
      "statusBadge": { "field": "status", "colorMap": "stateMachine:{Entity}" }
    },
    {
      "code": "{module}-detail-tabs",
      "type": "TabPanel",
      "entity": "{MainEntity}",
      "permission": "business.{app}.{module}.read",
      "tabs": [
        {
          "code": "info",
          "label": {"fr": "Informations", "en": "Information", "it": "Informazioni", "de": "Informationen"},
          "icon": "info",
          "default": true,
          "content": {
            "type": "DetailCard",
            "resourceRef": "{module}-info-card",
            "fields": ["code", "name", "type", "description", "startDate", "createdAt"],
            "editMode": {
              "enabled": true,
              "formRef": "{module}-form",
              "permission": "business.{app}.{module}.update"
            }
          }
        },
        {
          "code": "{relation}",
          "label": {"fr": "{RelationLabel}", "en": "{RelationLabel}"},
          "icon": "list",
          "content": {
            "type": "SmartTable",
            "resourceRef": "{module}-{relation}-grid",
            "entity": "{RelatedEntity}",
            "parentFilter": "{MainEntity}Id"
          }
        },
        {
          "code": "history",
          "label": {"fr": "Historique", "en": "History", "it": "Storico", "de": "Verlauf"},
          "icon": "clock",
          "showWhen": "auditable",
          "content": {
            "type": "Timeline",
            "resourceRef": "{module}-history",
            "source": "auditLog"
          }
        }
      ]
    }
  ]
}
```

**MANDATORY for detail section:**
- `navigation: "hidden"` — detail page is NOT shown in sidebar, reached by row click from list
- `route` MUST contain `:id` parameter
- At least one `TabPanel` resource with `tabs[]`
- First tab MUST be "info" with `DetailCard` + `editMode`
- One tab per 1:N relationship (auto-inferred from entity relationships)
- History tab if entity is auditable (has lifeCycles)

**Tab auto-generation rules:**
1. **Info tab** (always) — all entity attributes displayed as read-only fields, with edit toggle
2. **Relation tabs** (per 1:N relationship) — SmartTable filtered by `parentFilter`
3. **History tab** (if auditable) — Timeline from audit log
4. **Custom tabs** (from cadrage `detailTabs[]`) — any additional tabs specified during cadrage

## specification.uiWireframes[]

```json
{
  "screen": "{module}-{section}",
  "section": "{section}",
  "description": "Description of the screen",
  "mockupFormat": "ascii",
  "mockup": "╔═══...",
  "elements": ["DataGrid", "FilterBar", "Pagination", "CreateButton"],
  "actions": ["filter", "sort", "create", "view-detail"],
  "permissionsRequired": ["business.{app}.{module}.read"],
  "componentMapping": [
    { "wireframeElement": "DataGrid", "reactComponent": "SmartTable" },
    { "wireframeElement": "FilterBar", "reactComponent": "SmartFilter" },
    { "wireframeElement": "CreateButton", "reactComponent": "Button" }
  ],
  "layout": {
    "type": "page",
    "regions": [
      { "id": "toolbar", "position": "top", "components": [
        { "type": "FilterBar", "resourceRef": "{module}-filters" },
        { "type": "ActionMenu", "resourceRef": "{module}-actions", "permission": "business.{app}.{module}.create" }
      ]},
      { "id": "content", "position": "main", "span": 12, "components": [
        { "type": "SmartTable", "resourceRef": "{module}-grid" }
      ]}
    ]
  }
}
```

**REQUIRED fields:** `screen`, `mockup`, `elements`, `section`, `componentMapping`, `layout` are ALL mandatory.
A wireframe without `componentMapping` or `layout` will FAIL validation in step 9.
**layout.regions[].components[].resourceRef** MUST match a `sections[].resources[].code`.

## Detail Page Wireframe

> **RULE:** For every `list` section, a companion detail wireframe MUST exist with `section: "detail"`.

```json
{
  "screen": "{module}-detail",
  "section": "detail",
  "description": "Page de détail avec onglets — accessible depuis la liste par clic sur une ligne",
  "mockupFormat": "ascii",
  "mockup": "╔═══════════════════════════════════════════════════════════╗\n║  ← Retour à la liste                                    ║\n╠═══════════════════════════════════════════════════════════╣\n║  {Entity} : {code} — {name}        ● Statut  [✏️] [🗑️]  ║\n╠═══════════════════════════════════════════════════════════╣\n║  [ Informations ]  [ {Relation} ]  [ Historique ]        ║\n╠═══════════════════════════════════════════════════════════╣\n║  ┌─────────────────────────────────────────────────────┐  ║\n║  │  Code:        {code}                                │  ║\n║  │  Nom:         {name}                                │  ║\n║  │  Type:        {type}                 [Modifier]     │  ║\n║  │  Description: {description}                         │  ║\n║  │  Créé le:     {createdAt}                           │  ║\n║  └─────────────────────────────────────────────────────┘  ║\n╚═══════════════════════════════════════════════════════════╝",
  "elements": [
    { "id": "elem-back", "type": "BackButton", "label": "Retour à la liste" },
    { "id": "elem-header", "type": "DetailHeader", "label": "En-tête entité" },
    { "id": "elem-status", "type": "StatusBadge", "label": "Badge statut" },
    { "id": "elem-tabs", "type": "TabPanel", "label": "Onglets de détail" },
    { "id": "elem-info", "type": "DetailCard", "label": "Carte informations" },
    { "id": "elem-edit", "type": "SmartForm", "label": "Formulaire d'édition" }
  ],
  "actions": [
    { "trigger": "Click back", "action": "Navigate to list" },
    { "trigger": "Click edit", "action": "Toggle edit mode on info tab" },
    { "trigger": "Click tab", "action": "Switch tab content" },
    { "trigger": "Click status action", "action": "Trigger state transition (if lifeCycles)" }
  ],
  "componentMapping": [
    { "wireframeElement": "BackButton", "reactComponent": "BackButton" },
    { "wireframeElement": "DetailHeader", "reactComponent": "EntityDetailHeader" },
    { "wireframeElement": "StatusBadge", "reactComponent": "StatusBadge" },
    { "wireframeElement": "TabPanel", "reactComponent": "Tabs" },
    { "wireframeElement": "DetailCard", "reactComponent": "EntityDetailCard" },
    { "wireframeElement": "SmartForm", "reactComponent": "SmartForm" }
  ],
  "layout": {
    "type": "page",
    "regions": [
      { "id": "header", "position": "top", "components": [
        { "type": "BackButton", "target": "/business/{app}/{module}" },
        { "type": "DetailHeader", "resourceRef": "{module}-detail-header" },
        { "type": "StatusBadge", "resourceRef": "{module}-status" }
      ]},
      { "id": "tabs", "position": "main", "span": 12, "components": [
        { "type": "TabPanel", "resourceRef": "{module}-detail-tabs" }
      ]}
    ]
  },
  "permissionsRequired": ["business.{app}.{module}.read"]
}
```

**Detail wireframe adaptation rules:**
- **Tabs** must match `sections[code=detail].resources[type=TabPanel].tabs[]`
- **Relation tabs** show a SmartTable of child entities filtered by parent ID
- **History tab** only included if entity has `lifeCycles` defined
- **Edit button** only shown if user has `update` permission
- **Status actions** only shown if entity has state machine transitions from current state
