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#
takeclamped[1, 200]. Per-type cap is 15 (matches legacyTOP 15).qrequired + max 200 chars — empty or oversized → 400.MnxModule.IsModuleShow=falsenever appears in module results, regardless ofqmatch.typesfilter is comma-separated. Omit → search all three domains.- Flat response with
typediscriminator — client decides how to render each row.