# PRD Schema Reference — /business-analyse-quick

> Schemas for PRD v4.0 and companion specification files.
> Field names are **identical** to BA schemas for APEX delegate mode compatibility.

---

## PRD v4.0 Structure

```json
{
  "$version": "4.0.0",
  "project": {
    "application": "{AppPascalCase}",
    "module": "{module-kebab-case}"
  },
  "expectedFiles": {
    "domain": [
      { "path": "src/Domain/Entities/{App}/{Module}/{Entity}.cs", "type": "Entity", "module": "{Module}" }
    ],
    "infrastructure": [
      { "path": "src/Infrastructure/Persistence/Configurations/{App}/{Module}/{Entity}Configuration.cs", "type": "EFConfig", "module": "{Module}" }
    ],
    "seedData": [
      { "path": "src/Infrastructure/Persistence/Seeding/Data/{Module}/NavigationModuleSeedData.cs", "type": "NavModule", "module": "{Module}" },
      { "path": "src/Infrastructure/Persistence/Seeding/Data/{Module}/NavigationSectionSeedData.cs", "type": "NavSection", "module": "{Module}" },
      { "path": "src/Infrastructure/Persistence/Seeding/Data/{Module}/PermissionsSeedData.cs", "type": "Permissions", "module": "{Module}" },
      { "path": "src/Infrastructure/Persistence/Seeding/Data/{Module}/RolesSeedData.cs", "type": "Roles", "module": "{Module}" }
    ],
    "application": [
      { "path": "src/Application/Services/{App}/{Module}/{Entity}Service.cs", "type": "Service", "module": "{Module}" },
      { "path": "src/Application/DTOs/{App}/{Module}/Create{Entity}Dto.cs", "type": "DTO", "module": "{Module}" },
      { "path": "src/Application/DTOs/{App}/{Module}/Update{Entity}Dto.cs", "type": "DTO", "module": "{Module}" },
      { "path": "src/Application/DTOs/{App}/{Module}/{Entity}Dto.cs", "type": "DTO", "module": "{Module}" },
      { "path": "src/Application/Validators/{App}/{Module}/{Entity}Validator.cs", "type": "Validator", "module": "{Module}" }
    ],
    "api": [
      { "path": "src/API/Controllers/{App}/{Entity}Controller.cs", "type": "Controller", "module": "{Module}" }
    ],
    "frontend": [
      { "path": "src/pages/{app-kebab}/{module-kebab}/{Entity}ListPage.tsx", "type": "Page", "module": "{Module}" },
      { "path": "src/pages/{app-kebab}/{module-kebab}/{Entity}DetailPage.tsx", "type": "Page", "module": "{Module}" },
      { "path": "src/pages/{app-kebab}/{module-kebab}/Create{Entity}Page.tsx", "type": "Page", "module": "{Module}" },
      { "path": "src/pages/{app-kebab}/{module-kebab}/Edit{Entity}Page.tsx", "type": "Page", "module": "{Module}" },
      { "path": "src/i18n/locales/fr/{module-lower}.json", "type": "i18n", "module": "{Module}" },
      { "path": "src/i18n/locales/en/{module-lower}.json", "type": "i18n", "module": "{Module}" },
      { "path": "src/i18n/locales/it/{module-lower}.json", "type": "i18n", "module": "{Module}" },
      { "path": "src/i18n/locales/de/{module-lower}.json", "type": "i18n", "module": "{Module}" }
    ],
    "tests": [
      { "path": "src/Tests/Unit/Domain/{App}/{Module}/{Entity}Tests.cs", "type": "UnitTest", "module": "{Module}" },
      { "path": "src/Tests/Integration/{App}/{Module}/{Entity}ControllerTests.cs", "type": "IntegrationTest", "module": "{Module}" }
    ],
    "documentation": []
  },
  "specificationFiles": {
    "entities": "prd-{module}.entities.json",
    "permissions": "prd-{module}.permissions.json",
    "rules": "prd-{module}.rules.json",
    "usecases": "prd-{module}.usecases.json",
    "screens": "prd-{module}.screens.json"
  },
  "tasks": []
}
```

> **Paths in `specificationFiles`** are relative to the PRD directory (`.ralph/`).
> APEX resolves them via `path.join(path.dirname(prd_path), specFiles.xxx)`.

---

## entities.json

```json
{
  "entities": [
    {
      "name": "Employee",
      "description": "Represents a company employee",
      "personRoleConfig": { "variant": "mandatory", "userFields": ["firstName", "lastName", "email"] },
      "attributes": [
        { "name": "code", "type": "string", "required": true, "unique": true, "searchable": true },
        { "name": "firstName", "type": "string", "required": true },
        { "name": "hireDate", "type": "DateTime", "required": true },
        { "name": "status", "type": "enum", "required": true, "values": ["Active", "Inactive"] }
      ],
      "relationships": [
        { "target": "Department", "type": "ManyToOne", "description": "Employee belongs to a department" }
      ],
      "codePattern": { "strategy": "sequential", "prefix": "emp", "digits": 5, "separator": "-", "includeTenantSlug": true },
      "estimatedVolume": { "monthly": 20, "total2y": 500 }
    }
  ]
}
```

**Rules:**
- `personRoleConfig` only if entity has personal attributes (→ FK to auth_Users with type `string`, NOT Guid)
- Omit boolean flags when `false` (unique, searchable, computed)
- NO technical fields (Id, TenantId, CreatedBy, ModifiedBy, etc.)
- `type`: string | int | decimal | long | bool | DateTime | Guid | enum

---

## rules.json

```json
{
  "rules": [
    {
      "id": "BR-VAL-EMP-001",
      "name": "Hire date validation",
      "category": "validation",
      "statement": "Hire date cannot be in the future",
      "severity": "blocking",
      "priority": "must",
      "entities": ["Employee"],
      "examples": [
        { "input": "hireDate = 2027-01-01", "expected": "Error: date in the future" }
      ]
    }
  ]
}
```

**ID format:** `BR-{CAT}-{MODULE}-{NNN}` where CAT = VAL|CALC|WFL|SEC|DAT|NOT
**Categories:** validation | calculation | workflow | security | data | notification
- `formula` field required for `calculation` category
- `conditions` + `consequences` fields required for `workflow` category

---

## usecases.json

```json
{
  "useCases": [
    {
      "id": "UC-EMP-001",
      "name": "Create employee",
      "sectionCode": "list",
      "primaryActor": "HR Manager",
      "permission": "HumanResources.Employees.Create",
      "preconditions": ["User has HumanResources.Employees.Create permission"],
      "mainScenario": [
        "User opens the creation page",
        "User fills mandatory fields",
        "User submits the form",
        "System validates business rules",
        "System creates the employee with Active status"
      ],
      "alternativeScenarios": [
        { "name": "Invalid data", "steps": ["System displays validation errors", "User corrects and resubmits"] }
      ],
      "postconditions": ["Employee created with status Active"],
      "businessRules": ["BR-VAL-EMP-001"],
      "result": "Employee is created with Active status"
    }
  ]
}
```

**Field naming:** `useCases` (NOT usecases), `primaryActor` (NOT actor), `mainScenario` as string[]

---

## permissions.json

```json
{
  "roles": [
    { "role": "HR Admin", "level": "admin", "description": "Full access to HR module" },
    { "role": "Manager", "level": "manager", "description": "Read, create, update and approve access" },
    { "role": "Viewer", "level": "viewer", "description": "Read-only access" }
  ],
  "permissionPaths": [
    "HumanResources.Employees.Read",
    "HumanResources.Employees.Create",
    "HumanResources.Employees.Update",
    "HumanResources.Employees.Delete",
    "HumanResources.Employees.Export",
    "HumanResources.Employees.Approve"
  ],
  "matrix": {
    "roleAssignments": [
      { "role": "HR Admin", "permissions": ["HumanResources.Employees.*"] },
      { "role": "Manager", "permissions": ["HumanResources.Employees.Read", "HumanResources.Employees.Create", "HumanResources.Employees.Update", "HumanResources.Employees.Approve"] },
      { "role": "Viewer", "permissions": ["HumanResources.Employees.Read"] }
    ]
  }
}
```

**Role rules:**
- `role`: display name, PascalCase words with spaces (e.g., "HR Admin", NOT "hr-admin")
- `level`: one of `admin` | `manager` | `contributor` | `viewer` — determines hierarchy position
- `description`: one sentence in `{conversation_language}`
- MINIMUM 2 roles: one admin-level + one operational role

**Permission path format:**
- 3-segment (standard): `{ApplicationPascalCase}.{ModulePascalCase}.{Action}`
- 4-segment (custom section): `{ApplicationPascalCase}.{ModulePascalCase}.{SectionPascalCase}.{Action}`
- All segments are PascalCase — NO hyphens, NO spaces, NO kebab-case
- Module name conversion: `absence-management` → `AbsenceManagement`

**Standard actions:** Read, Create, Update, Delete, Export, Import, Approve, Admin

**Matrix rules:**
- Admin role ALWAYS gets wildcard: `["{base}.*"]`
- Other roles get EXPLICIT path lists (no wildcards)
- Every role in `roleAssignments` MUST exist in `roles[]`
- Every permission path in `roleAssignments` MUST exist in `permissionPaths` (except wildcards ending with `.*`)

**Cross-validation requirements:**
- Every `permission` field in usecases.json MUST exist in `permissionPaths`
- Every section `permission` in screens.json (where `permissionMode` is not `"inherit"`) MUST exist in `permissionPaths`
- `permissionPaths.length >= 4` (Read + Create + Update + Delete minimum per module)

---

## screens.json

```json
{
  "sections": [
    {
      "code": "list",
      "sectionType": "primary",
      "permissionMode": "crud",
      "parentSectionCode": null,
      "labels": { "fr": "Employés", "en": "Employees", "it": "Dipendenti", "de": "Mitarbeiter" },
      "route": "/{app-kebab}/{module-kebab}/list",
      "icon": "users",
      "permission": "HumanResources.Employees.Read",
      "useCases": ["UC-EMP-001", "UC-EMP-002"],
      "resources": [
        {
          "code": "employees-grid",
          "type": "SmartTable",
          "entity": "Employee",
          "columns": [
            { "field": "code", "label": { "fr": "Code", "en": "Code" }, "format": "text", "sortable": true },
            { "field": "firstName", "label": { "fr": "Prénom", "en": "First Name" }, "format": "text" },
            { "field": "status", "label": { "fr": "Statut", "en": "Status" }, "format": "badge" }
          ],
          "actions": ["create", "edit", "delete"],
          "defaultSort": { "field": "code", "direction": "asc" },
          "defaultPageSize": 20
        }
      ]
    }
  ]
}
```

**Section types:** primary (menu-visible, includes implicit detail/create/edit pages) | functional (independent workflow) | embedded (widget/tab)
**Resource types:** SmartTable | SmartForm | DetailCard | KpiPanel | KpiCard | Timeline | Chart | FilterBar | Tabs

> **IMPORTANT — Implicit pages (NOT sections):**
> APEX automatically generates detail (/:id), create (/create), and edit (/:id/edit) pages
> as routes under each primary section. Do NOT include "detail", "create", "edit", or "*-detail"
> as sections in screens.json — they are implicit APEX pages, not navigation entries.
>
> **API route convention:**
> - `route` field is the frontend React Router path (e.g., `/human-resources/employees/list`)
> - The backend API endpoint is `/api/{app-kebab}/{module-kebab}` (API routes never include section codes)
> - GetById: `GET /api/{app-kebab}/{module-kebab}/{id}`
> - GetAll: `GET /api/{app-kebab}/{module-kebab}` with pagination query params
