Event Metadata and Traceability
Event ID, aggregate ID, correlation ID, causation ID, trace context, tenant, actor, source service, event type/version/time, schema version, partition key, command ID, idempotency key, headers vs payload, standardisasi metadata, auditability, dan traceability checklist.
Part 014 — Event Metadata and Traceability
1. Tujuan Part Ini
Part ini membahas metadata event Kafka: data kecil yang membuat event bisa ditelusuri, di-debug, diaudit, di-deduplicate, di-replay, dan dikorelasikan dengan HTTP request, database transaction, outbox row, consumer processing, dan downstream workflow.
Payload menjawab:
Apa fakta bisnis yang terjadi?
Metadata menjawab:
Event ini dari mana?
Kenapa event ini ada?
Siapa yang memicu?
Kapan terjadi?
Versi contract apa yang dipakai?
Event ini bagian dari request/workflow yang mana?
Apakah event ini duplicate?
Bagaimana event ini ditelusuri saat incident?
Dalam sistem enterprise, metadata bukan dekorasi.
Metadata adalah control plane untuk event-driven debugging.
2. Core Mental Model
Kafka record memiliki struktur dasar:
topic + partition + offset + key + value + headers + timestamp
Namun sistem production biasanya membutuhkan envelope logis:
{
"metadata": {
"eventId": "evt-...",
"eventType": "OrderSubmitted",
"eventVersion": "1.0",
"correlationId": "corr-...",
"causationId": "cmd-...",
"traceId": "trace-...",
"tenantId": "tenant-...",
"sourceService": "order-service",
"eventTime": "2026-07-11T02:13:44Z"
},
"payload": {
"orderId": "ORD-123",
"status": "SUBMITTED"
}
}
Atau metadata bisa disimpan di Kafka headers, dengan payload hanya berisi business data.
Yang penting bukan bentuk fisiknya.
Yang penting adalah metadata standard, konsisten, dan tersedia di producer, outbox, broker, consumer, logs, metrics, tracing, dan DLQ.
3. Metadata sebagai Debugging Surface
Tanpa metadata, incident Kafka sering menjadi teka-teki:
Ada event salah. Event ini dari request mana?
Siapa user-nya?
Service mana yang publish?
Apakah duplicate?
Apakah replay?
Apakah versi schema baru?
Consumer mana yang gagal?
Apakah event ini menyebabkan saga stuck?
Dengan metadata yang baik, pertanyaan berubah menjadi query:
Find logs by correlationId.
Find event by eventId.
Find outbox row by eventId.
Find trace by traceId.
Find consumer processing by eventId.
Find DLQ item by originalTopic + partition + offset.
Metadata mengubah debugging dari forensics manual menjadi traceable workflow.
4. Event ID
Event ID adalah unique identifier untuk satu event occurrence.
Fungsi utama:
- deduplication
- idempotency
- audit trail
- DLQ tracking
- replay tracking
- log correlation
- consumer inbox key
Contoh:
{
"eventId": "evt_01J2KQ4D6XG8Y8X2Z7G9G2NQEP"
}
Prinsip:
- harus unik secara global atau cukup unik dalam scope event system
- dibuat sekali saat event dibuat
- tidak berubah saat retry publish
- tidak berubah saat event masuk DLQ
- tidak berubah saat replay, kecuali replay event memang diperlakukan sebagai event baru dengan metadata asal tetap disimpan
Anti-pattern:
Generate eventId setiap retry producer.
Akibat:
- duplicate terlihat seperti event baru
- consumer idempotency gagal
- audit trail pecah
5. Aggregate ID
Aggregate ID adalah ID entity/domain aggregate yang menjadi subjek event.
Contoh:
- quoteId
- orderId
- customerId
- accountId
- catalogItemId
Fungsi:
- partition key candidate
- ordering per aggregate
- business traceability
- projection update key
- reconciliation key
Contoh:
{
"aggregateType": "Order",
"aggregateId": "ORD-123"
}
Jika event adalah domain event, aggregate ID biasanya wajib.
Jika event adalah integration event lintas domain, aggregate ID tetap harus jelas, meskipun mungkin ada beberapa ID bisnis.
6. Correlation ID
Correlation ID menghubungkan seluruh chain aktivitas yang berasal dari satu request, command, workflow, atau business interaction.
Contoh alur:
HTTP POST /orders
correlationId = corr-123
→ outbox event OrderSubmitted correlationId=corr-123
→ billing consumer logs correlationId=corr-123
→ fulfillment command correlationId=corr-123
→ notification event correlationId=corr-123
Fungsi:
- trace request lintas service
- incident investigation
- log aggregation
- support/debugging
- workflow correlation
Dalam JAX-RS service, correlation ID biasanya berasal dari:
- incoming HTTP header
- generated server-side jika tidak ada
- gateway/API layer
- workflow command
- batch/replay job
Prinsip:
Correlation ID harus dipropagasikan, bukan dibuat ulang di setiap service.
7. Causation ID
Causation ID menjawab: event ini disebabkan oleh apa?
Contoh:
- command ID
- previous event ID
- request ID
- saga step ID
- workflow task ID
Jika correlation ID menghubungkan satu keseluruhan journey, causation ID menghubungkan sebab langsung.
Contoh:
Command SubmitOrder cmd-001
→ Event OrderSubmitted evt-101 causationId=cmd-001
→ Event OrderValidated evt-102 causationId=evt-101
→ Command StartFulfillment cmd-201 causationId=evt-102
Causation chain sangat berguna untuk menganalisis event storm, loop, dan saga behavior.
Tanpa causation ID, sulit membedakan event pertama dari event turunan.
8. Trace ID dan Span Context
Trace ID menghubungkan event processing dengan distributed tracing.
Dalam sistem modern, trace context sering memakai W3C Trace Context:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
Kafka event perlu membawa trace context agar trace dapat melewati boundary asynchronous.
Namun async tracing berbeda dari sync HTTP tracing.
Event bisa diproses:
- beberapa detik kemudian
- beberapa menit kemudian
- beberapa kali akibat retry
- oleh banyak consumer
- saat replay jauh setelah request asli selesai
Karena itu, trace harus dipahami sebagai causal trace, bukan selalu satu request latency trace sederhana.
Prinsip:
- producer menulis trace context ke header/metadata
- consumer membaca trace context
- consumer membuat span baru untuk processing
- retry/replay diberi attribute yang jelas
- DLQ publish mempertahankan original trace/correlation metadata
9. Tenant ID
Tenant ID penting untuk sistem multi-tenant.
Fungsi:
- authorization context
- data isolation
- routing
- observability per tenant
- incident blast-radius analysis
- rate limiting
- compliance evidence
Prinsip:
Tenant ID di event harus berasal dari trusted context, bukan input bebas dari payload yang tidak divalidasi.
Risiko jika tenant ID hilang:
- consumer tidak bisa enforce tenant boundary
- logs tidak bisa difilter per tenant
- replay bisa memproses data tenant secara salah
- DLQ triage sulit
Risiko jika tenant ID salah:
- cross-tenant data leak
- projection salah tenant
- compliance incident
10. Actor/User ID
Actor ID menjawab siapa atau apa yang memicu perubahan.
Actor bisa berupa:
- end user
- admin user
- service account
- batch job
- system process
- workflow engine
- integration partner
Metadata sebaiknya membedakan:
{
"actorType": "USER",
"actorId": "usr-123"
}
atau:
{
"actorType": "SERVICE",
"actorId": "pricing-service"
}
Jangan menaruh informasi sensitif seperti email lengkap atau nama user di header jika tidak diperlukan.
Untuk audit, ID stabil biasanya lebih aman daripada data personal langsung.
11. Source Service
Source service adalah service yang menghasilkan event.
Contoh:
{
"sourceService": "order-service",
"sourceInstance": "order-service-7d9f8b9c4c-nx2la"
}
sourceService biasanya contract-level metadata.
sourceInstance lebih operational dan bisa masuk log/header, tidak selalu perlu menjadi payload contract.
Fungsi source service:
- incident ownership
- debugging producer version
- routing audit
- event catalog validation
- detecting unexpected producer
Jika satu topic menerima event dari banyak producer, source service menjadi lebih penting.
Namun multi-producer topic harus direview dengan hati-hati karena ownership dan schema governance lebih kompleks.
12. Event Type
Event type menjelaskan jenis fakta bisnis.
Contoh:
QuoteCreatedQuoteSubmittedOrderSubmittedOrderCancelledCatalogItemUpdated
Event type harus stabil dan meaningful.
Anti-pattern:
OrderEvent
DataChanged
NotificationEvent
MessageEvent
Nama generic membuat consumer harus membaca payload untuk memahami arti event.
Untuk topic yang berisi banyak event type, event type wajib.
Untuk topic-per-event, event type tetap berguna untuk logging, schema registry, DLQ, dan tracing.
13. Event Version
Event version menjelaskan versi semantic contract event.
Contoh:
{
"eventType": "OrderSubmitted",
"eventVersion": "1.1"
}
Event version tidak selalu sama dengan schema registry version.
Schema version bisa berubah karena optional field.
Event version sebaiknya berubah ketika semantic contract berubah.
Heuristik:
- additive optional field: schema version naik, event version mungkin tetap
- semantic meaning berubah: event version harus naik atau event type baru
- breaking change: event version/topic/type baru + migration plan
14. Event Time
Event time adalah waktu ketika fakta bisnis terjadi.
Contoh:
{
"eventTime": "2026-07-11T03:04:05Z"
}
Event time berbeda dari Kafka record timestamp dan processing time.
Contoh:
| Time | Arti |
|---|---|
| eventTime | business fact happened |
| publishedTime | producer/outbox published to Kafka |
| broker timestamp | timestamp pada Kafka record |
| consumedTime | consumer menerima record |
| processingTime | consumer memproses record |
Dalam workflow bisnis, event time sering lebih penting daripada processing time.
Dalam observability latency, perbedaan waktu ini penting untuk menghitung lag end-to-end.
15. Processing Time
Processing time adalah waktu consumer memproses event.
Processing time biasanya bukan bagian dari original event contract.
Ini lebih cocok di log/metric/trace atau consumer-side audit.
Contoh log consumer:
{
"eventId": "evt-123",
"eventType": "OrderSubmitted",
"consumerGroup": "billing-projection",
"processingTime": "2026-07-11T03:04:08Z",
"processingLatencyMs": 253
}
Jangan menimpa eventTime dengan processingTime.
Itu akan menghancurkan temporal reasoning.
16. Schema Version
Schema version atau schema ID membantu consumer memahami payload format.
Jika memakai Schema Registry, schema ID mungkin sudah ada dalam serialized payload atau metadata serializer.
Namun untuk observability, schema version/ID sering tetap perlu terlihat di logs.
Fungsi:
- debugging deserialization failure
- tracking rollout schema baru
- DLQ analysis
- compatibility verification
- replay support
Contoh log:
{
"eventType": "OrderSubmitted",
"schemaSubject": "order-submitted-value",
"schemaId": 1042,
"schemaVersion": 7
}
17. Partition Key
Partition key adalah routing key Kafka.
Metadata harus menjelaskan key yang digunakan.
Contoh:
Kafka record key: ORD-123
metadata.partitionKey: ORD-123
metadata.partitionKeyType: orderId
Mengapa perlu dicatat?
- debugging ordering issue
- detecting key mismatch
- hot partition analysis
- replay verification
- consumer state partitioning
Jika payload orderId = ORD-123, tetapi Kafka record key ternyata tenant-9, ordering per order tidak dijamin.
Metadata atau log harus membuat mismatch mudah terdeteksi.
18. Command ID
Command ID mengidentifikasi command/request yang memicu event.
Contoh:
{
"commandId": "cmd-submit-order-123"
}
Fungsi:
- idempotency dari command
- causation tracking
- duplicate command detection
- linking HTTP request to event
- saga command/reply correlation
Command ID berbeda dari event ID.
Satu command bisa menghasilkan beberapa event.
SubmitOrder command
→ OrderSubmitted event
→ OrderValidationRequested event
→ OrderAuditRecorded event
19. Idempotency Key
Idempotency key membantu mencegah double processing untuk command atau event tertentu.
Di HTTP/JAX-RS:
POST /orders
Idempotency-Key: idem-abc
Di event:
{
"idempotencyKey": "idem-abc"
}
Namun event consumer biasanya lebih aman dedup berdasarkan eventId.
Idempotency key berguna jika event merupakan hasil command external dan downstream perlu tahu duplicate command boundary.
Jangan campuradukkan:
| Key | Fungsi |
|---|---|
| eventId | unique event occurrence |
| idempotencyKey | duplicate command/request prevention |
| aggregateId | business entity identity |
| correlationId | journey identity |
| causationId | direct cause identity |
| partitionKey | Kafka routing/ordering key |
20. Headers vs Payload
Pertanyaan umum:
Metadata taruh di Kafka headers atau payload envelope?
Jawabannya bergantung pada standard internal, tetapi trade-off-nya harus dipahami.
Kafka Headers
Kelebihan:
- cocok untuk routing/observability metadata
- tidak mencemari business payload
- mudah dipakai interceptor/middleware
- bisa dibaca tanpa deserialize full payload dalam beberapa tooling
Risiko:
- tidak semua tooling menampilkan header dengan nyaman
- schema governance header sering lebih lemah
- header bisa hilang jika connector/bridge tidak preserve
- consumer bisa lupa membaca header
Payload Envelope
Kelebihan:
- metadata ikut schema
- mudah diaudit bersama payload
- mudah direplay dari storage
- cocok untuk event log canonical
Risiko:
- payload lebih verbose
- business schema bercampur envelope
- perubahan envelope memengaruhi semua event
Hybrid
Banyak sistem memakai hybrid:
- header untuk trace/correlation/routing operational metadata
- payload envelope untuk eventId/eventType/eventVersion/eventTime/sourceService
Yang terpenting: standard harus konsisten.
21. Metadata Standardization
Metadata harus distandardisasi lintas producer dan consumer.
Contoh standard minimal:
required:
- eventId
- eventType
- eventVersion
- sourceService
- eventTime
- correlationId
- aggregateId
- partitionKey
recommended:
- causationId
- traceparent
- tenantId
- actorType
- actorId
- commandId
- idempotencyKey
- schemaVersion
- producerVersion
Jangan biarkan setiap service membuat nama sendiri:
corrId
correlation_id
correlationId
x-correlation-id
requestCorrelation
Perbedaan kecil seperti ini membuat log query dan tracing sulit.
22. Metadata Propagation dari JAX-RS
Dalam Java/JAX-RS service, metadata biasanya dibuat atau dibaca di boundary request.
Flow umum:
JAX-RS filter bisa:
- membaca
X-Correlation-ID - generate correlation ID jika kosong
- membaca trace context
- membaca tenant/user context dari auth layer
- menyimpan context ke request-scoped object
Service layer kemudian memakai context tersebut saat membuat event metadata.
Prinsip:
Resource method tidak boleh membuat metadata secara ad hoc tanpa standard.
23. Outbox Metadata
Jika memakai outbox pattern, metadata harus disimpan di outbox row.
Contoh schema outbox:
CREATE TABLE outbox_event (
id UUID PRIMARY KEY,
event_id TEXT NOT NULL UNIQUE,
event_type TEXT NOT NULL,
event_version TEXT NOT NULL,
aggregate_type TEXT NOT NULL,
aggregate_id TEXT NOT NULL,
partition_key TEXT NOT NULL,
correlation_id TEXT,
causation_id TEXT,
traceparent TEXT,
tenant_id TEXT,
source_service TEXT NOT NULL,
event_time TIMESTAMPTZ NOT NULL,
payload JSONB NOT NULL,
headers JSONB,
status TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
Outbox metadata membantu:
- publish retry tanpa kehilangan event ID
- debug event sebelum masuk Kafka
- repair publishing failure
- correlate DB transaction dengan Kafka record
- audit event creation
Jika metadata hanya dibuat saat publisher membaca outbox, event ID bisa berubah saat retry.
Itu buruk.
24. CDC/Debezium Metadata
Jika event berasal dari CDC/Debezium, metadata bisa berasal dari:
- table name
- database name
- transaction ID
- LSN/WAL position
- operation type
- source timestamp
- Debezium connector metadata
- outbox table columns
Jika memakai Debezium Outbox Event Router, outbox table biasanya menyediakan event metadata eksplisit.
Internal verification penting:
Apakah downstream consumer menerima raw CDC metadata, normalized event metadata, atau keduanya?
Raw CDC metadata berguna untuk debugging database changes.
Normalized event metadata berguna untuk business event contract.
Jangan campur tanpa dokumentasi.
25. Consumer Metadata Handling
Consumer harus memperlakukan metadata sebagai bagian dari processing contract.
Minimal consumer harus log:
- topic
- partition
- offset
- eventId
- eventType
- eventVersion
- correlationId
- causationId jika ada
- aggregateId
- tenantId jika ada
- schema ID/version jika ada
- consumer group
- processing result
Contoh structured log:
{
"message": "Processed Kafka event",
"topic": "order.events.v1",
"partition": 4,
"offset": 912301,
"consumerGroup": "billing-projection",
"eventId": "evt-123",
"eventType": "OrderSubmitted",
"correlationId": "corr-abc",
"aggregateId": "ORD-123",
"result": "success",
"durationMs": 42
}
Log tanpa event ID hampir tidak berguna saat incident.
26. DLQ Metadata
Event yang masuk DLQ harus mempertahankan metadata asli.
DLQ event sebaiknya menambahkan metadata failure:
{
"original": {
"topic": "order.events.v1",
"partition": 4,
"offset": 912301,
"eventId": "evt-123",
"eventType": "OrderSubmitted",
"correlationId": "corr-abc"
},
"failure": {
"consumerGroup": "billing-projection",
"errorClass": "DeserializationException",
"errorMessage": "Unknown enum value",
"failedAt": "2026-07-11T03:10:00Z",
"retryCount": 3
},
"payload": {}
}
DLQ tanpa original topic/partition/offset/eventId sulit direplay dengan aman.
DLQ tanpa error metadata sulit ditriage.
27. Auditability
Auditability berarti sistem bisa menjawab:
- apa yang terjadi
- kapan terjadi
- siapa/apa yang memicu
- service mana yang menghasilkan
- event mana yang dikonsumsi
- state apa yang berubah
- apakah event direplay
- apakah event duplicate
- apakah event gagal dan masuk DLQ
Metadata audit harus stabil.
Jangan bergantung pada log text bebas.
Gunakan structured fields.
Untuk sistem CPQ/order management, auditability sangat penting karena event bisa memengaruhi quote approval, order state, fulfillment, fallout, billing, dan customer-visible status.
28. Metadata dan Ordering
Metadata membantu mendeteksi ordering issue.
Contoh field:
- aggregateId
- eventTime
- sequenceNumber jika domain menyediakan
- previousEventId jika digunakan
- partitionKey
- topic/partition/offset
Kafka hanya menjamin order dalam partition.
Jika event untuk order yang sama tidak memakai key yang sama, metadata akan membantu menemukan akar masalah.
Contoh detection:
OrderValidated aggregateId=ORD-123 partition=2 offset=500
OrderSubmitted aggregateId=ORD-123 partition=7 offset=900
Jika ordering per order diharapkan, ini salah desain key.
29. Metadata dan Idempotency
Consumer idempotency biasanya membutuhkan event ID.
Contoh inbox table:
CREATE TABLE processed_event (
consumer_name TEXT NOT NULL,
event_id TEXT NOT NULL,
processed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
result TEXT NOT NULL,
PRIMARY KEY (consumer_name, event_id)
);
Jika event ID tidak stabil, inbox pattern tidak efektif.
Jika event ID hilang saat replay, replay bisa dianggap event baru.
Jika event ID sama untuk dua business event berbeda, consumer bisa skip event valid.
Event ID generation harus direview serius.
30. Metadata dan Reconciliation
Reconciliation membutuhkan metadata untuk mencocokkan state antar sistem.
Contoh:
Order table says status=SUBMITTED.
Projection table says status=PENDING.
Find OrderSubmitted event by aggregateId=ORD-123.
Find consumer processing by eventId.
Find DLQ by eventId.
Find trace by correlationId.
Tanpa metadata, reconciliation berubah menjadi manual data archaeology.
Metadata juga membantu membedakan:
- event belum dipublish
- event sudah dipublish tapi belum dikonsumsi
- event dikonsumsi tapi gagal
- event dikonsumsi sukses tapi projection salah
- event direplay dan menghasilkan duplicate
31. Metadata di Logs, Metrics, dan Traces
Metadata harus muncul di tiga observability surface:
Logs
Untuk diagnosis detail.
Wajib structured.
Metrics
Untuk aggregate signal.
Contoh label hati-hati:
- eventType
- consumerGroup
- result
- errorClass
Jangan jadikan eventId sebagai metric label karena high cardinality.
Traces
Untuk causal flow.
Trace span dapat menyimpan attribute:
- messaging.system = kafka
- messaging.destination.name
- messaging.kafka.partition
- messaging.kafka.offset
- event.type
- event.id
- correlation.id
Perhatikan high cardinality policy di tracing backend.
32. Failure Mode
Failure mode metadata:
| Failure | Dampak |
|---|---|
| eventId hilang | idempotency sulit |
| eventId berubah saat retry | duplicate tidak terdeteksi |
| correlationId dibuat ulang | trace lintas service putus |
| causationId tidak ada | event loop sulit dianalisis |
| tenantId salah | cross-tenant risk |
| actorId berisi PII | privacy exposure |
| eventTime memakai local timezone | temporal bug |
| schemaVersion tidak terlihat | schema incident sulit ditriage |
| partitionKey tidak konsisten | ordering rusak |
| DLQ tidak preserve metadata | replay tidak aman |
| header hilang saat connector | traceability putus |
33. Deteksi Metadata Failure
Tanda metadata buruk:
- log tidak bisa difilter by eventId/correlationId
- DLQ item tidak bisa dikaitkan ke original offset
- consumer duplicate tidak bisa dideteksi
- replay menghasilkan event yang terlihat baru
- support tidak bisa menemukan request asal
- tracing berhenti di producer dan tidak lanjut ke consumer
- tenant-specific incident tidak bisa di-scope
- ordering issue tidak bisa dibuktikan
- event catalog dan payload nyata berbeda
Monitoring/validation yang membantu:
- metadata completeness check di producer
- schema/header validation di CI
- runtime warning jika required metadata kosong
- DLQ by missing metadata reason
- log sampling untuk metadata completeness
- dashboard event version/schema version distribution
34. Debugging dengan Metadata
Saat incident, gunakan metadata sebagai path diagnosis.
Contoh: consumer billing lag dan DLQ naik.
Langkah:
- Ambil sample DLQ.
- Catat original topic/partition/offset.
- Catat eventId, eventType, schemaVersion, correlationId, aggregateId.
- Cari producer log by eventId/correlationId.
- Cari outbox row by eventId.
- Cari HTTP request log by correlationId.
- Cari consumer log by eventId.
- Bandingkan schema version dengan deployment timeline.
- Tentukan apakah ini metadata issue, schema issue, data issue, atau business logic issue.
Metadata yang baik membuat langkah ini cepat.
Metadata yang buruk membuat langkah ini spekulatif.
35. Trade-Off Metadata
| Pilihan | Kelebihan | Risiko |
|---|---|---|
| Metadata lengkap | debugging kuat | payload/header lebih besar |
| Metadata minimal | sederhana | incident analysis sulit |
| Header-only metadata | bersih dari payload | bisa hilang di connector/tooling |
| Envelope metadata | self-contained | semua schema harus mengikuti envelope |
| Global standard | konsisten | butuh governance |
| Per-service standard | fleksibel | query lintas service kacau |
| Correlation ID only | mudah | causality detail hilang |
| Full causation chain | forensics kuat | implementasi lebih disiplin |
Senior engineer harus menolak dua ekstrem:
Tidak ada metadata sama sekali.
Dan:
Semua informasi dimasukkan ke metadata tanpa alasan.
Metadata harus cukup untuk correctness, observability, auditability, dan operations.
36. Correctness Concern
Metadata memengaruhi correctness karena:
- eventId menentukan deduplication
- partitionKey menentukan ordering
- tenantId menentukan isolation
- eventTime menentukan temporal business logic
- causationId menentukan saga transition
- schemaVersion menentukan deserialization path
- idempotencyKey menentukan duplicate command handling
Jika metadata salah, payload benar pun bisa diproses salah.
Contoh:
Payload orderId benar.
Partition key salah.
Consumer yang mengandalkan ordering per order memproses state out-of-order.
37. Performance Concern
Metadata menambah ukuran record.
Namun biasanya overhead metadata kecil dibanding manfaat debugging.
Yang perlu diwaspadai:
- metadata terlalu besar
- header berisi payload fragment
- trace baggage berlebihan
- actor/user detail verbose
- high-cardinality metadata dipakai sebagai metric label
- logging full metadata + payload untuk semua event high-volume
Prinsip:
Metadata lengkap, tetapi log/metric usage harus cardinality-aware.
38. Security and Privacy Concern
Metadata sering dianggap aman karena “bukan payload”.
Ini salah.
Metadata bisa mengandung sensitive data:
- tenant ID
- user ID
- IP address
- auth subject
- organization ID
- partner ID
- correlation ID yang bisa dipakai tracking
Checklist:
- Jangan taruh email/nama/phone di header jika ID cukup.
- Jangan taruh token/JWT/secret di metadata.
- Jangan log full auth claim.
- Jangan expose sensitive metadata di DLQ viewer tanpa access control.
- Pastikan retention metadata mengikuti policy data.
39. Observability Concern
Metadata harus masuk observability secara sengaja.
Recommended log fields:
event.id
event.type
event.version
correlation.id
causation.id
aggregate.id
tenant.id
source.service
messaging.topic
messaging.partition
messaging.offset
consumer.group
schema.id
processing.result
Metric labels harus lebih terbatas:
event.type
consumer.group
result
error.class
Jangan pakai:
event.id as metric label
correlation.id as metric label
aggregate.id as metric label
Itu akan menciptakan high-cardinality problem.
40. PR Review Checklist
Required metadata
- Apakah eventId ada dan stabil?
- Apakah eventType jelas?
- Apakah eventVersion jelas?
- Apakah eventTime UTC dan jelas semantics-nya?
- Apakah sourceService ada?
- Apakah aggregateId ada untuk domain event?
- Apakah partitionKey sesuai aggregate/order requirement?
Traceability
- Apakah correlationId dipropagasikan dari HTTP/request/workflow?
- Apakah causationId diset dari command/event sebelumnya?
- Apakah trace context diteruskan ke Kafka dan consumer?
- Apakah logs consumer mencetak metadata penting?
Idempotency
- Apakah eventId dipakai untuk inbox/dedup?
- Apakah idempotencyKey berbeda jelas dari eventId?
- Apakah retry publish mempertahankan eventId?
- Apakah replay mempertahankan original eventId atau mencatat replay metadata?
Multi-tenancy and actor
- Apakah tenantId berasal dari trusted context?
- Apakah actorId/actorType cukup untuk audit tanpa mengekspos PII?
- Apakah service account dibedakan dari user actor?
Headers vs payload
- Apakah metadata location konsisten dengan standard internal?
- Apakah connector/bridge preserve header yang dibutuhkan?
- Apakah DLQ mempertahankan metadata?
Observability
- Apakah metadata masuk structured logs?
- Apakah metric labels tidak high-cardinality?
- Apakah trace span punya Kafka attributes?
- Apakah dashboard bisa filter by eventType/schemaVersion/consumerGroup?
41. Internal Verification Checklist
Untuk konteks CSG/team, verifikasi:
- Apakah ada standard event metadata internal?
- Apakah metadata disimpan di Kafka headers, payload envelope, atau hybrid?
- Apakah JAX-RS filter membuat/meneruskan correlation ID?
- Apakah trace context dipropagasikan ke Kafka producer/consumer?
- Apakah eventId dibuat di service layer, outbox insert, atau publisher?
- Apakah eventId stabil saat retry publish?
- Apakah outbox table menyimpan metadata lengkap?
- Apakah Debezium/CDC pipeline preserve metadata?
- Apakah DLQ schema mempertahankan original metadata?
- Apakah consumer logs mencetak eventId/topic/partition/offset/correlationId?
- Apakah metrics memakai label yang aman dari high cardinality?
- Apakah tenantId/actorId policy sudah sesuai privacy/security?
- Apakah event metadata masuk event catalog/AsyncAPI?
- Apakah replay tooling mempertahankan metadata atau mencatat replay metadata?
- Apakah ada incident lama yang sulit ditelusuri karena metadata kurang?
- Apakah platform/SRE punya dashboard correlation dari Kafka ke service logs?
42. Senior Engineer Heuristics
Gunakan heuristik berikut:
Jika event tidak punya eventId, consumer idempotency akan rapuh.
Jika event tidak punya correlationId, incident lintas service akan mahal.
Jika event tidak punya causationId, saga dan event loop sulit dianalisis.
Jika tenantId salah, itu bukan bug observability; itu security risk.
Jika partitionKey tidak bisa dijelaskan, ordering guarantee tidak bisa dipercaya.
Jika metadata hilang di DLQ, replay tidak production-safe.
Jika metadata tidak muncul di logs, metadata itu hampir tidak berguna saat incident.
43. Ringkasan
Event metadata adalah fondasi traceability event-driven system.
Payload menjelaskan fakta bisnis.
Metadata menjelaskan identitas, asal, sebab, versi, konteks, waktu, routing, idempotency, tenancy, actor, dan observability event.
Metadata yang baik membuat sistem Kafka:
- bisa di-debug
- bisa diaudit
- bisa di-replay
- bisa di-deduplicate
- bisa dikorelasikan dengan HTTP request
- bisa dikaitkan dengan outbox row
- bisa diamati dari producer sampai consumer
- bisa dianalisis saat DLQ, lag, missing event, duplicate event, dan ordering issue
Tanpa metadata standard, event-driven architecture akan terlihat decoupled saat design review, tetapi menjadi opaque saat production incident.
You just completed lesson 14 in build core. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.
Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.