Skip to main content
← All docs
FFlowcore
    flowcore

    Design your Flowcore event model

    Bergur Davidsen·Updated 2026-07-15

    |Open in||History

    A useful event model makes ownership, permissions, subscriptions, replay, and change understandable. A poor model turns the event platform into an unstructured message bus.

    Flowcore organizes event data as:

    tenant → data core → flow type → event type → event

    This guide focuses on the three levels your application teams design most often: data cores, flow types, and event types.

    Start from the business domain, not the current codebase

    Services, repositories, and teams change more frequently than business concepts. Model events around durable domain boundaries rather than today's deployment layout.

    For example, an application may currently have separate checkout-api, order-worker, and fulfillment-service deployments. That does not automatically mean it needs three data cores. If those services participate in one governed commerce domain, a commerce data core with focused flow types may be easier to own and replay.

    Before creating resources, identify:

    • The business capabilities represented by the events
    • Who owns their meaning and lifecycle
    • Which applications may publish or consume them
    • Which access, retention, and compliance rules apply
    • Which history must be replayed together
    • Whether the boundary must remain isolated from other domains

    Design data cores as durable ownership boundaries

    A data core is the primary container for a coherent body of event data. A good data-core boundary normally combines events with similar ownership, access policy, retention expectations, and operational lifecycle.

    Reasonable examples include:

    • commerce
    • customer-support
    • device-telemetry
    • billing

    A data core should be large enough to represent a meaningful domain but small enough to govern clearly.

    Keep events together when

    Use the same data core when events:

    • Belong to one durable product or bounded context
    • Share an owning team or governance process
    • Need similar access and retention rules
    • Are commonly queried, subscribed to, or replayed together
    • Should use the same production safeguards

    Split data cores when

    Create separate data cores when:

    • Ownership and administrative access differ materially
    • Regulations or data residency require isolation
    • Retention or deletion policy differs
    • One domain must not be discoverable by another
    • Operational failure or replay needs an independent boundary
    • The data represents an unrelated business capability

    Avoid the two common extremes

    One data core per event type creates excessive administration. Policies, descriptions, manifests, and replay procedures become fragmented.

    One global data core for everything makes permissions broad, ownership unclear, and replay difficult to scope.

    Aim for stable bounded contexts instead.

    Document data-core intent

    Every production data core should have a description that answers:

    • What domain does this data core represent?
    • Which team owns it?
    • What data belongs here?
    • What data explicitly does not belong here?
    • Which retention and sensitivity policy applies?
    • Who approves destructive operations?

    The name is a durable identifier; the description carries human context. Keep both under review.

    Set safe production defaults

    A v2 data-core resource includes access control and delete protection.

    apiVersion: data-core.flowcore.io/v1
    kind: DataCore
    metadata:
      name: commerce
      tenant: acme-production
    spec:
      accessControl: private
      deleteProtection: true
      description: Durable commerce events owned by the Orders team

    Use private unless cross-tenant access is intentionally designed and reviewed. Enable delete protection for production data cores.

    Access control and IAM are related but different:

    • Data-core access control determines whether the resource is private or public.
    • IAM determines which identities may perform specific actions on tenant resources.

    A private data core still needs least-privilege IAM. A public setting does not mean anonymous applications should receive unrestricted access.

    Design flow types around related lifecycles

    A flow type groups event types that belong to one domain lifecycle or closely related subject area inside a data core.

    For a commerce data core, possible flow types include:

    • order.0
    • payment.0
    • fulfillment.0

    Each flow type provides a stable grouping for discovery, permissions, subscriptions, Data Pathway sources, and replay.

    A good flow type has:

    • One clear domain purpose
    • An identifiable owner
    • Event types that are commonly understood together
    • A lifecycle that can evolve without absorbing unrelated events

    Do not create a flow type solely because one service produces the events. If service ownership changes, the domain name should still make sense.

    Design event types as immutable facts

    An event type names one kind of fact that has already happened.

    Good names include:

    • order.placed.0
    • payment.authorized.0
    • shipment.dispatched.0
    • customer.email-changed.0

    Avoid names such as:

    • create-order
    • update
    • process-payment
    • send-to-database
    • webhook-message

    Commands express requested work. Events record accepted outcomes. Transport and storage names describe implementation details, not business meaning.

    A consumer should be able to understand an event's meaning without knowing the producer's private database schema.

    Keep events focused and useful

    An event payload should communicate the fact completely enough for intended consumers without becoming a copy of every field in the producer's database.

    Include:

    • Stable identifiers for the subject
    • The values that define the fact
    • Domain time where relevant
    • Correlation or causation metadata when useful
    • References needed by independent consumers

    Avoid:

    • Access tokens and secrets
    • Unbounded binary data
    • Incidental database columns
    • Fields whose meaning is only known inside one service
    • Mutable URLs or internal implementation paths unless they are truly part of the contract

    Whether to include more context or only changed fields is a domain decision. Optimize for independent interpretation and future replay, not minimum bytes alone.

    Use a predictable naming convention

    Names appear in code, manifests, URLs, permissions, subscriptions, dashboards, and retained history. Treat them as API contracts.

    A common Flowcore convention is:

    • Flow type: domain.0
    • Event type: entity.fact.0
    • Full path: domain.0/entity.fact.0

    For example:

    order.0/order.placed.0

    Use:

    • Lowercase names
    • Consistent separators
    • Past-tense facts
    • Explicit version suffixes
    • Domain language understood outside one team

    Do not mix naming conventions casually across the same data core. Pick one convention, document it, and automate checks where practical.

    Version meaning, not every code change

    The version suffix represents contract semantics. It does not need to change whenever implementation code changes.

    A new version is normally required when old consumers cannot safely interpret the new event, for example:

    • A field changes type
    • A required field is removed or renamed
    • The event describes a different business fact
    • Units, currency, identifiers, or invariants change meaning
    • Existing values receive a new interpretation

    An additive optional field may remain compatible when old consumers ignore unknown fields and new consumers handle its absence. Compatibility still depends on actual producer and consumer behavior; do not assume it from syntax alone.

    Model a commerce example

    Suppose an organization needs order, payment, and fulfillment history.

    Tenant

    acme-production

    Data core

    commerce

    Flow types and event types

    commerce
    ├── order.0
    │   ├── order.placed.0
    │   ├── order.confirmed.0
    │   └── order.cancelled.0
    ├── payment.0
    │   ├── payment.authorized.0
    │   └── payment.declined.0
    └── fulfillment.0
        ├── shipment.created.0
        └── shipment.dispatched.0

    This structure lets teams grant payment publishing separately from order publishing, subscribe to one lifecycle, or replay fulfillment without treating every commerce event as one undifferentiated stream.

    Review the model with concrete questions

    Before creating production resources, ask:

    1. Will this boundary still make sense if services or teams are reorganized?
    2. Can we state who owns every data core and flow type?
    3. Do all events in the data core share compatible governance?
    4. Are event names facts rather than commands?
    5. Can a consumer understand each event without private producer knowledge?
    6. Is the versioning rule clear?
    7. Can permissions be granted without becoming unnecessarily broad?
    8. Can replay be scoped to the recovery or migration we expect?
    9. Are sensitive fields identified before ingestion?
    10. Is destructive lifecycle ownership documented?

    Modeling checklist

    • Data cores follow durable domain and governance boundaries.
    • Every data core has an owner and meaningful description.
    • Production data cores are private unless sharing is intentional.
    • Production data cores use delete protection.
    • Flow types group coherent business lifecycles.
    • Event types describe immutable facts in past tense.
    • Names use one documented convention.
    • Version suffixes begin with an explicit policy.
    • Payloads include stable identifiers and avoid secrets.
    • Replay, retention, and sensitivity requirements are understood.

    Next, read Define and evolve event contracts to turn these resource names into runtime-validated payloads.

    PreviousPrepare a Flowcore service for productionNextDefine and evolve event contracts