event

Franchise Partner Updated

The roles or the primary contact flag of a franchise partner changed. Carries both before and after. Consumed by cna-nexus to invalidate the economic group statistics cache and by cna-one to update the partner's access.

Event Topic: FranchiseKey: franchiseIdPayload drift

Overview

Fact: the roles or the primary contact flag of a Franchise PartnerFranchise PartnerEntityv1.1.0The link between a franchise unit and a person behind it, with one or more roles - FRANCHISEE (leads the unit) or OPERAT...Ownercna-platformView docs changed. The payload is the Franchise Partner AddedFranchise Partner AddedEventv1.2.0A person became a partner of a franchise unit, with their roles and whether they are a primary contact of the unit. One ...Ownercna-platformSchemaMapView docs payload plus previousRoles and previousIsPrimaryContact.

Since 1.2.0 the event carries isPrimaryContact and previousIsPrimaryContact, the flag after and before the change, in the same pattern as roles and previousRoles. The flag joined the roles as a mutable field of the partner link, so a change of the flag alone publishes this event with roles equal to previousRoles; consumers tell what changed by comparing each pair.

Since 1.1.0 person.birthDate is a calendar day, YYYY-MM-DD, as on FranchisePartnerAdded.

When it is published. CNA NexusCNA NexusServicev1.0.0Franchise network back-office (franchises, economic groups, partners, contracts and amendments, document storage, AI doc...PublishesInviteUser, ContractActivationRequested +13SubscribesContractActivationRequested, AmendmentApplyRequested +4Ownercna-platformMapRepoView docs, in updatePartners, only for partners whose roles or primary contact flag differ from the stored ones. It runs inside replaceFranchisePartners, which never sets the flag and keeps the stored one, so contracts and legal info edits publish it only for role changes; inside the operation that sets the primary contacts of a franchise, which changes only the flag of the partners whose flag differs; and when an audit reversal restores a partner’s previous roles and flag. Registered with manager.afterCommit(), one message per changed partner. A change to the person’s own data (name, contacts, birth date) is not a change of the link and does not publish this event; it travels as Partner UpdatedPartner UpdatedEventv1.0.0The personal data of a franchise partner changed in CNA Nexus - name, legal name, e-mail, phone or birth date. Snapshot ...Ownercna-platformSchemaMapView docs on Partner (Kafka topic)Partner (Kafka topic)Channelv1.0.0Kafka topic for the Partner aggregate - a person in their capacity as partner of one or more franchise units. Carries Pa...Ownercna-platformView docs (target contract).

What the consumer does. Same as for FranchisePartnerAdded: cna-nexus bumps the updatedAt of the franchise’s economic group, if any. A role change can move a person in or out of the franchisee count; a change of the flag alone moves no count, and the bump only makes the next read recompute the same numbers. CNA OneCNA OneServicev1.0.0Franchise operating system (franchises and employees, pricing, products and learning books, school operations). Publishe...PublishesGrantApplicationAccess, EmployeeCreated +6SubscribesInviteUser, FranchiseCreated +12Ownercna-platformMapRepoView docs (group franchise-franchise-events, handler syncFranchisePartner, on staging through cna-br/cna-one#903, not yet in production): mirrors the partner as an employee with the FRANCHISEE job role and access to the franchise; a partner of a franchise cna-one does not carry is logged and dropped. Its 1.1.0 copy does not read the flags, so a change of the flag alone rewrites the same employee.

Kafka

Topic (aggregateRoot)Franchise
Message key (routingKey)payload.franchiseId
Contract ownerNEXUS
metadata.eventFranchisePartnerUpdated
Consumer groupseconomic-group-partner-touch (cna-nexus), franchise-franchise-events (cna-one, pinned to 1.1.0)

Payload schema

Source of truth

export type FranchisePartnerUpdatedPayload = {
franchiseId: string;
roles: FranchisePartnerRole[];
previousRoles: FranchisePartnerRole[];
isPrimaryContact: boolean;
previousIsPrimaryContact: boolean;
person: FranchisePartnerEventPerson;
};
export class FranchisePartnerUpdated extends Event<FranchisePartnerUpdatedPayload> {
static readonly owner = 'NEXUS';
static readonly aggregateRoot = 'Franchise';
static readonly routingKey = 'franchiseId';
static readonly version = '1.2.0';
}

Known drift

Observed 2026-10-05.

  • cna-nexus api/app/events/nexus/franchise/FranchisePartnerUpdated.ts: production (v0.14.0) sends the 1.1.0 payload, with person.birthDate as YYYY-MM-DD, but declares static readonly version = '1.0.0', so metadata.version reads 1.0.0. staging declares 1.1.0 (cna-br/cna-nexus#587). The 1.2.0 payload, with isPrimaryContact and previousIsPrimaryContact, is on cna-nexus branch jc/feature/CWH-52595-publish-primary-contact-in-partner-events (pull request pending) and declares 1.2.0. No pin: cna-nexus is the producer. This note goes when the class declaring 1.2.0 is in production.
  • cna-one api/app/events/nexus/franchise/FranchisePartnerUpdated.ts on staging (cna-br/cna-one#903, not yet in production) declares version = '1.1.0' and has no isPrimaryContact nor previousIsPrimaryContact; it also types roles and person.documentType as string instead of the enums. cna-one’s receives is pinned to 1.1.0 until a copy carrying the flags is in production (no pull request yet).

Custom properties

PropertyValue
Contract Ownerx-contract-ownerNEXUS
Kafka Topicx-kafka-topicFranchise
Message Keyx-message-keyfranchiseId
Sourcex-sourcecna-nexus api/app/events/nexus/franchise/FranchisePartnerUpdated.ts
Driftx-driftcna-nexus production sends the 1.1.0 payload but its class declares version 1.0.0, and 1.2.0 (isPrimaryContact) is pending in a pull request; cna-one's copy is 1.1.0, without isPrimaryContact, and its receives is pinned to 1.1.0 until it is updated and in production.
15 properties
franchiseIdstring
required

Franchise id (UUID). Kafka message key.

rolesarray[string]
required

Roles after the change (FranchisePartnerRole). Never empty.

previousRolesarray[string]
required

Roles before the change.

isPrimaryContactboolean
required

Whether the partner is a primary contact of this franchise for the franchisor team after the change. Belongs to the link with this franchise, not to the person.

previousIsPrimaryContactboolean
required

Primary contact flag before the change. Differs from isPrimaryContact when the flag changed; equal when only the roles changed.

personobject
required

Snapshot of the person (common.persons).