بنقرة واحدة
awcms-mini-payment-gateway
Kerjakan bagian mana pun dari modul payment_gateway AWCMS-Mini (Issue
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Kerjakan bagian mana pun dari modul payment_gateway AWCMS-Mini (Issue
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | awcms-mini-payment-gateway |
| description | Kerjakan bagian mana pun dari modul payment_gateway AWCMS-Mini (Issue |
payment_gateway (src/modules/payment-gateway, Issue #877, epic #868 SaaS
control plane Wave 1, ADR-0022) adalah modul control-plane KEENAM &
TERAKHIR — Official Optional Business Foundation, opt-in per tenant,
default-disabled, tenant-scoped. Ia menyediakan kapabilitas pembayaran
provider-netral: hosted checkout/session, webhook masuk bertandatangan,
event pembayaran ternormalisasi, refund, retry/DLQ, provider health + circuit
breaker, dan reconciliation. Ia BUKAN general ledger / AR-AP / double-entry
accounting / merchant settlement / tax engine, dan tidak pernah menyimpan
kredensial kartu / PAN (ADR-0022 §11).
webhook/[providerAccountId].ts diautentikasi oleh id akun opaque (bind ke
TEPAT SATU tenant) + verifikasi adapter — bukan sesi JWT tenant.initiateCheckout/
requestRefund commit intent + baris outbox DULU; worker
outbox-dispatch memanggil provider tanpa transaksi terbuka, lalu
finalize di transaksi terpisah. Outage provider → retry/backoff + circuit
breaker + DLQ, TAK PERNAH menahan/rollback transaksi sumber.domain/webhook-security.ts +
webhook-intake.ts): (a) HMAC signature timing-safe; (b) timestamp/freshness
window ≤300s; (c) binding provider/account (payload account_ref ==
akun terikat → cegah cross-tenant substitution); (d) payload size; (e)
anti-replay via event-id PERSISTEN di DB (unique
(tenant, account, provider_event_id) — BUKAN in-memory); (f) ordering
(provider_sequence monotonic). Valid signed webhook update payment TEPAT
SEKALI (loser ON CONFLICT = no-op). Gagal/oversized/duplicate/out-of-order/
stale = tolak fail-closed + audit + reconciliation evidence.domain/endpoint-allowlist.ts): endpoint provider +
callback URL allow-listed per akun; validasi host via new URL() +
host equality (BUKAN startsWith prefix — memory
[[linkedin-media-trust-helper-862]]).process.env — row akun menyimpan POINTER
env:VAR_NAME (domain/secret-ref.ts), TAK PERNAH nilai secret. Tidak di
tabel/event/log/audit. Rotasi = env deployment.domain/masking.ts)
— hanya snippet ter-mask (bukan raw body), referensi provider ter-MASK,
safe error class (tak pernah pesan provider mentah).defaultTenantState:"disabled" + gate di
tests/unit/module-governance-default-disabled.test.ts.module-boundary.test.ts): no reverse dep,
awcms_mini_payment_gateway_* hanya modul sendiri, port payment_outcome
neutral. Konsumsi billing #876 (billing_document_state read + recordPayment
Allocation write) HANYA di composition-root (_support.ts/scripts), jangan
di app/domain payment_gateway.FOR UPDATE + UPDATE
ber-predikat status → 409, ON CONFLICT partial-unique,
replayConcurrentIdempotentWinner. Webhook EXACTLY-ONCE (event-id unique).
Job (dispatch/reconcile/expire) pakai LEASE per-(tenant,job_kind).
JANGAN Promise.all atas satu tx.BEFORE UPDATE saja sejak 102 (#932). Sebelumnya
BEFORE UPDATE OR DELETE + raise tanpa syarat = TIDAK ADA role yang bisa
hapus, termasuk pemilik tabel → retensi mustahil, legal hold tak punya
objek. Batas DELETE sekarang ada di GRANT (awcms_mini_app tidak pernah,
awcms_mini_worker ya), pola usage_metering 087. Kalau menambah tabel
bukti append-only baru: pakai BEFORE UPDATE + grant, JANGAN sertakan
OR DELETE.domain/money.ts).request-parsing/request- validation). Event versioned emit dgn KONSTANTA ter-import LANGSUNG dari
event-type-registry, snapshot same-commit.Adapter provider = External Integration off-by-default. Base HANYA ship
sandbox-adapter.ts (fake, untuk test + docs) di infrastructure/adapter- registry.ts. Provider nyata (Midtrans/Xendit/Stripe) opt-in via composition-root
repo ini lewat registerPaymentProviderAdapter, TAK PERNAH hardcoded di base.
LAN/offline (modul disabled) = 100% tanpa provider.
CONSUMES billing_document_state (#876, read-only) untuk validasi invoice payable.
PROVIDES payment_outcome (_shared/ports/payment-outcome-port.ts) —
settled/refunded diteruskan ke subscription_billing.recordPaymentAllocation
(write path #876 sendiri, idempoten, audited), wired di composition-root.
Migrasi 093 (schema) + 094 (permissions) + 102 (retensi bukti, #932);
jobs payment-gateway:dispatch-outbox|reconcile|expire-sweep|purge.
dataLifecycle: 4 descriptor (domain/lifecycle-keys.ts) mode delegated,
jalur hapus TUNGGAL application/retention-purge.ts. Rantai
webhook_inbox <- normalized_events <- processing_attempts di-purge
FK-safe (daun dulu; tiap tingkat HANYA hapus baris tanpa anak yang masih
hidup — umur saja tidak aman, induk selalu lebih tua dari anaknya). Legal
hold di satu mata rantai memblokir SELURUH rantai (fail-closed);
reconciliations independen, di-hold terpisah. Test batas grant WAJIB
assert SQLSTATE 42501 — "sekadar throw" juga dipenuhi 23503 dari FK
anak dan lolos walau grant salah lebar.
Sinyal fleet-wide (#930): application/control-plane-signals.ts —
deadLetterDepth (outbox status='dead') + webhookBacklog (inbox
status='received'), dibaca bun run control-plane:fleet-sweep. DLQ BUKAN
backlog: tiap barisnya kerja provider yang sudah habis retry dan tak akan
pernah dicoba lagi tanpa aksi operator — itu kehilangan permanen, bukan
antrean yang terkuras sendiri.
Lihat src/modules/payment-gateway/README.md untuk detail ERD/tabel/state
machine.
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