# Specification: Auto-Inference Rules

> Reference for step-03-specify.md — convention/override depth auto-generation from entity definitions.

## Entity Attribute → SmartTable Column

| Attribute Type | Column Format | Sortable | Filterable | Notes |
|---|---|---|---|---|
| string + unique | text | yes | yes | clickAction: navigate:detail |
| string | text | yes | yes | — |
| enum / status | badge | yes | yes (multi-select) | colorMap from lifeCycles if exists |
| FK:Entity | text (join .name) | yes | yes (EntityLookup) | Display related entity name, filter via searchable EntityLookup |
| decimal | currency | yes | no | — |
| int | number | yes | no | — |
| datetime | date-relative | yes | yes (date-range) | — |
| bool | boolean | yes | yes (toggle) | — |
| text (long) | — | no | no | Hidden in table, visible in detail |

## Entity Attribute → SmartForm Field

| Attribute Type | Component | Required from | Notes |
|---|---|---|---|
| string | Input | entity.required | — |
| string (multiline) | TextArea | entity.required | rows: 4 |
| enum | Select | entity.required | source: enum name |
| FK:Entity | EntityLookup | entity.required | source: target entity, searchable. Component: `@/components/ui/EntityLookup`. NEVER plain text input for FK Guid fields. Backend API MUST support `?search=` param. See `smartstack-frontend.md` section 6. |
| FK:User (person role) | `EntityLookup` | entity.required | searchable dropdown searching Users by name + email. `<EntityLookup apiEndpoint="/api/administration/users" mapOption={(user) => ({id: user.id, label: `${user.firstName} ${user.lastName}`, sublabel: user.email})} />` |
| decimal | NumberInput | entity.required | — |
| int | NumberInput | entity.required | — |
| datetime | DatePicker | entity.required | — |
| bool | Toggle | — | default: false |

## Auto-Generated UI Components by featureType

> **RULE:** Sections are functional, not CRUD-based. `create`/`edit` are separate pages with own URL routes (`/create` and `/:id/edit`). `detail` is a tabbed page reached from `list`.

| featureType | Sections (functional) | permissionMode | List page includes | Form pages | Detail page tabs |
|---|---|---|---|---|---|
| data-centric | list | `crud` | grid, filters, create button | `/create` page, `/:id/edit` page | Infos, {relations} |
| data-centric | (detail — implicit) | `inherit` | — | — | — |
| workflow | list | `crud` | grid, filters, create button | `/create` page, `/:id/edit` page | Infos, {relations}, Historique |
| workflow | approve | `custom:approve,reject` | — | — | — |
| integration | list | `crud` | grid, filters, config button | `/create` page, `/:id/edit` page | Infos, Config, Logs |
| reporting | dashboard | `read-only` | — | — | — |
| full-module | list | `crud` | grid, filters, create button | `/create` page, `/:id/edit` page | Infos, {relations}, Historique |
| full-module | dashboard | `read-only` | — | — | — |

> **RULE:** `detail` is NEVER a section with its own permission set. It is always `sectionType: view`, `permissionMode: inherit`. Detail pages inherit permissions from their parent module.

## Component Generation Rules

1. **list section:** SmartTable with all non-long-text attributes as columns, actions = [view, edit, delete], defaultSort = { createdAt, desc }. Create button navigates to `/create` page. Edit action navigates to `/:id/edit` page.
2. **create page (`/create` route):** SmartForm (full page) with all writable attributes as fields, component inferred from type. Back button + form + submit. NEVER a modal.
3. **edit page (`/:id/edit` route):** Same form as create but pre-filled with entity data. Full page with back button. NEVER a modal or inline toggle.
4. **detail page (from list click):** TabPanel with: Info tab (all attributes read-only + edit button navigating to `/:id/edit`), relation tabs (child SmartTable for each 1:N relationship), History tab (if auditable). See "Detail Page Tab Auto-Inference" below for exact rules.
5. **dashboard section:** Trigger 3d (dashboard specification)

## Detail Page Tab Auto-Inference

> **RULE:** Every module with a `list` section MUST have a companion detail page. Tabs are inferred from multiple sources.

### Tab sources (merged in order)

| Priority | Source | Tabs generated |
|----------|--------|----------------|
| 1 | `coverageMatrix[].detailTabs` (from cadrage) | Exact tab names as specified by client |
| 2 | Entity `relationships[]` where `type = "1:N"` | One tab per child relationship (SmartTable) |
| 3 | Entity has `lifeCycles[]` | History tab (Timeline) |
| 4 | Always present | Info tab (first position) |

### Merge algorithm

```
detailTabs = []

# 1. Always add Info tab first
detailTabs.push({ code: "info", label: "Informations", content: DetailCard })

# 2. If cadrage specified detailTabs, use those names
IF coverageMatrix[module].detailTabs EXISTS:
  FOR EACH tabName IN detailTabs:
    IF tabName matches a 1:N relationship entity → SmartTable tab
    ELIF tabName == "Historique"/"History" → Timeline tab
    ELSE → custom DetailCard tab (contents TBD in step-03)

# 3. If no cadrage tabs, auto-infer from relationships
ELSE:
  FOR EACH rel IN entity.relationships WHERE rel.type == "1:N":
    detailTabs.push({ code: rel.target (kebab-case), label: rel.target (plural), content: SmartTable })

# 4. Add History tab if auditable
IF entity has lifeCycles:
  detailTabs.push({ code: "history", label: "Historique", content: Timeline })
```

### Detail section auto-generation

When auto-generating the detail section, create:
- `specification.sections[]` entry with `code: "detail"`, `navigation: "hidden"`, route `/{app}/{module}/:id`
- `specification.uiWireframes[]` entry with `section: "detail"` and ASCII mockup showing all tabs
- Resources: `{module}-detail-header` (DetailHeader), `{module}-detail-tabs` (TabPanel), `{module}-info-card` (DetailCard), one `{module}-{relation}-grid` per relation tab, `{module}-history` (Timeline if auditable)

### Detail page navigation wiring

The detail page is NOT a sidebar entry. Navigation is handled by:
- **From list**: row click action `navigate:detail` → `/{app}/{module}/{id}`
- **Back button**: detail header → `/{app}/{module}`
- **Route registration**: route MUST be registered in frontend routing with `:id` parameter

## Status/Lifecycle Enhancement

If entity has a status/enum field AND lifeCycles exists:
- list section: status column gets `format: badge`, `colorMap: stateMachine:{Entity}`
- list section: rowActions get `showWhen` conditions based on state machine transitions
- detail section: add StatusBadge resource + transition action buttons

Write auto-generated sections to `specification.sections[]` via `ba-writer.enrichSection()`
