Shipping Device DB Reference Plan
This document lays out the db_reference design plan for the shipping rate master needed when delivering payment terminal devices from Makassar to merchants. The focus is on the reference data model, integration into the runtime, and its governance.
Companion document:
Goal
This plan ensures that the shipping rate master:
- is stored as structured reference data
- can support
1 primary partner + 2 backups - can separate the merchant-facing display from internal operational details
- can be linked into the runtime shipments in
db_kesles_merchant - can be updated without disturbing transaction history
Design Principles
db_referencestores reference master data and rules that are relatively stable.db_kesles_merchantstores the runtime snapshot when a shipment is created.- Courier partner data is internal-only.
- Services exposed to the merchant are limited to internal categories, not partner service names.
- Rates must be versioned through validity periods, not overwritten without a trace.
Schema Placement
Following the pattern already in merchant_database/db_reference/sql/013_create_merchant_schema.sql, merchant-specific reference data should sit in the merchant schema.
Because this use case is specific to:
- merchant onboarding / fulfillment
- terminal device distribution
- merchant operational pricing
new tables should sit in the schema:
merchant.ref_shipping_partnermerchant.ref_shipping_service- and so on
This approach is cleaner than adding many new tables to public.
Required Reference Entities
Minimum reference entities needed:
1. Courier partner
Stores the partners allowed by the system.
Required core columns:
shipping_partner_idpartner_codepartner_namepriority_rankis_primaryis_activesupports_regularsupports_cargonotescreated_atupdated_at
Notes:
- only partners that pass internal approval are entered into this table
- the priority order determines the default fallback
2. Internal service
Stores the services the system recognizes and may surface in the application layer.
Initial values:
regularcargo
Core columns:
shipping_service_idservice_codeservice_namesort_orderis_active
This table is important so that the UI and API are not directly dependent on the partner's service code.
3. Mapping internal service to partner service
Because each partner has its own service names, a mapping table is needed.
Examples:
- internal
cargomay map to partner serviceJTR - internal
cargomay map to partner serviceGOKIL
Core columns:
shipping_partner_service_idshipping_partner_idshipping_service_idpartner_service_codepartner_service_nameis_active
With this model, the merchant still only knows cargo, while internal fulfillment knows the final partner service code.
4. Origin node
Today the primary origin is Makassar, but it is still safer to make origin a reference.
Core columns:
shipping_origin_idorigin_codeorigin_namecity_idor an equivalent region referenceprovince_idis_defaultis_active
Benefits:
- ready for additional hubs in the future
- not hardcoded at runtime
5. Per-destination partner coverage
This table stores whether a particular partner is active for a particular destination.
Core columns:
shipping_partner_coverage_idshipping_partner_idshipping_service_idorigin_iddestination_city_idregion_group_codeis_availablesupports_codif needed latersla_min_dayssla_max_dayseffective_fromeffective_tois_active
Notes:
destination_city_idmust reference the city/regency table that is the source of truth- if seeds or imports still use names, use a single naming model that matches the region master:
KOTA ...orKABUPATEN ... region_group_codemay flagSULAWESIorNON_SULAWESIfor easier query and rules
6. Shipping rate
This is the core table for the shipping rate master.
Core columns:
shipping_rate_idshipping_partner_idshipping_service_idorigin_iddestination_city_idprice_amountcurrencyprice_unitmin_billable_weight_kgweight_increment_kgrounding_rule_codesla_min_dayssla_max_dayseffective_fromeffective_tois_activerate_sourcerate_notescreated_atupdated_at
Notes:
price_unitis important to distinguish whether the rate applies per kg, per shipment, or with some minimum- in the initial phase the rate is most likely standardized as
per kgwith a minimum billing
7. Fallback rule
Although fallback can be derived from priority_rank, it is still useful to have an explicit rule once the policy grows complex.
Core columns:
shipping_fallback_rule_idorigin_idregion_group_codeshipping_service_idsequence_noshipping_partner_idfallback_reason_codeis_active
Benefits:
- fallback changes do not require code edits
- operational rule audit becomes clearer
8. Destination region grouping
Because the policy differs between Sulawesi and outside Sulawesi, destination grouping is needed.
Design options:
- use a derivative field from province at runtime query time
- store an explicit table mapping destination to region group
For audit and ease of seeding, I recommend the explicit mapping:
SULAWESINON_SULAWESI
Core columns:
destination_region_group_iddestination_city_idregion_group_coderegion_group_nameis_active
Conceptual Relationships
The main relationships:
- one
shipping_partnerhas manyshipping_partner_services - one
shipping_servicemay be used by many partners - one
originhas many coverage and rate entries - one
destination_citymay have many rates depending on partner and service - one
fallback_ruleselects partners according to ordering
Policy Rules That Must Be Captured in Data
The agreed policy must be readable from the reference data:
Sulawesi
- default operational service:
cargo - use the primary partner if coverage and rate are available
- otherwise switch to backups by
sequence_no
Outside Sulawesi
- service can be
regularorcargo - selection depends on weight and coverage
- fallback still follows the partner ordering
Merchant-facing
What is returned to the merchant:
shipping_costestimated_delivery_daysorigin_name
What stays internal:
shipping_partner_idpartner_service_codefallback sequencecoverage flags
Integration Into the db_kesles_merchant Runtime
Reference data alone is not enough. The runtime must store a snapshot when the shipping decision is made.
The runtime will minimally need fields such as:
shipping_service_codeshipping_cost_amountshipping_currencyshipping_eta_min_daysshipping_eta_max_daysshipping_origin_nameresolved_shipping_partner_idinternal onlyresolved_partner_service_codeinternal onlyshipping_rate_reference_idresolved_at
Runtime principles:
- the shipping snapshot does not change even if the reference rate is updated
- the final partner can be used for fulfillment and audit
- the merchant response does not need to expose the final partner
Data Sources and Update Process
The rate data sources need to be clearly defined:
- partner negotiation or quotation results
- partner official rates approved internally
- manual updates by ops, verified by finance
Recommended update process:
- import or input the new rate
- internal review
- set
effective_from - deactivate the old rate via
effective_tooris_active - record source metadata and change notes
Validations Required
Minimum validations:
- there must not be two active rates conflicting for the same combination of partner, service, origin, destination, and period
- inactive partners cannot be used in active fallback
- destinations without a region group cannot reach the runtime
- an active rate must have active coverage
- SLA values must not be empty when a rate is activated
Versioning and Audit
Rates are sensitive operational data. Therefore:
- never overwrite without history
- use
effective_fromandeffective_to - store
rate_source - store
rate_notes - if needed, add an audit table or rely on the runtime migration audit layer in a later phase
Recommended Implementation Order
- finalize the business policy document
- finalize the list of primary and backup partners
- finalize the source of truth for city/regency regions
- create the basic reference table migrations
- seed the internal services and courier partners
- seed the destination region groups
- seed coverage
- seed tariff rates
- design the internal shipping resolver endpoint
- add snapshot fields to the runtime shipment or order
SQL Deliverables to Be Produced After This Plan Is Approved
Likely deliverables:
- create-reference-table migrations under
merchant_database/db_reference/sql/ - seed of active courier partners
- seed of internal services
regularandcargo - seed of destination region groups
- seed of initial coverage and rate from Makassar
- query contract document for the shipping resolver
Open Questions
Things that still need to be decided before final SQL implementation:
- which reference table will be the source of truth for
destination_city_id - the final weight threshold for
regularvscargo - whether rates are stored per kg, per package, or hybrid
- whether ETA
min/max daysis enough or a richer SLA model is needed - whether area-based surcharges are needed
- whether one device shipment is always one origin or eventually multi-origin
Status
Status (2026-06-23): shipped. The reference tables now live in
db_reference(schemamerchant, e.g.merchant.ref_shipping_partner,merchant.ref_shipping_service,merchant.ref_shipping_rate,merchant.ref_shipping_priority_destination) and are read by thecore_apidbreferencelayer andorder_service. The original design narrative below is preserved.
Original plan status: draft for schema design