Core concepts and the event data model
Bergur DavidsenUpdated 2026-07-15
Flowcore organizes event data in a hierarchy. Understanding that hierarchy is the key to designing clear contracts, access rules, subscriptions, and replay boundaries.
The complete path is:
tenant → data core → flow type → event type → event
Each level answers a different question. The tenant owns the resources. The data core defines a durable domain boundary. The flow type groups a related lifecycle. The event type names one kind of fact. The event is the individual fact that occurred.
Tenant: the ownership and security boundary
A tenant is the top-level boundary in Flowcore. Platform resources, users, service identities, credentials, IAM policies, variables, secrets, and quotas are tenant-scoped.
A tenant commonly represents an organization, product environment, or other boundary that needs independent ownership and access control. Development and production should be separated deliberately so that test credentials and resources cannot affect production data.
When deciding tenant boundaries, ask:
- Who owns and administers these resources?
- Which identities should be able to discover or operate on them?
- Do environments require independent credentials, policies, and quotas?
- Would accidental access across the boundary create a security or compliance problem?
Do not create a tenant for every small service. Tenants are governance boundaries, not merely folders.
Data core: the durable domain boundary
A data core is the main container for related event data. It typically represents an application, product domain, or bounded context with a shared lifecycle and ownership model.
Examples might include:
commercecustomer-supportdevice-telemetrybilling
A data core controls whether access is public or private and can use delete protection. Production data cores should normally be private, protected from accidental deletion, and owned by a clearly identified team.
Choose a boundary that is stable. Splitting one business lifecycle across many data cores makes querying, permissions, and replay harder to reason about. Putting unrelated domains in one data core creates the opposite problem: broad access and unclear ownership.
Flow type: a related stream of business facts
A flow type groups event types that belong to the same lifecycle or closely related subject area inside a data core.
For an order domain, a flow type could be order.0. Its event types might include:
order.placed.0order.confirmed.0order.cancelled.0
For a device domain, a flow type could be sensor-reading.0, with event types for measurements, threshold changes, or device health.
A flow type is useful as a subscription and organization boundary. Consumers can target a related family of facts without subscribing to everything in the data core.
Event type: the contract for one immutable fact
An event type names a specific kind of fact. Good event names describe something that has already happened:
invoice.issued.0payment.authorized.0profile.email-changed.0
Avoid names such as update-order or process-payment. Those describe commands or implementation steps rather than durable facts.
The payload contract normally lives with application code and should be validated at runtime. A TypeScript type alone disappears at runtime, so applications commonly pair static typing with a schema library such as Zod.
An event type should have one clear meaning. Once events have been published, do not reinterpret old payloads. If the meaning or required shape changes incompatibly, introduce a new version and let consumers migrate intentionally.
Event: an immutable occurrence
An event is one recorded occurrence of an event type. Its payload contains the domain data, while its envelope carries identity, routing, metadata, and time information.
For example, an order.placed.0 payload might contain an order ID, customer ID, currency, and line items. The event envelope can also identify the event itself, its source, when it occurred, and how it relates to other events.
Events should describe facts, not snapshots of every field in a database row by default. Include the information consumers need to understand the change, while avoiding credentials, secrets, or unbounded binary data.
Event identity and metadata
Every event needs a stable identity so consumers can recognize duplicate delivery and record processing progress. Flowcore adds platform identity and storage information; producers can attach domain and tracing metadata.
Useful metadata often includes:
- A correlation ID linking events from the same business operation
- A causation ID pointing to the command or event that caused this event
- The originating service or external system
- An actor or service identity reference
- An import, file, or synchronization batch ID
- Trace information used across observability tooling
Keep routing and operational context in metadata when it is not part of the business fact itself. Do not put secrets, access tokens, or sensitive personal data in metadata merely because it is convenient; metadata still requires intentional governance.
Event time, valid time, and storage time
Distributed systems need more than one notion of time.
Event time
Event time describes when the event occurred according to the producer or source system.
Valid time
Valid time describes when the fact should be considered true in the business domain. This matters for corrections, scheduled changes, and data that arrives after its real-world effective time.
Storage time
Storage time records when Flowcore accepted and stored the event.
Keeping these times separate makes late-arriving data and historical corrections explicit. A consumer can decide whether it cares about arrival order, occurrence order, or business validity.
For example, a transaction may occur at 10:00, arrive from an offline device at 10:20, and be valid for a reporting period that began at midnight. Treating all three as one timestamp loses important meaning.
Time buckets and positions
Flowcore groups retained events into time buckets for efficient listing and replay. Consumers advance through buckets and event IDs rather than assuming that all history is one unbounded response.
A durable consumer should persist the last successfully processed position. That position allows it to resume after a restart and gives operators a clear point from which to replay.
Do not rely only on local in-memory offsets. Progress must survive process replacement, deployment, and failure.
Naming and versioning principles
A predictable naming scheme makes resources easier to discover and operate.
- Use lowercase, stable names.
- Name event types as facts in the past tense.
- Keep domain boundaries more stable than individual service implementations.
- Add explicit versions when semantics change incompatibly.
- Never reuse an old event name for a different meaning.
- Document the owner and purpose of each data core and flow type.
Names become part of API paths, IAM resources, subscriptions, manifests, dashboards, and operational procedures. Changing them later is a migration, not a cosmetic refactor.
A complete example
Imagine a commerce tenant with an orders data core:
- Tenant:
acme-production - Data core:
commerce - Flow type:
order.0 - Event type:
order.placed.0 - Event: one customer's order placed at a particular time
The producer publishes the event once. A payment consumer, fulfillment projection, analytics pipeline, and notification service can each process it independently. Their storage models may differ, but they share the same durable fact.
Design questions to answer early
Before publishing your first production event, agree on:
- Which tenant owns the data and credentials?
- Which domain belongs in the data core?
- Which lifecycle does each flow type represent?
- What fact does each event type communicate?
- Which payload fields and metadata are required?
- Which time semantics matter to consumers?
- How will incompatible contract changes be versioned?
- Who can publish, read, replay, or administer the resources?
Clear answers prevent event contracts from becoming an ungoverned message bus.
What to read next
Read How events move through Flowcore to connect this data model to ingestion, Data Pathways, projections, checkpoints, and replay.
Return to What is Flowcore? for the platform overview.