---
name: step-01-transform
description: Build handoff data per module - 8 categories from flat BA files
model: sonnet
next_step: steps/step-02-export.md
---

> **Context files:** `references/handoff-file-templates.md` | `references/handoff-mappings.md` | `references/handoff-seeddata-generation.md` | `references/entity-domain-mapping.md`

# Step 01: Transform (Handoff Data Generation)

## MANDATORY EXECUTION RULES

- **ALWAYS** process modules in topological order (dependencies first)
- **ALWAYS** load data from **flat files** (entities.json, usecases.json, rules.json, screens.json, permissions.json)
- **ALWAYS** map to 8 categories (including "documentation")
- **ALWAYS** propagate personRoleConfig verbatim from entities
- **ALWAYS** separate seedData into core/business categories
- **ALWAYS** map entity to domain file path (1:1)
- **ALWAYS** include dependencies[] per file entry
- **NEVER** invent entities/BRs not in module JSON files
- **ALWAYS** generate API endpoints from use cases + entities (BA does not produce apiEndpoints)

## YOUR TASK

For each module in topological order, load flat BA files, build the complete handoff data with 8 file categories, BR-to-code mapping, API endpoint summary, and write to feature.json via ba-writer.

---

## DATA LOADING (Flat-File Architecture)

For each module, load data from separate files:

```javascript
// Module BA directory: docs/{AppCode}/{ModuleCode}/business-analyse/v{X.Y}/
const moduleDir = module.baDir;  // resolved in step-00

const entities    = READ(moduleDir + '/entities.json').entities || [];
const useCases    = READ(moduleDir + '/usecases.json').useCases || [];
const rules       = READ(moduleDir + '/rules.json').rules || [];
const permissions = READ(moduleDir + '/permissions.json');
const screens     = READ(moduleDir + '/screens.json').screens || [];
```

**Source mapping (flat files -> handoff categories):**

| Handoff needs | Source file | Root key |
|---------------|------------|----------|
| Entities, ValueObjects, Enums | `entities.json` | `entities[]` |
| Use cases | `usecases.json` | `useCases[]` |
| Business rules | `rules.json` | `rules[]` |
| Roles, permissions | `permissions.json` | `roles[]`, `matrix[]`, `permissionPaths[]` |
| Screens, sections, wireframes | `screens.json` | `screens[]` |

---

## EXECUTION SEQUENCE

For **EACH module** in topological order:

### 1. Calculate Complexity

```json
{
  "complexity": "simple|medium|complex",
  "complexityDetails": {
    "entities": {count},
    "useCases": {count},
    "businessRules": {count},
    "calculated": "{level} (entities<=X, UCs<=Y, BRs<=Z)"
  }
}
```

| Criteria | Simple | Medium | Complex |
|----------|--------|--------|---------|
| Entities | <=3 | <=6 | >6 |
| Use Cases | <=5 | <=12 | >12 |
| Business Rules | <=10 | <=20 | >20 |

**Global complexity** = highest across all modules.

### 2. Generate API Endpoints from Use Cases

Since `/business-analyse` does not produce `apiEndpoints`, generate them from use cases + entities:

```javascript
// For each use case, derive the API endpoint:
// UC "Create Employee" -> POST /api/{app}/{module}
// UC "List Employees"  -> GET  /api/{app}/{module}
// UC "Update Employee" -> PUT  /api/{app}/{module}/{id}
// UC "Delete Employee" -> DELETE /api/{app}/{module}/{id}
// UC "Get Employee"    -> GET  /api/{app}/{module}/{id}

// Use permission paths from permissions.json to determine operations
// Map CRUD operations to HTTP methods
```

### 3. Map Specification to Files (8 Categories)

> **Reference:** Read `references/handoff-file-templates.md` for complete JSON templates.
> All backend paths MUST include `{ApplicationName}/` hierarchy.

| Category | Source | Key rules |
|----------|--------|-----------|
| **Domain** | `entities.json > entities[]` | Entities, ValueObjects, Enums |
| **Application** | `usecases.json > useCases[]` | Services, DTOs, Validators |
| **Infrastructure** | `entities.json > entities[]` | EF Configurations, DbSet |
| **API** | Generated from useCases + entities | Controllers |
| **Frontend** | `screens.json > screens[]` | Pages, Components, Hooks; split by file (NOT monolithic) |
| **SeedData** | Generated from entities + permissions | CORE (2 app-level + per-module) + business |
| **Tests** | All layers | Unit, Integration, Security tests |
| **Documentation** | All layers | Technical docs, user guides, API specs (can be empty `[]`) |

**Frontend Task Splitting (MANDATORY):**
- Each page as separate entry (not bundled mega-task)
- FK fields: `"fkFields": ["EmployeeId->Employee", "DepartmentId->Department"]`
- ALL pages use `/ui-components` skill
- Route wiring: separate entry in `filesToCreate.frontend`

**Route Convention (CRITICAL):**
- Transform PascalCase module codes to kebab-case in NavigationModule/Section routes
- Example: `"HumanResources"` -> `"/human-resources"` (NEVER include `/business/` prefix)

**Documentation Category:**
- Include `doc-data.ts` for documentation data export
- Can be empty `[]` if no documentation is planned at this stage

### 4. Map Business Rules to Code

> **Reference:** Read `references/handoff-mappings.md` -- Section "Business Rules to Code Mapping"

For each rule in `rules.json > rules[]` of EACH module:
- ruleId, title, module, severity (from `rule.severity`)
- implementationPoints: Array of {layer, component, method, implementation} across all layers

### 5. Propagate personRoleConfig (GAP #2 Fix)

For each entity in `entities.json > entities[]`:
- IF entity has `personRoleConfig` property:
  - Copy verbatim into handoff entity data

### 6. Generate SeedData Core/Business (GAP #3 Fix)

Generate seed data from entities and permissions:

Each seedData entry MUST include a `category` field:

```json
{
  "path": "src/Infrastructure/Persistence/Seeding/Data/NavigationApplicationSeedData.cs",
  "type": "SeedData",
  "category": "core",
  "module": "shared"
}
```

- `category: "core"` -- Navigation, Permissions, Roles (mandatory infrastructure)
- `category: "business"` -- Domain-specific reference/lookup data

> **Reference:** Read `references/handoff-seeddata-generation.md` for complete core seed generation.

### 7. Map Entity to Domain File (GAP #4 Fix)

> **Reference:** Read `references/entity-domain-mapping.md` for complete mapping rules.

1:1 mapping from BA entity to Domain file:

| BA Element | Domain File Path |
|------------|-----------------|
| Entity | `src/Domain/Entities/{App}/{Module}/{EntityName}.cs` |
| ValueObject | `src/Domain/{Module}/ValueObjects/{VOName}.cs` |
| Enum | `src/Domain/{Module}/Enums/{EnumName}.cs` |

### 8. Add Dependencies per File Entry (GAP #7 Fix)

Each file entry includes `dependencies[]` ordered by layer:

| Layer | Dependencies |
|-------|-------------|
| domain | `[]` (no dependencies) |
| infrastructure | `["domain"]` |
| application | `["domain"]` |
| api | `["application"]` |
| seedData | `["domain", "infrastructure"]` |
| frontend | `["api"]` |
| tests | `["domain", "application", "infrastructure", "api"]` |
| documentation | `[]` |

### 9. Write Handoff to Feature.json

```
FOR i = 0 to modules.length-1:
  1. moduleCode = modules[i].code
  2. Build handoff payload:
     - complexity (from step 1)
     - filesToCreate (full 8-category structure, filtered for this module)
     - brToCodeMapping (from step 4)
     - apiEndpointSummary (from step 2)
     - prdFile: ".ralph/prd-{moduleCode}.json"
     - totalFiles: count from filesToCreate
     - totalTasks: estimated from complexity
     - handedOffAt: ISO timestamp
  3. Propagate featureDescription from app-level index.json:
     ```javascript
     handoffPayload.featureDescription = appIndex.metadata.featureDescription || null;
     ```
  4. Write via ba-writer.enrichModuleHandoff({ moduleFeatureId, handoffData })
  5. Display: "handoff {i+1}/{N}: {moduleCode} ({fileCount} files)"
```

### 10. POST-CHECK Per Module (BLOCKING)

Run the **output** AC script from `references/acceptance-criteria.md`:

```bash
MODULE_JSON="{module_index_json_path}"
node -e "
// ... (output AC script from references/acceptance-criteria.md)
" "$MODULE_JSON"
```

For each module, verify:

```javascript
const handoff = moduleFeature.handoff;

// 1. Handoff not empty
if (!handoff || Object.keys(handoff).length === 0) {
  BLOCKING_ERROR("Module {moduleCode}: handoff is empty");
}

// 2. All 8 categories present (AC-08)
const categories = ['domain', 'application', 'infrastructure', 'api', 'frontend', 'seedData', 'tests', 'documentation'];
const missing = categories.filter(cat => !handoff.filesToCreate[cat]);
if (missing.length > 0) {
  BLOCKING_ERROR("Module {moduleCode}: missing categories: " + missing.join(', '));
}

// 3. BR-to-code mapping non-empty (AC-09)
if (!handoff.brToCodeMapping || handoff.brToCodeMapping.length === 0) {
  BLOCKING_ERROR("Module {moduleCode}: brToCodeMapping is empty");
}

// 4. Display pass
console.log("POST-CHECK PASS: {moduleCode} -- 8 categories, {brCount} BRs mapped");
```

---

## NEXT STEP

Load: `steps/step-02-export.md`
