Global Search API#

Cross-domain lookup over users, groups, and modules. Reimplements the intent of the legacy MnxSearchView* stored procedures in LINQ against the already-mapped entities — the legacy SPs use table-valued parameters and one is dead code.

  • Endpoint: GET /api/v1/search?q=<term>&types=user,group,module&take=50
  • Auth: [Authorize]
  • Jira: BFC-24
  • Legacy source: LINQ over AspnetUsers + AspnetProfiles, AspmnxGroups, MnxModules

Flow#

flowchart LR
    Req[GET /search?q,types,take] --> Val[Validate]
    Val --> B1{q empty?}
    B1 -->|yes| R400a[400]
    Val --> B2{q over 200 chars?}
    B2 -->|yes| R400b[400]
    Val --> Svc[SearchService]
    Svc --> Wanted{types filter}
    Wanted -->|user| U[Query users<br/>LIKE %term% on Username/First/Last<br/>TOP 15]
    Wanted -->|group| G[Query aspmnx_Groups<br/>LIKE %term% on GroupName<br/>TOP 15]
    Wanted -->|module| M[Query MnxModule<br/>WHERE IsModuleShow=true<br/>LIKE %term% on Name/Desc/Abbrev<br/>TOP 15]
    U & G & M --> Merge[Merge + take up to 200]
    Merge --> Resp[200 - flat list with Type discriminator]

Response shape#

{
  "success": true,
  "data": [
    { "type": "user",   "id": "<guid>", "title": "Alice Smith",    "subtitle": "Engineering", "link": "/admin/users/<guid>" },
    { "type": "group",  "id": "<guid>", "title": "Admins",         "subtitle": null,          "link": "/admin/groups/<guid>" },
    { "type": "module", "id": "1",      "title": "SGA",            "subtitle": "Accounting",  "link": "/sga" }
  ]
}

Rules#

  • take clamped [1, 200]. Per-type cap is 15 (matches legacy TOP 15).
  • q required + max 200 chars — empty or oversized → 400.
  • MnxModule.IsModuleShow=false never appears in module results, regardless of q match.
  • types filter is comma-separated. Omit → search all three domains.
  • Flat response with type discriminator — client decides how to render each row.