Navigation / Main Menu API#

Menu tree the client renders, filtered by the caller’s mod_admin claims.

  • Endpoint: GET /api/v1/navigation/menu
  • Auth: [Authorize]
  • Jira: BFC-25
  • ADR: 0005
  • Legacy source: MnxModule, MnxModuleRelationship

Flow#

flowchart TD
    Req[GET /navigation/menu] --> Svc[NavigationService]
    Svc --> All[Load MnxModule<br/>WHERE IsModuleShow=true]
    Svc --> Rel[Load MnxModuleRelationship]
    Svc --> Claims[Extract mod_admin claims from JWT]
    All & Rel & Claims --> Filter[Filter each module]
    Filter --> D1{IsPermission=true?}
    D1 -->|no| Keep[Keep — public nav]
    D1 -->|yes| D2{mod_admin contains ModuleName?}
    D2 -->|yes| Keep
    D2 -->|no| Drop[Drop + drop descendants]
    Keep --> Sort[Order by:<br/>Relationship.ModuleOrder,<br/>RenderNumber,<br/>ModuleName]
    Sort --> Resp[200 - flat list with ParentId]

Response shape#

Flat list with parentId — the client rebuilds the tree (plays nicer with virtualization and lazy-expansion).

{
  "success": true,
  "data": [
    { "id": 1, "parentId": null, "name": "SGA", "order": 10, "path": "/sga" },
    { "id": 5, "parentId": 1,   "name": "Chart of Accounts", "order": 20, "path": "/sga/coa" }
  ]
}

Rules#

  • IsModuleShow=false → never returned, regardless of claims.
  • IsPermission=true + no matching mod_admin claim → dropped (and descendants dropped).
  • CompanyAdmin was already expanded to all six module keys at login (see Auth § Rules), so full-org admins see everything without special-casing.
  • Ordering: MnxModuleRelationship.ModuleOrder wins over MnxModule.RenderNumber, ties broken by ModuleName.