---
title: SAIF.Business.View.Policy architecture
summary: Architectural responsibilities, boundaries, and interaction patterns for the read-optimized policy view/aggregate library.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-31
library: SAIF.Business.View.Policy
reference_type: package
---

# SAIF.Business.View.Policy architecture

SAIF.Business.View.Policy is a business view-layer library that provides read-optimized ("view") policy header and detail aggregates for claim- and policy-facing consumers. It sits above the SAIF BOF framework data-portal abstraction and below application/orchestration packages such as `SAIF.Application.Policy`. The library defines no write path; every type is retrieved through a `Shared` factory method and populated via the standard BOF data-portal lifecycle.

## Responsibilities
- Assemble `clsPolicyData`, the central read-only policy header aggregate (identity, status, agency, dates, financial flags, associations, periods, team assignments, addresses), lazily composing child aggregates on first property access.
- Resolve policy associations through two coexisting subsystems: the legacy inline-SQL `PolicyAssociationList` and the newer code-table-driven `clsAssociationTypeCode` / factory model, the latter being the migration target (many `clsPolicyData` affiliate members are marked `Obsolete`).
- Provide data-level policy authorization via `clsPolicySecurity.IsPolicyValidForUser`, deciding whether the current security principal may view a given policy, and building the principal's permitted policy list (`PolicyList`).
- Supply supporting policy aggregates: agency/agent contact (`clsAgency`), addresses (`clsPolicyAddress`), team assignments (`clsTeamAssignment(Collection)`), policy periods (`clsPolicyPeriod(Collection)`), trading-as names, and non-employer accounts.

## Component boundaries
- `clsPolicyData` / `Criteria`: policy header + detail retrieval boundary; owns lazy composition of all child aggregates and the obsolete/legacy affiliate accessors.
- `clsPolicySecurity`: data-level authorization boundary; the only type in the library that opens its own SQL Server connection (the BDS/claim-profile database), separate from the caller-supplied Oracle `IDataPortalInfo`.
- `PolicyAssociationList` (legacy) vs. `clsAssociationTypeCode` / `clsPolicyHeaderAssociationFactory` / `clsAssociationTypeFactory` (code-table-driven): two parallel association-resolution boundaries kept for backward compatibility during migration.
- `clsAgency`, `clsPolicyAddress`, `clsTeamAssignment(Collection)`, `clsPolicyPeriod(Collection)`, `clsTradingAs(Collection)`, `clsNonEmployerAccount`: independent read-only aggregate boundaries, each following the same `Criteria` → `BeforeRetrieve` → `AfterRetrieve` shape.
- `Institutions` typed `DataSet`: generated banking-institution dataset with no hand-written behavior; not part of the business-object surface.
- The tables and statements behind these boundaries are cataloged on the [Database tables](database-tables.md) and [SQL catalog](sql/index.md) pages, and the association source procedures on the [Procedures](procedures/index.md) page.

## Interaction model
- Every persistent type follows the canonical BOF shape: a business object (`clsBusinessBase`†) or collection (`clsBusinessCollectionBase`† / `clsBusinessCollection(Of T)`†), paired with a nested `Criteria` class implementing `IBusinessCriteria`† that holds the five SQL properties (`CreateSQL`, `RetrieveSQL`, `InsertSQL`, `UpdateSQL`, `DeleteSQL`) plus auxiliary named SQL properties.
- `BeforeRetrieve` builds an `IDataRequest` (stored-procedure command type, REF CURSOR output parameter `recordset`); `AfterRetrieve` reads the result via `clsSAIFDataReader`/`clsResultSet`, fills the object, and calls `MarkOld()`. Public `Shared` factory functions (`GetXxx(dpi, key)`) are the only sanctioned construction path; constructors are `Friend`/`Protected Friend`.
- Callers supply an `IDataPortalInfo` (Oracle) for nearly all retrieval; `clsPolicySecurity` additionally constructs its own SQL Server `clsSQLDataLayer` from three environment settings (`BDS_USER`, `bdsDatabase`, `BDS_DATABASENAME`, described on the [Configuration](configuration.md) page) for the second, non-Oracle "BDS" claim-profile data store — a connection that bypasses the standard `DbConnectionManager` resolution path and does not appear in framework-level connection inventories.*
- Authorization decisions are consumed by upstream orchestration (e.g. `SAIF.Application.Policy.PolicyAppManager.UserCanAccessPolicy`, which delegates to `clsPolicySecurity.IsPolicyValidForUser`); this library has no HTTP surface or UI of its own — the AD resource gate `SAIFpolicyInfo` and the eight programmatic enforcement points (EP-01 to EP-08) it anchors are documented in full on the [Security and authorization](security-authorization.md) page.
- Dependency direction is strictly downward: this library depends on framework/business packages and exposes no service host back to them.

## Architecture diagram
The following diagram shows the high-level component interactions between this library, its data stores, and its consumers.

```mermaid
flowchart TD
    Caller[Caller<br>e.g. SAIF.Application.Policy] -->|IDataPortalInfo, PolicyNum| PolicyData[clsPolicyData]
    PolicyData --> Criteria[Criteria: IBusinessCriteria†]
    PolicyData -->|lazy access| Agency[clsAgency]
    PolicyData -->|lazy access| Addresses[clsPolicyAddress]
    PolicyData -->|lazy access| Periods[clsPolicyPeriodCollection]
    PolicyData -->|lazy access| Teams[clsTeamAssignmentCollection]
    PolicyData -->|lazy access| Assoc[Associations subsystem]
    Assoc --> Legacy[PolicyAssociationList<br>legacy inline SQL]
    Assoc --> CodeTable[clsAssociationTypeCode /<br>clsPolicyHeaderAssociationFactory]
    Caller -->|authorize policy| PolicySecurity[clsPolicySecurity]
    PolicySecurity -->|SAIFpolicyInfo gate| AD[AD authorization resource]
    PolicySecurity -->|GEN/BDS lookups| SqlServer[(SQL Server<br>BDS claim-profile DB)]
    PolicyData -->|stored procedures| Oracle[(Oracle<br>policy portal)]
    Criteria -.->|base type| Framework[SAIF.BOF.Business†<br>clsBusinessBase / clsBusinessCollectionBase]
```

## Sequence diagram
The following diagram shows the primary retrieve-and-authorize sequence for a policy view request.

```mermaid
sequenceDiagram
    participant Caller
    participant PolicyData as clsPolicyData
    participant Security as clsPolicySecurity
    participant Oracle as Oracle portal
    participant SqlServer as SQL Server (BDS)
    Caller->>PolicyData: GetPolicyData(dpi, policyNum, userAccessLevel)
    PolicyData->>Oracle: BeforeRetrieve / RetrieveObject (pk73094_policy_data.getpolicy)
    Oracle-->>PolicyData: AfterRetrieve (Fill + MarkOld)
    Caller->>Security: IsPolicyValidForUser(PolicyData)
    Security->>Security: Check SAIFpolicyInfo AD gate
    Security->>SqlServer: cp_policy_in_group / cp_get_agent_online_policy_list (user-type branch)
    SqlServer-->>Security: role-specific access result
    Security-->>Caller: Boolean access decision
```

## Design constraints
- Strictly read-only: every `Criteria.CreateSQL`/`InsertSQL`/`UpdateSQL`/`DeleteSQL` returns empty or throws; no write path exists in this library.
- Two association-resolution generations coexist in production; new consumers should prefer the code-table-driven model since the legacy affiliate accessors on `clsPolicyData` are marked `Obsolete`.
- The SQL Server BDS connection is built from three environment settings with inconsistent key-casing (`BDS_USER`, `BDS_DATABASENAME` upper snake case vs. `bdsDatabase` camelCase) and no password setting is read locally, implying integrated/trusted authentication resolved inside `clsSQLDataLayer`.*
- The `SAIFpolicyInfo` AD gate is evaluated before all other authorization checks and denies access unconditionally when absent, even for user types that would otherwise qualify; the intended population for this gate was never settled by the original authors (source `TODO` comment).*
- Lazy composition means a single `clsPolicyData` read can trigger many additional data-portal round trips (one per child aggregate on first access); the multi-policy overload of `GetPolicyData` performs one round trip per policy number with no batching.
- `clsAddress`† (base of `clsPolicyAddress`) could not be resolved against the indexed framework documentation in this run; its inherited behavior is unknown and should be verified directly against `SAIF.BOF.Business` source or updated framework documentation.**

> **Note:** Statements marked with `†` are derived from dependency library documentation via the Legends CLI. Statements marked with `*` were inferred from code structure or contextual evidence. Statements marked with `**` could not be confirmed; treat as unknown until verified.

## Related documentation

- [Index](index.md)
- [Overview](overview.md)
- [Dependencies](dependencies.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Security and authorization](security-authorization.md)
- [Database tables](database-tables.md)
- [SQL catalog](sql/index.md)
- [Procedures](procedures/index.md)
- [API reference](api/index.md)
- [Configuration](configuration.md)

## Sources

- `Business/SAIF.Business.View.Policy/clsPolicyData.vb`
- `Business/SAIF.Business.View.Policy/clsPolicySecurity.vb`
- `Business/SAIF.Business.View.Policy/PolicyAssociations.vb`
- `Business/SAIF.Business.View.Policy/clsAgency.vb`
- `Business/SAIF.Business.View.Policy/clsPolicyAddress.vb`
- `Business/SAIF.Business.View.Policy/clsPolicyPeriodCollection.vb`
- `Business/SAIF.Business.View.Policy/clsTeamAssignmentCollection.vb`
- `Business/SAIF.Business.View.Policy/Associations/clsAssociationTypeCode.vb`
- `Business/SAIF.Business.View.Policy/Associations/clsPolicyAssociationFactory.vb`
- `Business/SAIF.Business.View.Policy/app.config`
- `Business/SAIF.Business.View.Policy/SAIF.BOF.Business.View.Policy.vbproj`
