---
title: Resolve a user's authorized menu items
summary: Resolves the complete set of menu items a specific user may reach by combining group-granted items, unsecured items, and the user's own favorites into a single read-only, denormalized projection. This is the query that backs every subsequent page-authorization check in the requesting web session.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-08-17
library: SAIF.Business.Menu
reference_type: package
operation_id: OP-MENU-01
trigger: "`NavigationContext.New(user)` — once per web session"
---

# Resolve a user's authorized menu items

Resolves the complete set of menu items a specific user may reach by combining group-granted items, unsecured items, and the user's own favorites into a single read-only, denormalized projection. This is the query that backs every subsequent page-authorization check in the requesting web session.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-MENU-01 |
| **Trigger** | `NavigationContext.New(user)` — once per web session |
| **Inputs** | `IDataPortalInfo`, menu user ID (trimmed, upper-cased by the caller) |
| **Outputs** | Populated `clsMenuAuthorizedItemCollection` |
| **Primary components** | `clsMenuAuthorizedItemCollection.GetMenuAuthorizedItems(inDataportal, inMenuUser)` |
| **Entry point** | `SAIF.Business.Menu/clsMenuAuthorizedItemCollection.vb` |

## Steps

1. Construct `Criteria(dpi, menuUser)` and call `dpi.DataAccessLayer.RetrieveObject`.
2. `BeforeRetrieve` creates a data request with ID `BOC.RetrieveSQL`. If `MyCriteria.MenuUser` is non-empty, use `RetrieveSQL` ([SQL-015](../sql/SQL-015-retrieve-authorized-menu-items-for-user.md)) and `AddParm("MenuUser", value, 30)`; otherwise use `RetrieveAllSQL` ([SQL-016](../sql/SQL-016-retrieve-all-authorized-menu-items.md), no parameter). ([BR-MENU-001](../business-rules.md#br-menu-001-scoped-vs-unfiltered-retrieval))
3. The framework executes the three-branch `UNION`:
   - **Branch 1 (group-granted)** — `SELECT DISTINCT` items joined item → security → security-user → page → application → category, matching `upper(USR.SECURITY_GROUP_TXT) = upper(SEC.SECURITY_GROUP_TXT)` and `USR.MENU_USER = :MenuUser`, marked `UnsecuredFlag = 'N'`, `FavoriteFlag = 'N'`. ([BR-MENU-002](../business-rules.md#br-menu-002-group-granted-authorization), [BR-MENU-003](../business-rules.md#br-menu-003-case-insensitive-group-matching); tables [MENU_ITEM](../database-tables.md#menu_item), [MENU_SECURITY](../database-tables.md#menu_security), [MENU_SECURITY_USER](../database-tables.md#menu_security_user), [MENU_PAGE](../database-tables.md#menu_page), [BUSONLINE_APPS_CODE](../database-tables.md#busonline_apps_code), [MENU_CATEGORY_CODE](../database-tables.md#menu_category_code))
   - **Branch 2 (unsecured)** — items with `NOT EXISTS (SELECT 1 FROM menu_security …)`, marked `UnsecuredFlag = 'Y'`, with `:MenuUser` echoed as the owner and a `NULL` employee ID. ([BR-MENU-004](../business-rules.md#br-menu-004-unsecured-items-open-to-all))
   - **Branch 3 (favorites)** — items joined to [MENU_FAVORITE](../database-tables.md#menu_favorite) where `FAV.MENU_USER = :MenuUser` and `FAV.ITEM_INACTIVE_DATE IS NULL`, ordered by `FAV.MENU_ORDER_NUM`, marked `FavoriteFlag = 'Y'`. ([BR-MENU-005](../business-rules.md#br-menu-005-favorites-appear-in-the-authorized-set), [BR-MENU-006](../business-rules.md#br-menu-006-inactive-favorites-excluded))
4. `AfterRetrieve` casts the result to `IDataReader`, and for each row constructs a `clsMenuAuthorizedItem`, calls `Load` (which fills all 28 columns, builds a `Criteria`, and calls `MarkOld`), and adds it to the collection.
   - On failure: a missing or renamed column surfaces as a runtime error from the reader.*
5. The collection is returned to the caller and cached in web session by the MVC layer. ([BR-MENU-007](../business-rules.md#br-menu-007-authorized-items-are-read-only))

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
    Start([NavigationContext session start]) --> Criteria[Construct Criteria dpi, menuUser]
    Criteria --> Choice{MenuUser supplied?}
    Choice -->|Yes| Filtered[RetrieveSQL: three-branch UNION scoped to user]
    Choice -->|No| All[RetrieveAllSQL: three-branch UNION for all users]
    Filtered --> Load[AfterRetrieve: Load each clsMenuAuthorizedItem]
    All --> Load
    Load --> Cache([Return collection, cache in web session])
```

## Failure and edge-case behavior
- A missing or renamed column in the result set surfaces as a runtime error from `AfterRetrieve` rather than a handled business error.*
- Requesting an unknown `MenuUser` yields an empty collection (no rows satisfy any of the three UNION branches) rather than an error.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

## Sources
- SAIF.Business.Menu/clsMenuAuthorizedItemCollection.vb
