Platform: Infosys Equinox | EventBridge Source: "foundation-service"

EventBridge bus: EVENT_BUS_NAME (default eq-9-sandbox1-eventbus) Publishing gate: the EventBridge plugin is registered with enabled: process.env.STAGE !== 'test' — i.e. events publish in every stage except test. (There is no ENABLE_EVENT_BRIDGE variable; an older stub path uses ENABLE_EVENT_PUBLISHING — see “Legacy / stub publisher” below.)

What Are Events and Why Do They Matter

When Foundation changes certain entities, it publishes a domain event to AWS EventBridge. Other microservices subscribe to these events to react in real time without polling Foundation. For example, a downstream changelog/indexer service consumes foundationservice/store/create to keep its own copy of store data current.

If publishing is disabled (e.g. STAGE=test), the mutation still succeeds — the event is simply skipped and logged.

How Events Are Actually Published

Foundation publishes through the @equinox/event-bridge-implementation Fastify plugin, registered in src/app.ts with source: 'foundation-service'. Service-layer code calls the decorator fastify.publishEvent({ type, subject, data }).

Real example — store creation (src/service/store.service.ts):

await fastify.publishEvent({
  type: 'foundationservice/store/create',
  subject: `store-${savedStore.storeId}`,
  data: {
    id: savedStore.storeId,
    collectionId: savedStore.businessId,   // NOTE: businessId, not instanceId
    userId: savedStore.createdBy || userId,
    traceId: fastify.requestId || 'system',
    properties: ['storeId', 'name', 'businessId', 'status', 'type', 'defaultLocale', 'defaultCurrency'],
    payload: savedStore                     // the full entity document
  }
});

Event detail shape

The plugin wraps the call and delivers a detail of the form:

{
  "data": {
    "id": "<entity id>",
    "collectionId": "<owning businessId>",
    "userId": "<acting user id>",
    "traceId": "<request id or 'system'>",
    "properties": ["<changed/relevant field names>"],
    "payload": { "<full entity document>" }
  },
  "eventMetadata": { "<plugin-added metadata>" }
}

There is no entityType, eventType, instanceId, entity, or beforeState field on domain events. Domain events carry collectionId (= the owning businessId), not instanceId. Only batch events (published a different way, see below) carry instanceId.

Published Events (Outbound)

Only four entity domains actually publish publishEvent domain events today: store, location, locationEvent, and batch. Other entities (business, site, seller, siteData, storeAssociation, serviceProperty, featureFlag, userPreset) do not currently emit events.

Store events

type string Trigger
foundationservice/store/create Store created
foundationservice/store/update Store replaced (PUT)
foundationservice/store/patch Store patched (PATCH)
foundationservice/store/delete Store soft-deleted

Location & Location Event

type string Trigger
foundationservice/location/create Location created
foundationservice/location/updated Location updated (PUT or PATCH)
foundationservice/location/deleted Location soft-deleted
foundationservice/location/property-update Single location property upserted
foundationservice/location/property-delete Single location property deleted
foundationservice/location/properties-replace All location properties replaced
foundationservice/location/properties-patch Location properties merge-patched
foundationservice/location/bulk-sfs-update Bulk ship-from-store flag toggle
foundationservice/location/association-properties-update Location association properties updated
foundationservice/location-event/create Location event created
foundationservice/locationEvent/updated Location event updated
foundationservice/locationEvent/deleted Location event deleted

Batch execution events

Published from the batch execution service (src/service/batchExecution.service.ts):

type string Trigger
batch.execution.completed Execution finished successfully
batch.execution.partial_success Execution finished with some failed records
batch.execution.failed Execution failed
batch.execution.stopped Execution manually stopped
batch.execution.threshold_exceeded Error threshold exceeded mid-run
batch.execution.retry_requested A retry was requested
batch.execution.retry_started Retry execution started
batch.execution.retry_failed Retry execution failed
batch.execution.max_retries_exhausted All retries exhausted

Batch events use a second publish path. They are sent directly via the AWS SDK PutEvents in src/lambda.ts, producing a flat Detail: JSON.stringify({ ...detail, timestamp }) with Source: 'foundation-service'. These events do carry instanceId.


Consumed Events (Inbound)

Inbound events are routed by the switch in src/handlers/batchEventHandler.ts (and dispatched from src/lambda.ts).

Active handlers

Detail Type Purpose
batch.execution.progress Update the execution’s progressPercent
batch.execution.completed Mark execution COMPLETED, record metrics
batch.execution.failed Mark execution FAILED, record error
batch.execution.retry_requested Trigger a retry of a failed execution
batch.schedule.trigger Fire a scheduled batch job (from the EventBridge cron rule)
batch.job.initiated Begin processing an initiated job
batch.job.started Mark the job as started/running
gdpr.export.* / gdpr.delete.* GDPR Step Functions action routing (see 15-gdpr.md)

Deprecated handlers (backward-compatibility only)

These are still accepted but are marked deprecated in code — do not build new integrations against them:

batch.job.completed, batch.job.failed, batch.chunk.completed, batch.chunk.failed

Loop prevention: the EventBridge rule that targets Foundation’s handler filters by source so Foundation does not re-consume its own published events.

Legacy / stub publisher (not the live path)

The repository also contains src/utils/eventPublisher.ts (EventBridgeEventPublisher with publishCreated/publishUpdated/publishDeleted and an EventPayload {entityType,eventType,instanceId,entity,userId,beforeState} interface) and src/utils/eventPublisher.util.ts (gated by ENABLE_EVENT_PUBLISHING, bus EVENTBRIDGE_BUS_NAME='foundation-events', with StoreCreationStarted/Completed/Failed stubs).

These are not wired into the live request path — they have no call sites in the service layer and are placeholder/TODO code. The envelope described in older documentation came from this dead path. The authoritative, live behaviour is the fastify.publishEvent(...) path described above.


Revision History
2026-08-04 | AN – Page created and uploaded the contents