---
title: SAIF.Business.Menu business rules
summary: Enumerated business rules with per-rule trigger, enforcement, and outcomes.
status: draft
owner: SAIF
last_reviewed: 2026-07-24
library: SAIF.Business.Menu
reference_type: package
---

# SAIF.Business.Menu business rules

This page captures business rules enforced by this library.

## BR-MNU-01: Menu item visibility determined by security-group or user mapping

| Field | Value |
| --- | --- |
| **Statement** | A menu item's visibility to a user is determined by whether the user's `SecurityGroup` (via `clsMenuSecurityUser`) or explicit user mapping matches a `clsMenuSecurity` record tied to that `MenuItemSeqNum`; items with no `MENU_SECURITY` record are treated as unsecured and visible to all users.** |
| **Trigger** | A presentation-layer or menu-rendering consumer requests the authorized menu-item list for a user. |
| **Enforcement** | Data is gathered by [SQL-015](sql/SQL-015-saif-business-menu.md) (all-user UNION query) or [SQL-016](sql/SQL-016-saif-business-menu.md) (per-user UNION query) in `clsMenuAuthorizedItemCollection`. The actual authorization gating decision is performed by the consuming presentation layer using this data, not within this library.** |
| **Outcome** | The authorized-item collection returned to the caller includes only items matching the user's security group, plus items with no security record (flagged `UnsecuredFlag = 'Y'`), plus the user's active favorites. |
| **Tables** | [MENU_SECURITY](database-tables.md#menu-security), [MENU_SECURITY_USER](database-tables.md#menu-security-user), [MENU_ITEM](database-tables.md#menu-item) |
| **SQL** | [SQL-015](sql/SQL-015-saif-business-menu.md), [SQL-016](sql/SQL-016-saif-business-menu.md) |
| **Confidence** | Mixed (includes unknown elements)** |
| **Source** | `Business\SAIF.Business.Menu\clsMenuAuthorizedItemCollection.vb`, `Business\SAIF.Business.Menu\clsMenuSecurity.vb` |

---

## BR-MNU-02: DML row-count enforcement

| Field | Value |
| --- | --- |
| **Statement** | Every insert, update, or delete operation must affect exactly one row. If `RowsAffected <> 1`, an error is immediately raised and the operation is considered failed. |
| **Trigger** | `AfterInsert`, `AfterUpdate`, or `AfterDelete` lifecycle method is called following any DML SQL execution. |
| **Enforcement** | Each `After*` method checks `RowsAffected <> 1` and calls `AddErrorMessage("InsertError"/"UpdateError"/"DeleteError", ...)`. Applies to all 7 tables: `BUSONLINE_APPS_CODE`, `MENU_CATEGORY_CODE`, `MENU_FAVORITE`, `MENU_ITEM`, `MENU_PAGE`, `MENU_SECURITY`, `MENU_SECURITY_USER`. |
| **Outcome** | Failed operations add an error message to the business object; the save is rejected. Successful operations call `MarkOld()` (insert/update) or `MarkNew()` (delete). |
| **Tables** | [BUSONLINE_APPS_CODE](database-tables.md#busonline-apps-code), [MENU_CATEGORY_CODE](database-tables.md#menu-category-code), [MENU_FAVORITE](database-tables.md#menu-favorite), [MENU_ITEM](database-tables.md#menu-item), [MENU_PAGE](database-tables.md#menu-page), [MENU_SECURITY](database-tables.md#menu-security), [MENU_SECURITY_USER](database-tables.md#menu-security-user) |
| **SQL** | [SQL-005](sql/SQL-005-saif-business-menu.md), [SQL-006](sql/SQL-006-saif-business-menu.md), [SQL-007](sql/SQL-007-saif-business-menu.md), [SQL-008](sql/SQL-008-saif-business-menu.md), [SQL-009](sql/SQL-009-saif-business-menu.md), [SQL-010](sql/SQL-010-saif-business-menu.md), [SQL-011](sql/SQL-011-saif-business-menu.md), [SQL-031](sql/SQL-031-saif-business-menu.md)–[SQL-044](sql/SQL-044-saif-business-menu.md) |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Menu\clsApplicationCode.vb`, `Business\SAIF.Business.Menu\clsMenuCategoryCode.vb`, `Business\SAIF.Business.Menu\clsMenuFavorite.vb`, `Business\SAIF.Business.Menu\clsMenuItem.vb`, `Business\SAIF.Business.Menu\clsMenuPage.vb`, `Business\SAIF.Business.Menu\clsMenuSecurity.vb`, `Business\SAIF.Business.Menu\clsMenuSecurityUser.vb` |

---

## BR-MNU-03: Active application code filtering

| Field | Value |
| --- | --- |
| **Statement** | When retrieving active application codes, only records where `NVL(ACTIVE_CODE, 'Y') = 'Y'` are returned. Records with a null `ACTIVE_CODE` are treated as active by default. |
| **Trigger** | `clsApplicationCodeCollection.BeforeRetrieve` is called with `ActiveOnly = True`. |
| **Enforcement** | [SQL-013](sql/SQL-013-saif-business-menu.md) applies the `WHERE NVL(ACTIVE_CODE, 'Y') = 'Y'` predicate. |
| **Outcome** | The collection contains only active application codes. Inactive codes are excluded. |
| **Tables** | [BUSONLINE_APPS_CODE](database-tables.md#busonline-apps-code) |
| **SQL** | [SQL-013](sql/SQL-013-saif-business-menu.md) |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Menu\clsApplicationCodeCollection.vb` |

---

## BR-MNU-04: Case-insensitive security-group matching

| Field | Value |
| --- | --- |
| **Statement** | Security group comparisons between `MENU_SECURITY.SECURITY_GROUP_TXT` and `MENU_SECURITY_USER.SECURITY_GROUP_TXT` are performed case-insensitively using `UPPER()`. |
| **Trigger** | `clsMenuAuthorizedItemCollection.BeforeRetrieve` executes either [SQL-015](sql/SQL-015-saif-business-menu.md) or [SQL-016](sql/SQL-016-saif-business-menu.md). |
| **Enforcement** | Both UNION queries apply `UPPER(USR.SECURITY_GROUP_TXT) = UPPER(SEC.SECURITY_GROUP_TXT)` in the join predicate. |
| **Outcome** | Users are matched to security groups regardless of the case in which the `SecurityGroup` string was stored. |
| **Tables** | [MENU_SECURITY](database-tables.md#menu-security), [MENU_SECURITY_USER](database-tables.md#menu-security-user) |
| **SQL** | [SQL-015](sql/SQL-015-saif-business-menu.md), [SQL-016](sql/SQL-016-saif-business-menu.md) |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Menu\clsMenuAuthorizedItemCollection.vb` |

---

## BR-MNU-05: Favorite active-status enforcement

| Field | Value |
| --- | --- |
| **Statement** | Only favorites with a null `ITEM_INACTIVE_DATE` are included in the authorized-item projection for a specific user. |
| **Trigger** | [SQL-016](sql/SQL-016-saif-business-menu.md) is executed with a non-empty `MenuUser` value. |
| **Enforcement** | The favorites leg of the UNION in [SQL-016](sql/SQL-016-saif-business-menu.md) includes the predicate `FAV.ITEM_INACTIVE_DATE IS NULL`. |
| **Outcome** | Deactivated favorites (with a non-null `ITEM_INACTIVE_DATE`) are excluded from the user's authorized menu view. |
| **Tables** | [MENU_FAVORITE](database-tables.md#menu-favorite) |
| **SQL** | [SQL-016](sql/SQL-016-saif-business-menu.md) |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Menu\clsMenuAuthorizedItemCollection.vb` |

---

## Inherited business rules

`SAIF.Business.Menu` includes two framework-derived classes (`frameworkClassCount: 2` per `dependency-resolution.json`). The BOF framework base classes (`clsBusinessBase`, `clsBusinessCollection(Of T)`) define lifecycle and validation contracts that all BOF business objects inherit. Specific inherited rule details could not be enumerated: the Legends CLI has no indexed content for BOF framework base classes in this run.*

---

## Notes
- [BR-MNU-01](#br-mnu-01-menu-item-visibility-determined-by-security-group-or-user-mapping) describes a data model enforced in the database layer; the authorization gating decision itself resides in a consuming presentation-layer component outside this library's scope.
- The `clsMenuSecurityUserCollection.BeforeRetrieve` method appears to invert its bind behavior: `retrieveForUserSQL` ([SQL-029](sql/SQL-029-saif-business-menu.md)) is selected without `AddParm("MenuUser", ...)`, while the unfiltered `RetrieveSQL` ([SQL-030](sql/SQL-030-saif-business-menu.md)) branch adds `:MenuUser` even though the SQL text has no bind variable. This is a potential source defect noted in the DB analysis.*


## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Operations and processes](operations-processes.md)
- [Database tables](database-tables.md)
- [SQL catalog](sql/index.md)
- [API reference](api/index.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with `**` could not be confirmed; treat as unknown until verified.

## Sources
- `Business\SAIF.Business.Menu\clsApplicationCode.vb`
- `Business\SAIF.Business.Menu\clsApplicationCodeCollection.vb`
- `Business\SAIF.Business.Menu\clsMenuAuthorizedItemCollection.vb`
- `Business\SAIF.Business.Menu\clsMenuCategoryCode.vb`
- `Business\SAIF.Business.Menu\clsMenuFavorite.vb`
- `Business\SAIF.Business.Menu\clsMenuItem.vb`
- `Business\SAIF.Business.Menu\clsMenuPage.vb`
- `Business\SAIF.Business.Menu\clsMenuSecurity.vb`
- `Business\SAIF.Business.Menu\clsMenuSecurityUser.vb`
- `Business\SAIF.Business.Menu\clsMenuSecurityUserCollection.vb`
