Franchise Partner Added
A person became a partner of a franchise unit, with their roles and whether they are a primary contact of the unit. One message per partner. Consumed by cna-nexus to invalidate the economic group statistics cache and by cna-one to give the partner access to the franchise.
Overview
Fact: 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 row was added. The payload carries the unit, the partner’s roles, whether the partner is a primary contact of the unit and a snapshot of the person.
Since 1.2.0 isPrimaryContact says whether the partner is a primary contact of the franchise, the partner the franchisor team usually talks to. It belongs to the link with this franchise, not to the person: the same person may be a contact of one unit and not of another, so it is not part of 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. A franchise may have none, one or several. Operations and Implementation set it by hand in cna-nexus; contracts never set it, so a partner added by a contract or a legal info edit arrives with false, and a partner recreated by an audit reversal arrives with the flag they had.
Since 1.1.0 person.birthDate is a calendar day, YYYY-MM-DD, with no time zone: the column is a date, and a consumer that built a Date from the former midnight-UTC timestamp and stored it in a negative offset landed on the day before.
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 addPartners, which runs inside replaceFranchisePartners whenever a franchise is created from a contract, its legal information is edited, or a contract is applied onto it, and when an audit reversal recreates a removed partner. Registered with manager.afterCommit(), one message per added partner, batched in a single send. The same commit may also carry Franchise Partner RemovedFranchise Partner RemovedEventv1.2.0A person stopped being a partner of a franchise unit. One message per partner. Consumed by cna-nexus to invalidate the e...Ownercna-platformSchemaMapView docs and Franchise Partner UpdatedFranchise Partner UpdatedEventv1.2.0The roles or the primary contact flag of a franchise partner changed. Carries both before and after. Consumed by cna-nex...Ownercna-platformSchemaMapView docs messages. A later change to the person’s own data does not republish 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. cna-nexus (touchEconomicGroupOnFranchisePartnerChange, group economic-group-partner-touch): loads the franchise; if it has an economic group, bumps the group’s updatedAt. That timestamp versions the Redis cache of the economic group statistics (units, franchisees, active groups), so the next read recomputes them. Franchises without a group are ignored. 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 isPrimaryContact.
Kafka
Topic (aggregateRoot) | Franchise |
Message key (routingKey) | payload.franchiseId |
| Contract owner | NEXUS |
metadata.event | FranchisePartnerAdded |
| Consumer groups | economic-group-partner-touch (cna-nexus), franchise-franchise-events (cna-one, pinned to 1.1.0) |
Payload schema
Source of truth
export type FranchisePartnerEventPerson = { id: string; document: string; documentType: PersonsDocumentType; name: string; email?: string | null; phone?: string | null; birthDate?: string | null; legalName?: string | null; isFranchisee: boolean;};
export type FranchisePartnerEventPayload = { franchiseId: string; roles: FranchisePartnerRole[]; isPrimaryContact: boolean; person: FranchisePartnerEventPerson;};
export class FranchisePartnerAdded extends Event<FranchisePartnerEventPayload> { 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/FranchisePartnerAdded.ts: production (v0.14.0) sends the 1.1.0 payload, withperson.birthDateasYYYY-MM-DD, but declaresstatic readonly version = '1.0.0', sometadata.versionreads1.0.0.stagingdeclares1.1.0(cna-br/cna-nexus#587). The 1.2.0 payload, withisPrimaryContact, is on cna-nexus branchjc/feature/CWH-52595-publish-primary-contact-in-partner-events(pull request pending) and declares1.2.0. No pin: cna-nexus is the producer. This note goes when the class declaring1.2.0is in production. - cna-one
api/app/events/nexus/franchise/FranchisePartnerAdded.tsonstaging(cna-br/cna-one#903, not yet in production) declaresversion = '1.1.0'and has noisPrimaryContact; it also typesrolesandperson.documentTypeasstringinstead of the enums. cna-one’sreceivesis pinned to 1.1.0 until a copy carryingisPrimaryContactis in production (no pull request yet). person.isFranchiseeis true when the person holdsFRANCHISEEin any franchise, not only infranchiseId.
Custom properties
| Property | Value |
|---|---|
| Contract Ownerx-contract-owner | NEXUS |
| Kafka Topicx-kafka-topic | Franchise |
| Message Keyx-message-key | franchiseId |
| Sourcex-source | cna-nexus api/app/events/nexus/franchise/FranchisePartnerAdded.ts |
| Driftx-drift | cna-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; isFranchisee is global across franchises, not scoped to franchiseId. |
Franchise id (UUID). Kafka message key.
Roles of the partner in this unit (FranchisePartnerRole). Never empty.
Whether the partner is a primary contact of this franchise for the franchisor team. Belongs to the link with this franchise, not to the person. Set by hand in cna-nexus: false for a partner added by a contract or a legal info edit; a reverted removal brings back the flag the partner had.
Snapshot of the person (common.persons).