event

Franchise Partner Added

A person became a partner of a franchise unit, with their roles. One message per partner. Consumed by cna-nexus itself to invalidate the economic group statistics cache.

Event Topic: FranchiseKey: franchiseIdPayload drift

Overview

Fact: a Franchise PartnerFranchise PartnerEntityv1.0.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 and a snapshot of the person. 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. 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.1.0A person stopped being a partner of a franchise unit. One message per partner. Consumed by cna-nexus itself to invalidat...Ownercna-platformSchemaMapView docs and Franchise Partner UpdatedFranchise Partner UpdatedEventv1.1.0The roles of a franchise partner changed - roles are the only mutable field. Carries the roles before and after. Consume...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 +9Ownercna-platformMapRepoView docs has no class for this event and drops it.

Kafka

Topic (aggregateRoot)Franchise
Message key (routingKey)payload.franchiseId
Contract ownerNEXUS
metadata.eventFranchisePartnerAdded
Consumer groupeconomic-group-partner-touch

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[];
person: FranchisePartnerEventPerson;
};
export class FranchisePartnerAdded extends Event<FranchisePartnerEventPayload> {
static readonly owner = 'NEXUS';
static readonly aggregateRoot = 'Franchise';
static readonly routingKey = 'franchiseId';
static readonly version = '1.0.0'; // wire format is 1.1.0, bump pending (Known drift)
}

Known drift

Observed 2026-09-24.

  • cna-nexus api/app/events/nexus/franchise/FranchisePartnerAdded.ts on staging (cna-br/cna-nexus#562) sends person.birthDate as YYYY-MM-DD, the 1.1.0 contract, but still declares static readonly version = '1.0.0', so metadata.version will read 1.0.0. Production (v0.13.0) runs the 1.0.0 contract, with the ISO timestamp, until the next release. No pin: cna-nexus is the producer and the only consumer, and its handler reads only franchiseId. The badge and this note go when the class declares 1.1.0 in production.
  • cna-one has no class for this event on main and drops it. Branch jl/feature/CWH-49388-consume-franchise-partner-events (not merged) types birthDate as YYYY-MM-DD text, has no static version, and does not carry roles or isFranchisee.
  • person.isFranchisee is true when the person holds FRANCHISEE in any franchise, not only in franchiseId.

Custom properties

PropertyValue
Contract Ownerx-contract-ownerNEXUS
Kafka Topicx-kafka-topicFranchise
Message Keyx-message-keyfranchiseId
Sourcex-sourcecna-nexus api/app/events/nexus/franchise/FranchisePartnerAdded.ts
Driftx-driftcna-nexus publishes birthDate as YYYY-MM-DD (cna-br/cna-nexus#562, staging) but its class still declares version 1.0.0, and production sends the ISO timestamp until the next release; isFranchisee is global across franchises, not scoped to franchiseId.
12 properties
franchiseIdstring
required

Franchise id (UUID). Kafka message key.

rolesarray[string]
required

Roles of the partner in this unit (FranchisePartnerRole). Never empty.

personobject
required

Snapshot of the person (common.persons).