A tracking plan says what should be produced. An executable contract validates one event. A catalog helps a person discover what exists, whether it is trusted, who owns it, and how it can be used.
business question
→ catalog entry
→ tracking-plan definition
→ executable schema
→ producer and collection
→ governed metrics and assets
GraphJSON does not currently provide a built-in organization-wide event catalog or automatic lineage graph. Keep the catalog in a version-controlled repository or another governed system, and link it to GraphJSON collections, queries, dashboards, and owners.
Separate the registries#
| Registry | Primary question |
|---|---|
| Event catalog | What facts exist, and may I use them? |
| Property dictionary | What does this field mean and how is it typed? |
| Tracking plan | What should producers implement? |
| Executable contract | Is this payload valid? |
| Metric registry | How is this decision-level number calculated? |
| Asset inventory | Which queries, dashboards, alerts, and embeds consume it? |
These can share one source repository, but do not collapse their semantics into one spreadsheet cell.
Define a catalog entry#
event: report_published
title: Report published
description: A report became visible to its intended audience.
domain: reporting
owner: reporting-product
status: official
collection: product_events
producer: reports-api
trigger: After the publish transaction commits.
grain: One successful publication per report version.
identifiers:
- user_id
- account_id
- report_id
properties:
- visibility
- template
- duration_ms
sensitivity: internal
retention_class: product-standard
schema_version: 2
introduced_at: 2026-03-14
contract: schemas/report_published.v2.json
known_consumers:
- activation-dashboard
- weekly-active-accounts-v4
Store stable IDs for owners and assets. Display names can change.
Use clear lifecycle states#
Recommended states:
| State | Meaning |
|---|---|
proposed |
Under review; producers must not rely on it yet |
development |
Implemented outside production |
verified |
Observed and contract-tested in production |
official |
Approved for shared metrics and reporting |
deprecated |
No new consumers; replacement documented |
retired |
Producer stopped; history may remain |
quarantined |
Known defect makes current use unsafe |
“Exists in Samples” does not make an event official. Endorsement should require an owner, definition, contract, privacy classification, and verified producer.
Do not delete retired definitions while their historical data or downstream assets remain.
Document the trigger and grain#
Weak:
report_published: when someone publishes
Strong:
Emitted once after a report-version publish transaction commits and the
version becomes visible. Retries keep the same event_id. A republish of a
new version is a new event.
The catalog should resolve:
- attempt vs successful outcome
- one event per click, entity, state transition, or reporting period
- behavior for retries and duplicates
- server vs client authority
- event-time timestamp
- relationship to earlier versions
Define properties once#
Property entry:
property: duration_ms
description: Wall-clock time from accepted publish request to committed result.
type: integer
unit: milliseconds
required: true
nullable: false
minimum: 0
sensitivity: internal
cardinality: high_bounded
owner: reporting-platform
Record:
- type and null behavior
- unit
- bounded allowed values
- meaning at event time
- sensitivity
- expected cardinality class
- source of truth
- examples and invalid examples
Do not define plan globally if one producer means current plan and another
means plan at event time. Prefer explicit plan_at_event and link it to the
reference definition.
Classify sensitivity and use#
Example classification:
public
internal
confidential
restricted
prohibited
The catalog should identify:
- direct identifiers
- pseudonymous identifiers
- user-authored content
- financial or security context
- collection and retention requirement
- whether embedding or public sharing is allowed
Never treat classification as a free-form note. Use a controlled vocabulary with a responsible security or privacy owner.
Track cardinality expectations#
Cardinality affects chart usability, cost, and privacy:
| Class | Example |
|---|---|
| Low bounded | Plan, platform, outcome |
| Medium bounded | Country, template, error class |
| High bounded | Account, user, report |
| Unbounded text | Raw URL, message, query, stack trace |
Mark fields safe for chart splits. A property can be valid for lookup or correlation but inappropriate as a visualization dimension.
Do not include live cardinality counts in the static catalog unless a job refreshes them with a timestamp. Use Instrumentation health for observed drift.
Generate documentation from source contracts#
Prefer one source of truth:
catalog YAML
├── rendered human documentation
├── JSON Schema or runtime validator
├── test fixtures
└── change-review diff
If JSON Schema is the source, supplement it with ownership, business trigger, sensitivity, status, and consumer metadata. A type system cannot explain why the event exists.
Fail CI when:
- an official event has no owner
- a required property lacks a description or type
- a prohibited field appears
- an incompatible change keeps the same schema version
- a deprecated event has no replacement or retirement date
- a new producer references an unknown event
Use Executable event contracts for implementation patterns.
Link producers and consumers#
Maintain both directions:
producer → event → property → metric/query → dashboard/alert/embed → decision
For each official event, link:
- code owner and producer
- collection
- schema and fixtures
- sample query
- official metrics
- important dashboards and embeds
- change history
For each important asset, list the source events and expected result contract.
GraphJSON does not infer this lineage automatically. Use Analytics asset change management before a breaking change.
Create an endorsement process#
An event becomes official when:
- the business trigger and grain are reviewed
- identity, event time, units, and privacy are explicit
- the producer uses a durable-enough delivery path
- positive and negative fixtures pass
- a known scenario reconciles
- production type and volume are observed
- an accountable owner approves it
Official status does not mean immutable forever. It means changes follow a visible compatibility and migration process.
Deprecate safely#
Deprecation record:
event: report_created
status: deprecated
deprecated_at: 2026-07-26
replacement: report_published
reason: Creation did not guarantee customer-visible value.
producer_stop_target: 2026-08-15
consumer_migration_target: 2026-09-01
historical_definition_retained: true
Then:
- prevent new consumers
- inventory queries, dashboards, alerts, embeds, and exports
- dual-emit only when meanings are genuinely comparable
- reconcile old and new over a settled window
- migrate consumers
- stop the old producer
- monitor for unexpected events
- retain historical documentation
Do not rename a catalog entry in place when the business meaning changed.
Measure catalog health#
Useful governance indicators:
- official events without active owners
- production events absent from the catalog
- catalog events not seen within their expected cadence
- unknown schema versions
- deprecated events still arriving
- properties with observed type drift
- high-cardinality fields marked safe for splits
- critical events without known consumers or reconciliation
- assets depending on quarantined events
These are prompts for review, not automatic evidence that the event is wrong. A quarterly billing event should not be declared dead after seven days.
Make discovery useful#
A person should be able to search by:
- business concept
- event or property name
- domain and owner
- producer and collection
- status
- sensitivity
- identifier
- metric or dashboard consumer
Include one good example and one boundary example. Avoid pasting dozens of raw production payloads into the catalog.
Launch checklist#
- Events, properties, metrics, and assets have distinct definitions.
- Every official entry has an owner, trigger, grain, and collection.
- Event-time identity, units, null behavior, and retries are explicit.
- Sensitivity and cardinality use controlled classifications.
- Human docs and executable contracts share one governed source.
- Official status requires production verification.
- Producers and important consumers are linked.
- Deprecation retains historical meaning and names a replacement.
- Catalog-health checks account for expected cadence.
- Search supports business concepts, not only exact event names.