# SeedData Core Generation for Handoff

Complete reference for generating `seedDataCore` from module JSON files, application roles, and coverage matrix.

## Helper Functions

### PascalCase to Human Readable

```javascript
function toHumanReadable(pascalCase) {
  return pascalCase
    .replace(/([a-z])([A-Z])/g, '$1 $2')
    .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2');
}
```

### PascalCase to Kebab Case

```javascript
function toKebabCase(code) {
  return code
    .replace(/([a-z])([A-Z])/g, '$1-$2')
    .toLowerCase();
}
```

## SeedDataCore Template

```javascript
const appCode = master.metadata.application;
const appLabel = toHumanReadable(appCode);
const appDesc = master.cadrage?.problem?.split('.')[0] || `Gestion ${appLabel}`;
const lang = master.metadata.language || "fr";

const seedDataCore = {
  // Application-level navigation (MANDATORY — one entry per application)
  navigationApplications: (() => {
    if (workflow.mode === "project") {
      // Multi-app: one navigation entry per application
      return projectFeature.applications.map((app, idx) => {
        const appLabel = toHumanReadable(app.code);
        return {
          code: app.code.toLowerCase(),
          name: app.code,
          labels: {
            fr: lang === "fr" ? (app.name || appLabel) : appLabel,
            en: lang === "en" ? (app.name || appLabel) : appLabel,
            it: appLabel,
            de: appLabel
          },
          description: {
            fr: lang === "fr" ? (app.description || `Gestion ${appLabel}`) : `Gestion ${appLabel}`,
            en: lang === "en" ? (app.description || `${appLabel} management`) : `${appLabel} management`,
            it: `Gestione ${appLabel}`,
            de: `${appLabel} Verwaltung`
          },
          icon: app.icon || inferIconFromApplication({ metadata: { application: app.code } }) || "layout-grid",
          iconType: "lucide",
          route: `/${toKebabCase(app.code)}`,
          displayOrder: (idx + 1) * 10
        };
      });
    } else {
      // Single-app: one navigation entry
      return [{
        code: appCode.toLowerCase(),
        name: appCode,
        labels: {
          fr: lang === "fr" ? (master.cadrage?.applicationName || appLabel) : appLabel,
          en: lang === "en" ? (master.cadrage?.applicationName || appLabel) : appLabel,
          it: appLabel,
          de: appLabel
        },
        description: {
          fr: lang === "fr" ? appDesc : `Gestion ${appLabel}`,
          en: lang === "en" ? appDesc : `${appLabel} management`,
          it: `Gestione ${appLabel}`,
          de: `${appLabel} Verwaltung`
        },
        icon: inferIconFromApplication(master) || "layout-grid",
        iconType: "lucide",
        route: `/${toKebabCase(appCode)}`,
        displayOrder: 1
      }];
    }
  })(),

  navigationModules: (() => {
    if (workflow.mode === "project") {
      let order = 0;
      return projectFeature.applications.flatMap(app => {
        return (app.modules || []).map(m => ({
          code: m.code,
          applicationCode: app.code,
          label: m.name || m.code,
          description: m.description,
          icon: inferIconFromModule(m) || "folder",
          iconType: "lucide",
          route: `/${toKebabCase(app.code)}/${toKebabCase(m.code)}`,
          displayOrder: (++order) * 10
        }));
      });
    } else {
      return master.modules.map((m, i) => ({
        code: m.code,
        label: m.name || m.code,
        description: m.description,
        icon: inferIconFromModule(m) || "folder",
        iconType: "lucide",
        route: `/${toKebabCase(appCode)}/${toKebabCase(m.code)}`,
        displayOrder: (i + 1) * 10
      }));
    }
  })(),

  navigationSections: (() => {
    const buildSections = (modules, appCode) =>
      modules.flatMap(m =>
        (m.anticipatedSections || []).map((s, j) => ({
          moduleCode: m.code,
          code: s.code,
          label: s.description?.split(':')[0] || s.code,
          description: s.description || "",
          route: s.code === "list"
            ? `/${toKebabCase(appCode)}/${toKebabCase(m.code)}`
            : s.code === "detail"
              ? `/${toKebabCase(appCode)}/${toKebabCase(m.code)}/:id`
              : `/${toKebabCase(appCode)}/${toKebabCase(m.code)}/${toKebabCase(s.code)}`,
          displayOrder: (j + 1) * 10,
          navigation: s.code === "detail" ? "hidden" : "visible",
          // Propagate permissionMode for section-level permission generation
          permissionMode: s.permissionMode || (s.code === "detail" ? "inherit" : s.code === "dashboard" ? "read-only" : "crud")
        }))
      );

    if (workflow.mode === "project") {
      return projectFeature.applications.flatMap(app =>
        buildSections(app.modules || [], app.code)
      );
    } else {
      return buildSections(master.modules, appCode);
    }
  })(),

  navigationResources: master.cadrage.coverageMatrix
    .filter(cm => cm.module && cm.anticipatedResources?.length > 0)
    .flatMap(cm =>
      cm.anticipatedResources.map((r, k) => ({
        moduleCode: cm.module,
        sectionCode: cm.anticipatedSections?.[0] || "list",
        code: r,
        label: r.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase()),
        displayOrder: (k + 1) * 10
      }))
    ),

  navigationTranslations: master.modules.flatMap(m => {
    const langs = ["fr", "en", "it", "de"];
    return langs.map(lang => ({
      moduleCode: m.code,
      language: lang,
      label: lang === master.metadata.language ? (m.name || m.code) : m.code,
      description: lang === master.metadata.language ? m.description : ""
    }));
  }),

  permissions: (() => {
    const buildPermissions = (modules, appCode) =>
      modules.flatMap(m => {
        const basePath = `${toKebabCase(appCode)}.${toKebabCase(m.code)}`;
        const actions = ['read', 'create', 'update', 'delete'];
        return [
          { path: `${basePath}.*`, action: '*', description: `Full ${m.name || m.code} access` },
          ...actions.map(action => ({
            path: `${basePath}.${action}`,
            action: action,
            description: `${action.charAt(0).toUpperCase() + action.slice(1)} ${m.name || m.code}`
          }))
        ];
      });

    if (workflow.mode === "project") {
      return projectFeature.applications.flatMap(app =>
        buildPermissions(app.modules || [], app.code)
      );
    } else {
      return buildPermissions(master.modules, appCode);
    }
  })(),

  rolePermissions: (() => {
    const buildRolePermissions = (roles, modules, appCode) =>
      roles.map(role => ({
        role: role.role,
        level: role.level,
        permissions: modules.map(m => `${toKebabCase(appCode)}.${toKebabCase(m.code)}.${
          role.level === 'admin' ? '*' :
          role.level === 'manager' ? 'read,create,update' :
          role.level === 'contributor' ? 'read,create' : 'read'
        }`)
      }));

    if (workflow.mode === "project") {
      return projectFeature.applications.flatMap(app =>
        buildRolePermissions(app.applicationRoles || [], app.modules || [], app.code)
      );
    } else {
      return buildRolePermissions(master.cadrage.applicationRoles, master.modules, appCode);
    }
  })(),

  permissionConstants: (() => {
    const buildConstants = (modules, appCode) =>
      modules.flatMap(m =>
        ['Read', 'Create', 'Update', 'Delete', 'Validate', 'Export'].map(action => ({
          module: m.code,
          application: appCode,
          action: action,
          constant: `${appCode}${m.code}${action}`,
          path: `${toKebabCase(appCode)}.${toKebabCase(m.code)}.${action.toLowerCase()}`
        }))
      );

    if (workflow.mode === "project") {
      return projectFeature.applications.flatMap(app =>
        buildConstants(app.modules || [], app.code)
      );
    } else {
      return buildConstants(master.modules, appCode);
    }
  })()
};
```

## Icon Inference Functions

### Application Level

```javascript
function inferIconFromApplication(master) {
  const appLC = (master.metadata.application || '').toLowerCase();
  const iconMap = {
    'humanresource': 'users', 'rh': 'users', 'hr': 'users', 'personnel': 'users',
    'sales': 'shopping-cart', 'vente': 'shopping-cart', 'commerce': 'shopping-cart',
    'finance': 'wallet', 'comptabilite': 'calculator', 'accounting': 'calculator',
    'inventory': 'warehouse', 'stock': 'package', 'logistic': 'truck',
    'crm': 'building-2', 'customer': 'building', 'client': 'building-2',
    'project': 'folder-kanban', 'task': 'check-square', 'gestion': 'layout-grid',
    'admin': 'shield', 'support': 'headphones', 'maintenance': 'wrench',
    'production': 'factory', 'quality': 'badge-check', 'document': 'file-text',
    'fleet': 'car', 'vehicle': 'car', 'transport': 'truck',
    'education': 'graduation-cap', 'formation': 'graduation-cap', 'training': 'graduation-cap'
  };
  for (const [keyword, icon] of Object.entries(iconMap)) {
    if (appLC.includes(keyword)) return icon;
  }
  return "layout-grid";  // fallback — NEVER null
}
```

### Module Level

```javascript
function inferIconFromModule(module) {
  const codeLC = module.code.toLowerCase();
  const iconMap = {
    'employee': 'users', 'staff': 'users', 'personnel': 'users', 'user': 'users',
    'project': 'folder-kanban', 'task': 'check-square', 'work': 'briefcase',
    'time': 'clock', 'schedule': 'calendar', 'planning': 'calendar-days',
    'absence': 'calendar-off', 'leave': 'calendar-off', 'vacation': 'palm-tree',
    'finance': 'wallet', 'billing': 'receipt', 'invoice': 'file-text',
    'inventory': 'warehouse', 'stock': 'package', 'product': 'shopping-bag',
    'customer': 'building', 'client': 'building-2', 'contact': 'contact',
    'report': 'bar-chart', 'dashboard': 'layout-dashboard', 'analytics': 'trending-up',
    'document': 'file-text', 'notification': 'bell', 'setting': 'settings',
    'order': 'shopping-cart', 'vehicle': 'car', 'maintenance': 'wrench',
    'audit': 'shield-check', 'workflow': 'git-branch', 'approval': 'check-circle'
  };
  for (const [keyword, icon] of Object.entries(iconMap)) {
    if (codeLC.includes(keyword)) return icon;
  }
  return "folder";  // fallback — NEVER null
}
```

## POST-CHECK (BLOCKING for icons/application, warning for counts)

```javascript
IF !seedDataCore.navigationApplications || seedDataCore.navigationApplications.length === 0:
  BLOCKING ERROR: "navigationApplications is empty — Application navigation will NOT be seeded. Menu will show (nothing) → Modules."
IF seedDataCore.navigationApplications[0].icon === null || seedDataCore.navigationApplications[0].icon === undefined:
  BLOCKING ERROR: "Application icon is null — business-analyse-develop will render empty navigation"
IF !seedDataCore.navigationApplications[0].labels?.fr || !seedDataCore.navigationApplications[0].labels?.en:
  BLOCKING ERROR: "Application labels missing fr/en — translations will fail"
IF seedDataCore.navigationModules.length !== master.modules.length:
  WARNING: seedDataCore has ${seedDataCore.navigationModules.length} nav modules but ${master.modules.length} modules exist
IF seedDataCore.permissions.length === 0:
  WARNING: seedDataCore has 0 permissions — applicationRoles may be missing
IF seedDataCore.navigationModules.some(m => !m.icon || m.icon === null):
  BLOCKING ERROR: "Navigation modules with null icons detected — business-analyse-develop will render empty navigation"
  → Fix: Re-run inferIconFromModule() for modules with null icons
IF seedDataCore.navigationSections.length === 0:
  WARNING: "0 navigation sections — every module should have at least 1 section (e.g., 'list')"
```

## Writing to index.json

```javascript
ba-writer.enrichSection({
  featureId: {feature_id},
  section: "generated seedData (core)",
  data: seedDataCore
})
```
