---
title: SAIF.Business.Policy.Agency architecture
summary: Architectural responsibilities, boundaries, and interaction patterns for SAIF.Business.Policy.Agency.
status: draft
owner: Technical Writer
last_reviewed: 2026-07-31
library: SAIF.Business.Policy.Agency
reference_type: package
---

# SAIF.Business.Policy.Agency architecture

`SAIF.Business.Policy.Agency` is a mid-tier BOF library that models the policy distribution channel. Its object graph centers on agencies and exposes contracts, office locations, and producers through retrieve-only business objects that execute Oracle reads through the framework data portal.

## Responsibilities
- Model agencies as the aggregate root for contracts, offices, and producers.
- Support both lazy navigation and bulk-load patterns for related data.
- Overlay office and producer semantics on the shared `AGENT` table.
- Keep persistence responsibilities out of this library by exposing retrieve-only criteria classes.

## Component boundaries
- `clsAgency` / `clsAgencyCollection`: agency retrieval, collection filtering, and bulk distribution of related producers and contracts.
- `clsAgencyContract` / `clsAgencyContractCollection`: contract retrieval plus code-to-enum translation for appointment and commission classifications.
- `clsAgencyOffice` / `clsAgencyOfficeCollection`: office-specific filtering over `AGENT` rows.
- `clsProducer` / `clsProducerCollection`: producer retrieval plus the direct `POLICY` agent-of-record lookup.
- `clsAgentUnderwritingData`: simple value carrier that packages producer, agency, license, FEID, and address data for callers.
- `Institutions`: generated reference-data dataset included in the assembly but not part of the core agency workflow.

## Interaction model
- Single-object retrieves build criteria, execute BOF `BeforeRetrieve` / `AfterRetrieve`, and hydrate one business object from a data reader.
- Collection retrieves execute one SQL statement, iterate the returned rows, and load each item into an in-memory BOF collection.
- `clsAgency.Contracts`, `clsAgency.Offices`, and `clsAgency.Producers` lazy-load related collections on first access.
- `clsAgencyCollection.RetrieveContracts()` and `RetrieveProducers()` issue one unfiltered child query each, then distribute rows to matching agencies in memory.
- `clsProducer.GetAgent()` bypasses the normal business-object criteria path and performs an application-layer scalar lookup against `POLICY`.

## Architecture diagram
The following diagram shows the aggregate root and the retrieve paths used to populate related collections.

```mermaid
flowchart TD
  Caller[Caller] --> AgencyColl[clsAgencyCollection]
  Caller --> Agency[clsAgency]
  AgencyColl --> Agency
  Agency -.lazy load.-> Contracts[clsAgencyContractCollection]
  Agency -.lazy load.-> Offices[clsAgencyOfficeCollection]
  Agency -.lazy load.-> Producers[clsProducerCollection]
  AgencyColl -.bulk load.-> Contracts
  AgencyColl -.bulk load.-> Producers
  Producers --> PolicyLookup[clsProducer.GetAgent]
  Agency --> Portal[IDataPortalInfo / BOF data portal]
  Contracts --> Portal
  Offices --> Portal
  Producers --> Portal
  PolicyLookup --> Portal
  Portal --> Oracle[(Oracle: AGENCY, AGENCY_CONTRACT, AGENT, POLICY)]
```

## Sequence diagram
The following diagram shows the bulk producer-loading path that avoids issuing one producer query per agency.

```mermaid
sequenceDiagram
  participant Client
  participant Agencies as clsAgencyCollection
  participant Portal as BOF data portal
  participant Oracle
  Client->>Agencies: GetAgencyCollection(dpi, criteria)
  Agencies->>Portal: RetrieveObject(criteria)
  Portal->>Oracle: Execute agency retrieval SQL
  Oracle-->>Portal: IDataReader rows
  Portal-->>Agencies: Hydrated clsAgencyCollection
  Client->>Agencies: RetrieveProducers()
  Agencies->>Portal: GetProducerCollection(dpi)
  Portal->>Oracle: Execute producer retrieval SQL
  Oracle-->>Portal: Producer rows
  Portal-->>Agencies: Hydrated clsProducerCollection
  Agencies-->>Client: Producers assigned to matching agencies
```

## Design constraints
- All criteria classes are retrieve-only; create, insert, update, and delete SQL paths throw invalid-SQL exceptions.
- `clsAgencyCollection.Criteria.RetrieveSQL` assembles optional predicates dynamically, including a contract-type `IN` list rendered as string literals instead of bind variables.
- `clsAgencyOffice` and `clsProducer` both project from `AGENT`, so schema changes to that table affect two distinct business views.
- Lazy navigation is convenient for single-object use but can trigger N+1 database access if callers iterate many agencies without using the bulk-load helpers.

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

## Sources
- `Business\SAIF.Business.Policy.Agency\clsAgency.vb`
- `Business\SAIF.Business.Policy.Agency\clsAgencyCollection.vb`
- `Business\SAIF.Business.Policy.Agency\clsAgencyContract.vb`
- `Business\SAIF.Business.Policy.Agency\clsAgencyContractCollection.vb`
- `Business\SAIF.Business.Policy.Agency\clsAgencyOffice.vb`
- `Business\SAIF.Business.Policy.Agency\clsAgencyOfficeCollection.vb`
- `Business\SAIF.Business.Policy.Agency\clsProducer.vb`
- `Business\SAIF.Business.Policy.Agency\clsProducerCollection.vb`
