بنقرة واحدة
awcms-mini-domain-event-runtime
Kerjakan bagian mana pun dari modul domain_event_runtime AWCMS-Mini (Issue
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Kerjakan bagian mana pun dari modul domain_event_runtime AWCMS-Mini (Issue
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Kelola/konsumsi sistem Module Management AWCMS-Mini (registry, validasi komposisi registry base, tenant lifecycle enable/disable, settings, permission sync/status, navigation, job registry, health/readiness). Gunakan saat menambah field descriptor baru (permissions/navigation/settings/jobs/health) di modul lain, saat menambah modul domain baru langsung di `src/modules/` dan perlu memverifikasi registry base tetap valid (`bun run modules:compose:check`), saat menyelidiki kenapa suatu modul terlihat degraded/orphaned, atau saat mengubah perilaku enable/disable/settings/health module_management sendiri. Sesuai src/modules/module-management/README.md, epic
Pilih dan jalankan profil deployment AWCMS-Mini (development/staging/production/offline-LAN). Gunakan saat menyiapkan deployment baru, memutuskan LAN-first vs registry-based, atau deploy ke Coolify. Sesuai doc 18 dan deployment-profiles.md/deploy-coolify.md.
Kelola sistem log/audit/metrics AWCMS-Mini yang sudah aktif — correlation ID lintas hop, retensi/purge audit log, extension point untuk consumer eksternal (alerting/export/SIEM), dan metrics port (counter/histogram/gauge berkardinalitas rendah untuk request/pool/job/provider). Gunakan saat menambah endpoint baru (correlation ID otomatis), menjadwalkan purge audit log, memasang consumer log/audit di aplikasi turunan, atau menambah/mengonsumsi metrik operasional. Berbeda dari awcms-mini-audit-log (APA yang wajib diaudit) — skill ini tentang BAGAIMANA sistem log/audit/metrics itu sendiri dikelola, sesuai Issue
Kerjakan bagian mana pun dari modul tenant_provisioning AWCMS-Mini (Issue
Triase dan perbaiki temuan CodeQL code scanning AWCMS-Mini (github.com/ahliweb/awcms-mini/security/code-scanning). Gunakan saat diminta "analisis code scanning"/"perbaiki CodeQL", saat sebuah PR gagal check CodeQL, atau saat menemukan alert baru. Mendokumentasikan satu TRUE-positive terkonfirmasi (password sungguhan → digest cepat yang dipersist = oracle cracking offline, plus dua "fix" yang membungkam alert tanpa memperbaiki apa pun) dan lima false-positive nyata (name-heuristic password, incompatible-types typeof/null, URL substring-sanitization di test mock, dua kasus dismiss resmi tanpa reformulasi kode, dan Bun.SQL tagged-template null-cast) plus pola "unused-local-variable di test kadang menandai coverage gap" — supaya tidak diinvestigasi ulang dari nol.
Daftarkan tabel bervolume tinggi ke registry lifecycle AWCMS-Mini (retensi/partisi/arsip/legal hold/purge), atau kerjakan bagian mana pun modul data_lifecycle sendiri. Gunakan saat menambah tabel baru yang tumbuh besar (log, telemetry, outbox, queue, provider attempt) dan butuh kebijakan retensi/purge aman, saat membuat/melepas legal hold, atau saat mengubah engine dry-run/archive/purge/archive-port. Sesuai Issue
| name | awcms-mini-domain-event-runtime |
| description | Kerjakan bagian mana pun dari modul domain_event_runtime AWCMS-Mini (Issue |
domain_event_runtime (src/modules/domain-event-runtime, Issue #742, epic
platform-evolution #738 Wave 1) adalah System Foundation (type: "system",
ADR-0013 §1/§6) — outbox domain-event transaksional & versioned plus
dispatcher-nya. Fan-in tertinggi kedua di repo (←7 modul), setelah logging
(←13).
Baca src/modules/domain-event-runtime/README.md untuk peta tabel/endpoint.
Skill ini merangkum yang tidak jelas dari membaca satu file: kenapa model
eksekusinya sengaja berbeda dari setiap outbox lain di repo, invariant ordering
head-of-line, dan satu cycle import yang masih hidup hari ini.
Melengkapi (bukan menggantikan) awcms-mini-new-event (cara menambah event +
AsyncAPI), awcms-mini-idempotency, awcms-mini-abac-guard,
awcms-mini-integration. Pakai skill ini untuk konteks runtime-nya:
bagaimana event dipersist, di-fan-out, di-dispatch, di-retry, dan di-replay.
Repo ini sudah punya TIGA preseden outbox/queue single-purpose nyata yang sengaja diikuti BENTUK-nya, bukan digantikan:
sync-storage — awcms_mini_object_sync_queue + dispatchObjectSyncQueueemail — awcms_mini_email_messages + dispatchEmailQueuesocial-publishing — awcms_mini_social_publish_jobs + dispatchSocialPublishQueueMasing-masing adalah queue single-purpose milik SATU modul, dengan tepat satu "consumer" implisit (dispatcher-nya sendiri memanggil satu provider eksternal). Modul ini adalah padanan generik, provider-neutral, multi-consumer: satu event bisa fan-out ke BANYAK consumer terdaftar, dengan ordering eksplisit per-aggregate/order-key — tidak pernah total order global lintas aggregate yang tak berhubungan.
application/append-domain-event.ts's appendDomainEvent(tx, tenantId, input)
di dalam transaksi bisnisnya sendiri (callback withTenant). Hanya
plain DB write (tanpa panggilan network/provider, ADR-0006): baris event
(awcms_mini_domain_events) + satu baris delivery per consumer yang cocok
(awcms_mini_domain_event_deliveries) ditulis atomik bersama perubahan state
sumbernya. Kalau transaksi caller rollback, tidak ada yang persist.infrastructure/consumer-registry.ts's
DOMAIN_EVENT_CONSUMERS adalah array source-code polos yang direview
(bukan panggilan registrasi runtime). Fan-out diputuskan saat publish
dari registry ini, bukan saat dispatch.application/dispatch-domain-events.ts's
dispatchDomainEventsForTenant (dijalankan bun run domain-events:dispatch,
di atas shared worker runner src/lib/jobs/job-runner.ts) meng-claim,
mengeksekusi, dan memfinalisasi delivery yang jatuh tempo per consumer.application/consumer-effect.ts's
applyConsumerEffectOnce memberi handler consumer mana pun idempotency
ber-key event-ID (awcms_mini_domain_event_consumer_effects), sehingga event
yang dikirim ulang (crash/restart atau replay eksplisit) tidak bisa
menduplikasi efek samping.dead_letter. Replay
(application/delivery-replay.ts) adalah aksi admin yang permission-gated,
wajib-alasan (1-500 char), idempotent, dan diaudit — membuat baris delivery
BARU yang mereferensikan aslinya, dan menolak (409) bila consumer
terdaftar sudah tidak mendukung eventVersion delivery itu.application/consumer-state-directory.ts memungkinkan
operator mem-pause pasangan (tenant, consumer) tertentu; dispatcher berhenti
meng-claim delivery untuknya sampai di-resume.Setiap dispatcher outbox lain di repo ini memakai bentuk 3-fase berbasis lease (CLAIM di transaksi pendek → CALL di luar transaksi apa pun → FINALIZE di transaksi pendek kedua) karena fase CALL-nya melakukan panggilan network eksternal nyata (upload, SMTP, provider API), yang ADR-0006 larang dijalankan di dalam transaksi DB.
Consumer di modul ini adalah handler same-process, DB-only, tanpa I/O
eksternal. dispatch-domain-events.ts karena itu menjalankan claim-check +
handler + finalize-on-success dalam SATU transaksi: crash di tengah handler
me-rollback seluruh transaksi otomatis, mengembalikan baris delivery ke
pending tanpa state lease/stale-claim yang pernah teramati durabel. Inilah
yang membuat recovery crash/restart benar secara konstruksi, bukan
berbasis lease-timeout — dan kenapa
awcms_mini_domain_event_deliveries.status tidak punya nilai transient
"claimed".
Jangan mengubah ini menjadi 3-fase "supaya konsisten dengan dispatcher
lain", dan jangan menambah consumer yang melakukan I/O eksternal ke jalur
ini. Consumer out-of-transaction / broker-backed (lihat
infrastructure/broker-adapter-port.ts) memang butuh bentuk lease itu kembali —
tapi jalur dispatch-nya belum dibangun (sengaja tidak spekulatif). Kalau butuh
provider eksternal per event, itu pekerjaan integration_hub's outbound
subscription, bukan handler di sini.
order_key default-nya aggregateType:aggregateId (domain/envelope.ts's
deriveOrderKey), boleh di-override producer. Query head-of-line dispatcher:
SELECT DISTINCT ON (order_key) ... ORDER BY order_key, event_sequence
memilih, per order_key, hanya satu delivery pending tertua untuk consumer
tertentu — dihitung SEBELUM difilter backoff (next_attempt_at). Ini
disengaja: baris head-of-line yang sedang di-backoff dengan benar men-stall
order_key-nya sendiri tanpa membiarkan event berikutnya untuk key yang sama
menyalip, sementara order_key lain tetap maju setiap pass. Jangan pindahkan
filter next_attempt_at ke sebelum DISTINCT ON — itu diam-diam merusak
ordering per-aggregate.
appendDomainEvent menolak (melempar UnregisteredDomainEventTypeError)
mempersist event yang (eventType, eventVersion)-nya tidak terdaftar di
domain/event-type-registry.ts's DOMAIN_EVENT_TYPE_REGISTRY. Inilah mekanisme
di balik "event type/version tidak bisa drift diam-diam".
tests/unit/domain-event-registry-parity.test.ts mengecek silang registry ini
terhadap asyncapi/awcms-mini-domain-events.asyncapi.yaml dua arah (entri
registry tanpa channel = gagal; event type yang di-subscribe consumer terdaftar
tanpa entri registry = gagal), dan events.publishes di module.ts dicek
terhadap AsyncAPI oleh checkModuleEventChannels (scripts/api-spec-check.ts,
bagian bun run check).
Menambah producer: tambahkan type/version ke DOMAIN_EVENT_TYPE_REGISTRY +
channel AsyncAPI yang cocok DULU, baru panggil appendDomainEvent di transaksi
modulmu. Menambah consumer: tambahkan entri ke DOMAIN_EVENT_CONSUMERS yang
event type/version-nya sudah ada di registry.
Keduanya terdaftar terhadap satu event referensi self-contained,
awcms-mini.domain-event-runtime.sample.recorded — sengaja tidak terikat logika
bisnis modul lain di foundation issue ini (preseden "foundation issue ships zero
real business integrations").
logging.sample_event_audit_projector — consumer lintas-modul
same-process: memanggil recordAuditEvent publik milik logging (panggilan
lintas-modul yang sama yang sudah dilakukan ~10 modul lain langsung — audit
logging adalah infra fondasional, bukan capability domain di balik port
ADR-0011).domain_event_runtime.activity_rollup_projector — consumer proyeksi
read-model: memelihara tabel rollup denormalisasinya sendiri,
awcms_mini_domain_event_activity_daily, tanpa menyentuh tabel modul
reporting (no shared-table write, ADR-0013 §6).Consumer NYATA (non-referensi) pertama datang dari luar: reporting's
reporting.event_activity_projector (Issue #753) dan integration_hub's
outbound fanout consumer (Issue #754) — keduanya didaftarkan DI SINI, di
consumer-registry.ts. Lihat §Cycle di bawah: arah registrasi itulah akar
masalah arsitektural yang masih terbuka.
Ada cycle import tingkat modul yang hidup hari ini, dan kedua gate yang seharusnya menangkapnya lolos hijau:
domain-event-runtime/infrastructure/consumer-registry.ts
-> integration-hub/application/outbound-fanout-consumer
integration-hub/application/outbound-fanout-consumer.ts
-> domain-event-runtime/application/consumer-effect
Kenapa kedua gate buta:
tests/unit/module-boundary-cycles.test.ts hanya memindai application/ +
domain/ sebagai direktori sumber. Sisi keluar cycle ini ada di
infrastructure/, jadi aImportsB terbaca false.bun run modules:dag:check memercayai deklarasi dependencies di
module.ts — dan module.ts modul ini mendeklarasikan
["tenant_admin", "identity_access", "logging"] saja, padahal
consumer-registry.ts nyata-nyata mengimpor integration_hub DAN
reporting. Edge-nya tidak dideklarasikan → graf yang dicek tidak punya
edge itu → tidak ada yang bisa ditemukan.Satu gate memindai direktori yang salah; gate satunya memercayai deklarasi yang
tidak sinkron dengan kode. Akar sesungguhnya: deklarasi dependencies bisa
bohong tanpa ada yang protes.
Kalau kamu mengerjakan #826: memperluas direktori yang dipindai cycles-test ke
infrastructure/ + api/ akan langsung merah — itu justru tujuannya.
Pemutusan cycle-nya kemungkinan lewat port di _shared/ports/ (pola yang sudah
dipakai 12 port lain) atau dengan membalik arah registrasi consumer
(integration-hub mendaftarkan dirinya sendiri, bukan runtime yang mengimpornya).
Sampai #826 ditutup: jangan tambah import baru dari consumer-registry.ts ke
application/ modul lain — setiap tambahan memperdalam cycle yang sama dan
tetap tidak akan ditangkap gate mana pun.
ENABLE+FORCE ROW LEVEL SECURITY dan policy standar tenant_id = current_setting(...)::uuid
(migration 056); setiap query aplikasi juga memfilter tenant_id eksplisit
(defense in depth).domain/envelope.ts's validateDomainEventPayload
hard-reject (tidak pernah persist) payload dengan nama key berbentuk
credential (password/token/apiKey/secret/credential/authorization
— sengaja LEBIH SEMPIT dari REDACTION_KEYS penuh di _shared/redaction.ts,
yang juga memuat PII biasa seperti email/phone yang mungkin memang
dibutuhkan consumer sah) ATAU nilai berbentuk credential terlepas dari nama
key-nya (memakai ulang findSecretShapedValues dari _shared/redaction.ts
tanpa modifikasi — JWT/PEM/AWS key/Bearer header/connection string). Cap
payload 64 KiB di kode aplikasi DAN sebagai backstop CHECK di DB.domain/payload-redaction.ts menerapkan
redactSensitiveAttributes penuh (termasuk PII) ke setiap payload yang keluar
lewat fungsi baca admin/API di application/domain-event-directory.ts.
Payload mentah yang diterima handler consumer secara internal tidak pernah
di-redact (ia butuh data aslinya) — jangan tukar dua jalur ini.domain_event_runtime.deliveries.replay),
wajib-alasan, Idempotency-Key, diaudit.infrastructure/broker-adapter-port.ts mendefinisikan
port opsional; tidak ada adapter terdaftar secara default. Setiap deployment,
termasuk offline/LAN, men-dispatch murni lewat PostgreSQL + registry
in-process.| Tabel | Fungsi |
|---|---|
awcms_mini_domain_events | Outbox-nya sendiri — append-only. |
awcms_mini_domain_event_deliveries | State delivery/retry/dead-letter per (event, consumer). |
awcms_mini_domain_event_consumer_effects | Marker idempotency efek samping ber-key event-ID, reusable. |
awcms_mini_domain_event_consumer_state | Flag pause/resume per (tenant, consumer). |
awcms_mini_domain_event_replays | Jejak audit replay, append-only. |
awcms_mini_domain_event_activity_daily | Tabel rollup milik consumer proyeksi referensi. |
GET/POST /api/v1/domain-events/{events,deliveries,consumers} —
openapi/modules/domain-event-runtime.openapi.yaml. API admin read-mostly;
satu-satunya mutasi adalah replay dan pause/resume. Consumer tidak pernah
dibuat/diedit lewat API — mereka registry source-code statik yang direview.
bun run domain-events:dispatch (scripts/domain-events-dispatch.ts) —
disarankan tiap 30-60 detik via cron/systemd timer. Murni PostgreSQL/in-process,
aman di deployment offline/LAN.
appendDomainEvent di luar transaksi bisnis caller.appendDomainEvent akan melempar.DISTINCT ON (order_key).consumer-registry.ts ke application/ modul
lain selama #826 masih terbuka.Wiring producer/consumer modul nyata yang sudah ada (sebagian sudah menyusul
lewat #747/#749/#753/#754); jalur dispatch broker-backed; retensi/purge tabel
event (didelegasikan ke data_lifecycle, lihat awcms-mini-data-lifecycle);
materialized view milik modul reporting di atas aktivitas event.
tests/unit/domain-event-{registry-parity,runtime-consumer-registry,runtime-envelope,runtime-retry}.test.ts
dan tests/integration/domain-event-runtime.integration.test.ts. Jalankan
bun test dengan DATABASE_URL — tanpa itu seluruh test integration dilewati
diam-diam.