DAM Sync
Source:
omni-cms-composable-cms/infrastructure/lib/components/dam-sync-kafka.ts📐 ADR: ADR-0010 — CMS NOT to consume Bynder directly — Decision: asset metadata syncs via an event pipeline, not by the CMS querying Bynder at render time.
Overview
Section titled “Overview”All images in the CMS come from Bynder (HEMA’s Digital Asset Management). Direct uploads are disabled. When asset metadata changes in Bynder, a Kafka-based pipeline syncs those changes to Sanity.
Pipeline Architecture
Section titled “Pipeline Architecture”What Gets Synced
Section titled “What Gets Synced”| Bynder Change | Sanity Update |
|---|---|
| Tags changed | Updates opt.media.tags on asset + creates media.tag_* documents |
| Description changed | Updates description on asset document |
| Metadata properties changed | Updates metadata object on asset.metadata document |
| Archive status changed | Updates archived flag |
| Media version changed | Flags as input_required (manual action needed) |
Only MediaUpdated and MediaDeleted events are processed (filtered at the pipe level).
Components
Section titled “Components”Kafka Pipe (EventBridge)
Section titled “Kafka Pipe (EventBridge)”new KafkaPipe(this, "BynderEventsPipe", { topicName: "Hema.dam-engine.BynderAssets", consumerGroupId: `${service}-${stage}-dam-sync`, batchSize: 100, maximumBatchingWindowInSeconds: 5, startingPosition: "LATEST", enrichment: new SchemaDecodeEnrichLambda(...), target: new KafkaRecordsToSqsLambda(...),});SQS FIFO Queue
Section titled “SQS FIFO Queue”- FIFO with content-based deduplication
- Dead-letter queue for failed messages
- S3 bucket for oversized payloads
DAM Sync Lambda
Section titled “DAM Sync Lambda”Finds related Sanity documents by Bynder media_id, builds a transaction with patches, and commits atomically.
Asset Cleanup Scheduler
Section titled “Asset Cleanup Scheduler”A scheduled Lambda removes unused/orphaned assets:
new AssetCleanupScheduler(this, "AssetCleanupScheduler", { cleanupSchedule: props.assetCleanupSchedule, dryRun: props.assetCleanupDryRun, gracePeriodDays: props.assetCleanupGracePeriodDays, maxDeletions: props.assetCleanupMaxDeletions,});Bynder Plugin (Studio Side)
Section titled “Bynder Plugin (Studio Side)”The Studio uses a custom Bynder plugin (plugins/bynder/) that:
- Replaces default image upload with Bynder’s Compact View
- Imports assets with
source.name = "bynder"andsource.id = <media-id> - Stores metadata in a companion
asset.metadatadocument
form: { image: { assetSources: () => [bynderMediaSource], directUploads: false }, file: { assetSources: () => [bynderMediaSource], directUploads: false },},Troubleshooting
Section titled “Troubleshooting”| Issue | Cause | Resolution |
|---|---|---|
| Asset not syncing | Media ID not in Sanity | Re-import asset from Bynder in Studio |
| Tags not updating | Failed messages | Check DLQ, replay messages |
input_required status | Media file version changed | Editor must re-select asset in Studio |
| Lambda timeout | Large batch | Check batch size config |