Chapter 03 / 09
ENSK

SmartExchange · .NET 10 · Chapter 03

CRM annotations and Diagram

CRM declares which entity paths are available to authorization. The same metadata drives context selection, scope validation and SQL relationship mapping.

Shared code · Intaker + Web APIReviewed · 2026-10-27

Declarations for both export examples

Person → Company

BmcGroup.CRM · Person.cs
[CrmAuthorizationRelation("companyIds",
    nameof(Person.PersonInCompanies),
    nameof(PersonInCompany.Company))]

Provides companyIds through the linking entity.

InterestedParty → Project

BmcGroup.CRM · InterestedParty.cs
[CrmAuthorizationRelation("projectIds",
    nameof(InterestedParty.Project))]

Provides projectIds through the declared Project reference.

Both annotations feed DiagramCrm.Generate(). Both aliases are used in their derived-role conditions. Neither annotation activates export; each resource policy must explicitly allow that action.

Metadata already implemented

Class / memberOutput / use
DiagramCrm.Generate(assemblies)Builds the CRM diagram using the existing reflection workflow, including ACL and relationship annotations.
DiagramClass.AuthorizationRelationsDeclarations belonging to this resource.
DiagramAuthorizationRelationAttributeName, NavigationPath, resolved TargetEntity.
DiagramAcl from CrmAclAttributeLegacy entity/permission codes used by the adapter. Numeric identifiers stay at this conversion boundary.

The diagram resolves navigation targets; the authorization registry validates the usable relationship and generates its neutral join steps. We reuse the existing foreign-key/reverse-navigation metadata; policies do not contain SQL paths.

Seven declared relationships

ResourcePolicy aliasCRM navigation
PersoncompanyIdsPersonInCompanies → Company
CompanypersonIdsPersonInCompanies → Person
ProjectinterestedPartyIdsInterestedPartys
InterestedPartyprojectIds / investorIdsProject / Investor
InvestorinterestedPartyIds / projectIdsInterestedParties / InterestedParties → Project
Generic code, explicit metadata. Adding an ACL relationship requires an annotation. No Person/Company branch is added to the resolver or SQL factory. A corresponding policy condition remains an explicit business decision; creating an annotation does not activate access.

Cerbos receives the relationship attribute name in expressions, not the CRM graph or FK metadata. In list planning it leaves unknown record attributes in the returned condition. Our SQL mapping supplies their database meaning.