Primary Database
Source of truth untuk write, versioning, relationship, idempotency, policy, dan ledger.
Strong consistencyDesain fleksibel untuk perubahan bisnis: JSON sebagai write model evolutif, Manticore sebagai read/search projection, dan tabel typed untuk integritas transaksi serta komisi.
Source of truth untuk write, versioning, relationship, idempotency, policy, dan ledger.
Strong consistencyProfil, role, capability, requirement, dan konfigurasi sparse yang dapat berkembang tanpa DDL rutin.
Flexible schemaProjection terdenormalisasi untuk pencarian, filter, CMS, dan dashboard. Disposable dan dapat di-reindex.
Eventually consistentMasterdata, AWB, dan Billing tetap menjadi pemilik data masing-masing. S&DP menyimpan external ID.
No authoritative duplicationOwnership per service dan akses melalui API/event.
Role taxonomy dan default capability, bukan table-per-subclass.
Behavior dipilih berdasarkan capability, workflow, dan policy.
Satu party dapat menerima banyak role dan capability tanpa menggandakan identity.
JSON tidak dipakai untuk menggantikan constraint. Uang, relationship penting, idempotency, validity period, dan lifecycle transaksi tetap typed.
v2.2.0 — Portable Partitioning SOP alignment: PARTITION BY LIST COLUMNS (partition_key, is_active) across Aurora MySQL, MySQL, MariaDB, and OceanBase. Every partitioned table uses application-maintained partition_key BIGINT (YYYYMM from updated_at), is_active, and partition_created_time; each month is pre-created as an _active and _inactive pair. Inactive pairs are archive-then-drop retention targets.
Antipattern: Random UUIDv4 (gen_random_uuid())
Counter-Design: Time-Ordered UUIDv7 (gen_ordered_uuid() / UUID_TO_BIN(UUID(), 1))
Eliminates B-Tree Index FragmentationAntipattern: Hardcoded CHECK (status IN (...))
Counter-Design: Zero-DDL Lookup Tables
No AccessExclusiveLock on ADDAntipattern: Jaywalking / JSON inline createdBy
Counter-Design: Typed FK created_by_account_id
Engine-Enforced FK IntegrityAntipattern: Duplicate fields in JSON & Metadata
Counter-Design: Canonical JSON Document + typed query fields
Prevents Update AnomaliesAntipattern: Read version without lock
Counter-Design: SKIP LOCKED relay + optimistic aggregate version
Safe Under High Concurrent WritesAntipattern: Unconditional CTE UPDATE candidate
Counter-Design: Strict INNER JOIN on accepted receipts
Prevents False Positive published_atAntipattern: Unpartitioned transaction tables with full table scans
Counter-Design: LIST COLUMNS (partition_key, is_active) active/inactive pairs
Optimized Monthly Scans & Settled FilteringAntipattern: Missing CDC watermarks requiring heavy full extractions
Counter-Design: Native ON UPDATE CURRENT_TIMESTAMP(6) CDC Watermarks
Low-Latency CDC Ingestion to SnowflakeAntipattern: Hard deletes losing audit trails & state history
Counter-Design: Universal deleted_at; composite indexes (MySQL has no partial indexes)
Audit-Compliant Soft DeletesTwo latest versions only: v2.1.0 introduced the Account Party model and Operational Transaction aggregate, but used non-portable RANGE partitioning and incomplete partition-key design. v2.2.0 is a backward-compatible partition refinement driven by the draft DBE SOP: LIST COLUMNS (partition_key, is_active), BIGINT keys, active/inactive monthly pairs, and explicit application ownership.
| Concern | v2.1.0 | v2.2.0 | Reason |
|---|---|---|---|
| Partition method | RANGE (partition_key) | LIST COLUMNS (partition_key, is_active) | Portable common denominator: OceanBase, MySQL, MariaDB. |
| Partition key | INT YYYYMM | BIGINT YYYYMM, app-derived from updated_at | Matches SOP and permits controlled row movement after update. |
| Lifecycle | is_active was indexed only | is_active is a partition dimension | Retain/drop inactive data without affecting current transactions. |
| Key rule | PK omitted is_active | Every PK/unique key includes both partition columns | Required for MySQL/MariaDB partitioned unique keys. |
| Period operations | Static partitions plus catch-all | Pre-create monthly _active/_inactive pairs; no catch-all | Missing periods fail fast; automation can create and retire periods predictably. |
| Retention | No executable safety process | Archive → evidence → drop only pYYYYMM_inactive | Partition-level removal preserves active rows. |
| Referential integrity | Mixed FK expectations | Service-side validation on partitioned tables; DB FKs on reference tables | MySQL/MariaDB disallow FKs on partitioned InnoDB tables. |
updated_at in UTC.partition_key = YYYYMM(updated_at).is_active=1 until final settlement, otherwise 0.INFORMATION_SCHEMA.PARTITIONS and pruning plans.DROP PARTITION pYYYYMM_inactive.Baca Manticore
Text search, faceting, filter, pagination, dan dashboard.
Baca primary/service owner
Candidate ID dari Manticore dapat di-hydrate bila perlu.
Jangan percaya index
Evaluasi primary DB dan policy engine.
Jangan percaya index
Gunakan activity, policy version, dan ledger typed.
| Data | Source of Truth | Yang disimpan S&DP |
|---|---|---|
| Customer/account, PIC, kontak | Masterdata | customer_account_id |
| Alamat & wilayah | Masterdata | address_id |
| File dokumen | Attachment/Masterdata | ID + status verifikasi S&DP |
| Agent role & hierarchy | S&DP | JSON document + typed relationship |
| AWB, sender, recipient, status | AWB Service | ID transaksi + immutable facts untuk kalkulasi |
| Policy komisi | S&DP | Versioned policy JSON |
| Accrual/reversal komisi | S&DP | Typed immutable ledger |
| Invoice/payment/settlement | Billing | billing_external_id |
| Search projection | Derived | Manticore; rebuildable |
Tambah role, capability, document requirement, workflow, dan policy sebagai data.
Zero DDLBuat policy version baru dengan validity period. Ledger lama tetap menunjuk versi lama.
Zero DDLTambah field JSON, naikkan schema version, validasi dengan JSON Schema, lalu update projection.
Zero DDL primary*Jika belum tersedia sebagai invariant typed, lakukan migration dan update accounting rules.
DDL layakTambah relationship type dan metadata selama constraint existing cukup.
Zero DDLKonsep fundamental baru; jangan dipaksakan ke JSON.
DDL wajib* Perubahan searchable attribute mungkin tetap memerlukan perubahan konfigurasi/index Manticore. Zero-DDL database tidak berarti zero-governance.
Alur tulis selalu selesai di AWS Aurora MySQL 8.0 terlebih dahulu. Manticore diproyeksikan asinkron dan tidak dipakai untuk keputusan approval atau uang.
Self-service stores a typed REFERRED_BY edge. CMS registration stores only the external operator ID.
Touches: account, account_relationship, outbox_event
Document status lives in bounded JSON; approval audit is an idempotent typed activity.
Touches: account, activity_event, outbox_event
Create, receive, and handover use unique keys. Commission pins the activity and policy version.
Touches: activity_event, policy_document, ledger_entry
Billing callback ID is unique. Projection receipts make consumer processing auditable.
Touches: ledger_entry, outbox_event, projection_receipt
See USER-JOURNEYS.md for six complete sequence diagrams and exact columns touched.
The complete executable runbook is partition-operations.sql: application computes partition_key=YYYYMM(updated_at), DBE pre-creates one _active and one _inactive LIST COLUMNS partition per month, and retention archives then drops only inactive partitions.
Snippets are abbreviated for reading. The transactionally complete, rerunnable examples are in scenario-queries.sql; DDL and helper functions are in schemas.sql.
Hindari dual-write DB + Manticore pada request yang sama.
Projection membawa sourceVersion; event lama tidak boleh menimpa event baru.
Deduplicate berdasarkan event ID atau aggregate ID + version.
JSON memakai schema_version, JSON Schema, validation, dan migration strategy.
Manticore harus dapat dibangun ulang sepenuhnya dari primary DB.
Gunakan decision table/DSL terbatas, bukan arbitrary SQL atau JavaScript.