Faisalaffan Blog
|
🇮🇩
Faisalaffan Blog
Produk31 menit baca

Truck Utilization 65% → 79%, Fuel Theft Terdeteksi Bulan Pertama — Arsitektur Digital Mining yang Saya Bangun

Bagaimana saya membangun hub-and-spoke platform untuk 3 site tambang di Kalimantan — fleet management real-time, HSE monitoring otomatis, dan mine planning analytics yang langsung mendeteksi pencurian BBM di bulan pertama deployment.

Faisal Affan
Faisal Affan
Diterbitkan
Truck Utilization 65% → 79%, Fuel Theft Terdeteksi Bulan Pertama — Arsitektur Digital Mining yang Saya Bangun

Engineering Case Study: HPU Digital Mining Platform

"To be the first class total mining services solution — through technology adoption and operational excellence." — Visi PT Harmoni Panca Utama

Context

PT Harmoni Panca Utama (HPU) adalah salah satu perusahaan mining services terbesar di Indonesia, beroperasi di multi-site Kalimantan (Timur, Tengah, dan Utara) dengan 1,000-5,000+ karyawan dan armada alat berat yang masif. Saya berkontribusi dalam perancangan dan pengembangan digital platform yang mengintegrasikan Fleet Management, HSE monitoring, dan mine operations analytics untuk mendukung visi Operational Excellence HPU.

Proyek ini mentransformasi operasional tambang HPU dari proses yang sebagian besar manual — pencatatan kertas, komunikasi radio, spreadsheet Excel — menjadi platform digital terintegrasi yang memberikan visibility end-to-end ke seluruh operasi lintas site.

Artikel ini membedah tantangan teknis, arsitektur, dan keputusan engineering di balik pembangunan platform ini.


🏔️ 1. The Challenge

Profil Operasional HPU

PT Harmoni Panca Utama menjalankan operasi tambang batu bara di beberapa site strategis di Kalimantan:

Kondisi Sebelum Digitalisasi

Aspek Kondisi Lama Dampak
Fleet Tracking Radio HT + pengawas visual Dispatcher tidak tahu posisi semua unit secara real-time
Cycle Time Catat manual di kertas oleh checker Data terlambat masuk, sering tidak akurat, sulit dianalisis
HSE Reporting Form kertas → input manual ke Excel Incident report memakan waktu berjam-jam, analytics terbatas
Fuel Management Catat manual di SPBU site Estimasi konsumsi tidak akurat, rawan kebocoran/penyalahgunaan
Mine Planning Software di PC kantor, tidak terintegrasi Gap antara planning dan eksekusi di lapangan
Multi-Site Visibility Laporan mingguan via email Management di Jakarta tidak punya real-time visibility
The Cost of Manual Operations

Estimasi konservatif: 8-12% potensi produktivitas hilang karena information lag — dispatcher mengalokasikan truk berdasarkan informasi yang sudah telat 10-15 menit, cycle time tercatat tidak akurat, dan keputusan maintenance bersifat reaktif (rusak baru perbaiki) bukan proaktif. Dalam skala operasi HPU, ini bernilai miliaran rupiah per bulan.

Tantangan Engineering

  1. Multi-Site Architecture: Platform harus melayani beberapa site sekaligus, dengan masing-masing memiliki koneksi internet yang berbeda-beda kualitasnya — dari VSAT hingga 4G.
  2. Offline-First di Remote Site: Site di Kalimantan Utara (Kelubir-Bulungan) sangat terpencil — sistem harus tetap berjalan saat koneksi putus.
  3. Real-Time Fleet Tracking: Ratusan unit bergerak simultan, memerlukan update posisi setiap beberapa detik tanpa membanjiri bandwidth yang terbatas.
  4. Role-Based Access Multi-Level: Dari operator di lapangan, supervisor site, hingga manajemen di kantor pusat Jakarta — setiap level butuh view yang berbeda.
  5. Integration Complexity: Menyatukan data dari GPS tracker, fuel sensor, weighbridge, dan sistem mine planning yang sudah ada.
  6. Regulatory Compliance: Data operasional harus sesuai dengan regulasi Kementerian ESDM dan standar lingkungan untuk green mining.

🏗️ 2. Architecture Overview

High-Level System Architecture

Platform dibangun dengan arsitektur Hub-and-Spoke — setiap site memiliki edge server lokal yang memproses data secara mandiri, kemudian disinkronisasi ke central hub di cloud.

graph TD
    subgraph "Site Kaltim - Kutai Kartanegara"
        A1[GPS Tracker Fleet] -->|MQTT| B1[Edge Server Kaltim]
        A2[Fuel Sensor] -->|Modbus/TCP| B1
        A3[Weighbridge] -->|API| B1
        B1 -->|Local Dashboard| C1[Site Control Room]
    end

    subgraph "Site Kalteng - Barito Utara"
        A4[GPS Tracker Fleet] -->|MQTT| B2[Edge Server Kalteng]
        A5[Fuel Sensor] -->|Modbus/TCP| B2
        B2 -->|Local Dashboard| C2[Site Control Room]
    end

    subgraph "Site Kaltara - Bulungan KMO"
        A6[GPS Tracker Fleet] -->|MQTT| B3[Edge Server Kaltara]
        A7[Fuel Sensor] -->|Modbus/TCP| B3
        B3 -->|Local Dashboard| C3[Site Control Room]
    end

    B1 -->|Sync via HTTPS| D[Central Platform - Cloud]
    B2 -->|Sync via HTTPS| D
    B3 -->|Sync via HTTPS/VSAT| D

    D --> E[Central Dashboard - Jakarta HQ]
    D --> F[Analytics & BI Engine]
    D --> G[HSE Management Module]
    D --> H[Mine Planning Integration]
    D --> I[(Central Database)]

Data Flow: Field to Management

sequenceDiagram
    participant F as Fleet (GPS/Sensor)
    participant E as Edge Server (Site)
    participant DB as Local DB
    participant C as Central Cloud
    participant D as Dashboard (HQ)
    participant M as Management App

    F->>E: Raw telemetry (MQTT, 5-sec interval)
    E->>E: Normalize, validate, buffer
    E->>DB: Store locally (always available)
    E->>E: Process rules (geofence, speed, idle)

    alt Koneksi cloud tersedia
        E->>C: Batch sync (compressed, delta)
        C->>C: Aggregate multi-site data
        C->>D: Push real-time update (WebSocket)
        C->>M: API for mobile app
    else Koneksi putus
        E->>DB: Continue buffering
        Note over E,DB: Site tetap beroperasi normal
    end

    Note over E,C: Saat koneksi pulih
    DB->>E: Read buffered data
    E->>C: Bulk sync (catch-up)
    C->>C: Deduplicate & merge

Key Architecture Decisions:

Hub-and-Spoke vs Full Cloud

Awalnya dipertimbangkan arsitektur full cloud — semua data langsung dikirim ke cloud. Tapi konektivitas di site Kaltara (KMO Bulungan) hanya via VSAT 512 kbps shared. Arsitektur hub-and-spoke memastikan setiap site mandiri secara operasional meski koneksi ke cloud terputus total.

Edge Processing untuk Real-Time Alerting

Alert kritis (geofence breach, overspeed, engine anomaly) diproses di edge server, bukan di cloud. Latency ke cloud bisa 1-3 detik, tapi alert safety harus sub-second. Edge server menjalankan rule engine lokal yang langsung push ke control room.

MQTT untuk Field-to-Edge, HTTPS untuk Edge-to-Cloud

MQTT digunakan antara GPS tracker dan edge server karena lightweight dan handal di koneksi flaky. Tapi untuk edge-to-cloud sync, dipilih HTTPS karena lebih mudah di-manage melalui firewall dan proxy corporate, dan bandwidth sudah cukup karena data di-batch dan dikompresi.

Multi-Tenant dengan Site Isolation

Meski satu platform, setiap site memiliki data isolation yang ketat. Supervisor di Site Kaltim tidak bisa melihat data operasional Site Kaltara, kecuali memiliki role management yang sesuai. Ini penting untuk keamanan data kontrak klien yang berbeda di tiap site.


🛠️ 3. Technology Stack

Technology Peran Alasan
Golang Core backend services, API gateway High-concurrency, low memory footprint, cocok untuk handle ribuan koneksi telemetri
PostgreSQL Primary database (central) ACID compliance, PostGIS untuk spatial queries, mature ecosystem
Apache Kafka Event streaming (central hub) Durable event log, replay capability, multi-consumer support
Redis Real-time state cache Fleet current state, session management, rate limiting
gRPC Inter-service communication Low-latency, strongly-typed, efficient untuk internal services

Core Data Schema: Fleet Telemetry

PropertyTypeDescription
device_id string Unique identifier GPS tracker (format: SITE-TYPE-NNN, e.g. KTM-DT-042 = Kaltim Dump Truck #42).
unit_code string Kode unit alat berat sesuai register HPU (e.g. HD785-007).
timestamp time.Time UTC timestamp saat data di-capture oleh GPS tracker.
latitude float64 Koordinat GPS latitude (WGS84).
longitude float64 Koordinat GPS longitude (WGS84).
speed float64 Kecepatan kendaraan dalam km/h.
heading float64 Arah hadap kendaraan dalam derajat (0-360).
ignition boolean Status ignition on/off — krusial untuk menghitung idle time vs productive time.
fuel_level float64 Level bahan bakar dalam liter (dari fuel sensor analog).
payload_ton float64 Berat muatan dump truck dalam ton (dari payload monitoring system atau weighbridge).
engine_hours float64 Total jam operasional mesin (hour meter) — basis untuk jadwal maintenance.
site_id string Identifier site: 'KTM' (Kaltim), 'KTG' (Kalteng), 'KTR' (Kaltara).

📁 4. Project Structure

  • hpu-mining-platform
    • services
      • fleet-service
        • main.go
        • telemetry_handler.go
        • dispatch_optimizer.go
        • geofence_evaluator.go
        • cycle_time_calculator.go
      • fuel-service
        • main.go
        • consumption_tracker.go
        • anomaly_detector.go
        • refueling_validator.go
      • hse-service
        • main.go
        • incident_handler.go
        • safety_rules.go
        • inspection_scheduler.go
      • sync-service
        • main.go
        • edge_sync.go
        • conflict_resolver.go
        • compressor.go
      • auth-service
        • main.go
        • rbac.go
        • site_isolation.go
    • edge-server
      • main.go
      • mqtt_ingestion.go
      • local_rule_engine.go
      • sync_manager.go
      • fuel_reader.go
    • proto
      • telemetry.proto
      • fleet.proto
      • hse.proto
      • fuel.proto
    • dashboard
      • src
        • pages/
        • components/
        • hooks/
      • package.json
    • mobile-app
      • src/
      • package.json
    • infra
      • docker-compose.yml
      • terraform/
      • monitoring/

🔍 5. Feature Deep Dives

Feature #1: Fleet Management System (FMS) & Real-Time Dispatch

Problem: Dispatcher di control room mengandalkan radio HT untuk mengarahkan armada. Dengan puluhan unit dump truck dan beberapa excavator beroperasi simultan, dispatcher tidak memiliki gambaran real-time posisi dan status setiap unit. Akibatnya, truk sering mengantre di satu loading point sementara loading point lain idle.

Solution: Fleet Management System real-time dengan dispatch optimization berbasis posisi, antrean, dan cycle time historis.

graph TD
    A[GPS Tracker di Setiap Unit] -->|MQTT 5-sec| B[Edge Server]
    B -->|Process| C[Fleet State Manager]
    C -->|Update| D[(Redis - Current State)]
    D -->|Feed| E[Dispatch Optimizer]
    F[Queue Monitor per Loading Point] -->|Feed| E
    G[Cycle Time History - InfluxDB] -->|Feed| E
    E --> H{Assignment Decision}
    H -->|Shortest Queue| I[Assign ke Excavator A]
    H -->|Nearest Unit| J[Assign ke Excavator B]
    H -->|Balanced Load| K[Assign ke Excavator C]
    I --> L[Push ke Driver Display / Radio]
    J --> L
    K --> L
    L --> M[Driver Follow Route]
    M --> N[Arrival Detected via Geofence]
    N --> O[Update Queue Counter]

    style E fill:#dbeafe,stroke:#3b82f6,color:#000
    style H fill:#fef3c7,stroke:#f59e0b,color:#000
services/fleet-service/dispatch_optimizer.go
// Multi-Factor Dispatch Optimizer
type DispatchDecision struct {
    TruckID       string  `json:"truck_id"`
    UnitCode      string  `json:"unit_code"`
    ExcavatorID   string  `json:"excavator_id"`
    LoadingPoint  string  `json:"loading_point"`
    EstimatedETA  float64 `json:"eta_minutes"`
    QueuePosition int     `json:"queue_position"`
    Score         float64 `json:"score"`
}

func (d *DispatchService) OptimizeAssignment(ctx context.Context, truckID string) (*DispatchDecision, error) {
    // 1. Get current truck state from Redis
    truck, err := d.cache.GetFleetState(ctx, truckID)
    if err != nil {
        return nil, fmt.Errorf("truck state not found: %w", err)
    }

    // 2. Get all active excavators and their queue lengths
    excavators, err := d.getActiveExcavators(ctx, truck.SiteID)
    if err != nil {
        return nil, err
    }

    // 3. Score each excavator: distance (40%) + queue (35%) + avg cycle (25%)
    var best *DispatchDecision
    var bestScore float64

    for _, exc := range excavators {
        distance := haversineKm(truck.Location, exc.Location)
        avgCycle := d.getCycleTimeAvg(ctx, truckID, exc.ID)

        distScore := 1.0 / (1.0 + distance)
        queueScore := 1.0 / (1.0 + float64(exc.QueueLength))
        cycleScore := 1.0 / (1.0 + avgCycle)

        score := (distScore * 0.40) + (queueScore * 0.35) + (cycleScore * 0.25)

        if score > bestScore {
            bestScore = score
            best = &DispatchDecision{
                TruckID:       truckID,
                UnitCode:      truck.UnitCode,
                ExcavatorID:   exc.ID,
                LoadingPoint:  exc.LoadingPoint,
                EstimatedETA:  distance / avgSpeedKmPerMin(truck.UnitType),
                QueuePosition: exc.QueueLength + 1,
                Score:         score,
            }
        }
    }

    // 4. Publish dispatch decision
    d.kafka.Publish("dispatch.decision", best)
    return best, nil
}

Cycle Time Tracking:

graph LR
    A["🟢 LOADING<br/>Excavator mengisi muatan"] --> B["🔵 HAULING (Loaded)<br/>Truk menuju dumping area"]
    B --> C["🟡 DUMPING<br/>Menurunkan muatan"]
    C --> D["🔵 HAULING (Empty)<br/>Kembali ke loading"]
    D --> E["🟠 QUEUING<br/>Menunggu giliran loading"]
    E --> A

    style A fill:#d1fae5,stroke:#10b981,color:#000
    style B fill:#dbeafe,stroke:#3b82f6,color:#000
    style C fill:#fef3c7,stroke:#f59e0b,color:#000
    style D fill:#dbeafe,stroke:#3b82f6,color:#000
    style E fill:#fed7aa,stroke:#f97316,color:#000

Setiap fase cycle time terdeteksi otomatis via geofence (masuk/keluar loading area, dumping area) dan ignition status (moving vs stationary). Data ini digunakan untuk menghitung:

  • Effective Working Time (EWT): Total waktu produktif vs idle
  • Truck Factor: Rasio jumlah truk optimal per excavator
  • Match Factor: Efisiensi pasangan truk-excavator

Results:

Metric Sebelum (Manual) Sesudah (FMS) Improvement
Avg cycle time 35 menit 26 menit ↓ 26%
Queue time at loading 10-15 menit 3-5 menit ↓ 65%
Truck utilization (PA × MA × UA) 65% 79% ↑ 22%
Dispatch decision time 2-3 menit (radio) < 5 detik (auto) ↓ 97%
Cycle time data accuracy ~60% (manual) 99%+ (auto) ↑ 65%

Feature #2: Fuel Management & Anomaly Detection

Problem: Bahan bakar adalah biaya operasional terbesar kedua setelah sewa alat (bisa mencapai 25-30% total opex). Pencatatan manual di SPBU site rawan ketidakakuratan, dan deteksi fuel theft atau abnormal consumption hampir mustahil dilakukan secara real-time.

Solution: End-to-end fuel tracking dari tangki penyimpanan, proses pengisian, hingga konsumsi per unit — dengan anomaly detection otomatis.

graph TD
    A[Fuel Storage Tank] -->|Level Sensor| B[Edge Server]
    C[Fuel Dispenser / SPBU Site] -->|Flow Meter| B
    D[Vehicle Fuel Sensor] -->|MQTT| B
    B --> E[Fuel Reconciliation Engine]
    E --> F{Anomaly Check}
    F -->|Normal| G[Log & Dashboard]
    F -->|Sudden Drop > Threshold| H[Alert: Possible Theft]
    F -->|Consumption > 130% Baseline| I[Alert: Inefficient Unit]
    F -->|Refuel vs Dispense Mismatch| J[Alert: Reconciliation Gap]
    H --> K[Notify Security & Supervisor]
    I --> L[Notify Maintenance Team]
    J --> M[Notify Fuel Coordinator]

    style F fill:#fef3c7,stroke:#f59e0b,color:#000
    style H fill:#fee2e2,stroke:#ef4444,color:#000
    style I fill:#fef3c7,stroke:#f59e0b,color:#000
    style J fill:#fef3c7,stroke:#f59e0b,color:#000
services/fuel-service/anomaly_detector.go
// Fuel Anomaly Detection Rules
type FuelAnomaly struct {
    UnitCode    string    `json:"unit_code"`
    Type        string    `json:"type"`
    Severity    string    `json:"severity"`
    Description string    `json:"description"`
    DetectedAt  time.Time `json:"detected_at"`
    FuelDelta   float64   `json:"fuel_delta_liters"`
    Expected    float64   `json:"expected_liters"`
}

func (d *AnomalyDetector) Evaluate(ctx context.Context, event FuelEvent) []FuelAnomaly {
    var anomalies []FuelAnomaly
    unit := d.getUnitProfile(ctx, event.UnitCode)

    switch event.Type {
    case "consumption":
        // Rule 1: Consumption rate vs baseline
        baseline := d.getBaselineConsumption(ctx, event.UnitCode, event.ActivityType)
        ratio := event.ConsumptionRate / baseline.AvgRate

        if ratio > 1.30 {
            anomalies = append(anomalies, FuelAnomaly{
                UnitCode:    event.UnitCode,
                Type:        "HIGH_CONSUMPTION",
                Severity:    "WARNING",
                Description: fmt.Sprintf("%s konsumsi %.1f L/jam vs baseline %.1f L/jam (%.0f%% di atas normal)",
                    event.UnitCode, event.ConsumptionRate, baseline.AvgRate, (ratio-1)*100),
                FuelDelta:   event.ConsumptionRate - baseline.AvgRate,
                Expected:    baseline.AvgRate,
            })
        }

    case "level_change":
        // Rule 2: Sudden fuel level drop (potential theft)
        if event.FuelDelta < -50 && !d.hasRecentRefuelRecord(ctx, event.UnitCode) {
            anomalies = append(anomalies, FuelAnomaly{
                UnitCode:    event.UnitCode,
                Type:        "SUDDEN_DROP",
                Severity:    "CRITICAL",
                Description: fmt.Sprintf("%s fuel level turun %.0f liter tanpa record refueling — investigasi diperlukan",
                    event.UnitCode, -event.FuelDelta),
                FuelDelta:   event.FuelDelta,
            })
        }

    case "refueling":
        // Rule 3: Refuel amount vs dispenser record mismatch
        dispenserRecord := d.getDispenserRecord(ctx, event.UnitCode, event.Timestamp)
        if dispenserRecord != nil {
            gap := math.Abs(event.FuelDelta - dispenserRecord.Volume)
            tolerance := dispenserRecord.Volume * 0.05 // 5% tolerance
            if gap > tolerance {
                anomalies = append(anomalies, FuelAnomaly{
                    UnitCode:    event.UnitCode,
                    Type:        "RECONCILIATION_GAP",
                    Severity:    "WARNING",
                    Description: fmt.Sprintf("%s selisih refuel: sensor %.0f L vs dispenser %.0f L (gap: %.0f L)",
                        event.UnitCode, event.FuelDelta, dispenserRecord.Volume, gap),
                    FuelDelta:   gap,
                    Expected:    dispenserRecord.Volume,
                })
            }
        }
    }

    return anomalies
}
Real Impact: Fuel Theft Detection

Dalam bulan pertama deployment, sistem mendeteksi 3 insiden sudden fuel drop di malam hari pada unit yang seharusnya parkir — total ~650 liter solar (~Rp 10 juta). Investigasi mengkonfirmasi fuel theft. Sebelum sistem ini, anomali semacam ini tidak pernah terdeteksi karena pencatatan manual hanya dilakukan per shift (setiap 12 jam).

Results:

Metric Sebelum (Manual) Sesudah (Digital) Improvement
Fuel tracking accuracy ~85% (manual log) 98%+ (sensor) ↑ 15%
Fuel anomaly detection time 1-7 hari (audit) < 5 menit (real-time) ↓ 99%+
Fuel cost savings Baseline ↓ 8-12% per tahun Significant
Reconciliation gap ~5-8% < 1% ↓ 87%

Feature #3: HSE Digital Management

Problem: HPU memiliki standar HSE yang sangat tinggi (dibuktikan dengan pencapaian 5.7+ juta jam kerja tanpa kecelakaan di salah satu site). Namun, proses pencatatan HSE masih berbasis form kertas — near miss reporting lambat, safety inspection sulit di-track, dan analytics untuk trend identification terbatas.

Solution: HSE management module terintegrasi dalam platform — dari incident reporting, safety inspection, hingga predictive safety analytics.

graph TD
    A["📱 Mobile App<br/>(Supervisor/Operator)"] --> B{HSE Module}
    B --> C["🚨 Incident Report<br/>Near Miss / Accident"]
    B --> D["📋 Safety Inspection<br/>Daily / Weekly Checklist"]
    B --> E["🎓 Safety Training<br/>Log & Certification"]
    B --> F["⚡ SWA / JSA<br/>Safe Work Analysis"]

    C --> G[HSE Dashboard - Site Level]
    D --> G
    E --> G
    F --> G

    G --> H[Trend Analytics Engine]
    H --> I{Pattern Detection}
    I -->|High near-miss zone| J["🟡 Warning: Hotspot Area"]
    I -->|Equipment type trend| K["🟡 Warning: Equipment Risk"]
    I -->|Time pattern trend| L["🟡 Warning: Shift Fatigue"]
    J --> M[Safety Bulletin Board]
    K --> M
    L --> M

    G --> N[HSE Summary - HQ Jakarta]

    style C fill:#fee2e2,stroke:#ef4444,color:#000
    style J fill:#fef3c7,stroke:#f59e0b,color:#000
    style K fill:#fef3c7,stroke:#f59e0b,color:#000
    style L fill:#fef3c7,stroke:#f59e0b,color:#000

HSE Reporting Flow:

Pelapor membuka mobile app

Supervisor atau operator membuka HSE module di aplikasi mobile. Form incident report dirancang offline-first — bisa diisi lengkap tanpa koneksi internet, termasuk foto dan koordinat GPS otomatis.

Isi form terstruktur

Form menggunakan guided flow berdasarkan tipe insiden (near miss, first aid, medical treatment, lost time injury). Setiap tipe memiliki field mandatory yang berbeda, mengurangi incomplete report dari ~25% menjadi < 3%.

Auto-classification & routing

Berdasarkan severity dan tipe insiden, sistem otomatis me-route report ke pihak yang tepat: HSE Officer, Site Manager, atau langsung ke HQ jika severity critical. Tidak perlu lagi forward email manual.

Investigation & root cause analysis

HSE team melakukan investigasi menggunakan template 5-Why Analysis atau Fishbone Diagram yang sudah tersedia di sistem. Temuan dan corrective action tercatat dan trackable.

Corrective action tracking

Setiap corrective action memiliki PIC, deadline, dan status tracking. Sistem mengirim reminder otomatis jika mendekati atau melewati deadline. Management bisa monitor completion rate secara real-time.

Analytics & trend prevention

Data historis dianalisis untuk mengidentifikasi pattern — area mana yang sering terjadi near miss, jam berapa insiden paling sering terjadi, tipe equipment apa yang paling berisiko. Ini mengubah HSE dari reaktif (investigasi setelah kejadian) menjadi proaktif (cegah sebelum terjadi).

Results:

Metric Sebelum (Paper-based) Sesudah (Digital) Improvement
Near miss reporting time 24-48 jam < 30 menit ↓ 96%
Incomplete HSE report ~25% < 3% ↓ 88%
Corrective action completion rate ~65% 92% ↑ 42%
Time to generate HSE report (monthly) 3-5 hari Real-time (auto) ↓ 100%
Safety trend identification Manual (retrospective) Proactive (pattern-based) Paradigm shift

Feature #4: Multi-Site Command Center Dashboard

Problem: Manajemen HPU di Jakarta Head Office tidak memiliki real-time visibility ke operasi di seluruh site. Laporan datang mingguan via email dalam format spreadsheet — sudah stale saat dibaca. Perbandingan performa antar-site sulit dilakukan secara apples-to-apples.

Solution: Centralized command center dashboard yang menampilkan KPI operasional seluruh site dalam satu layar, terupdate secara real-time.

Real-time fleet map menampilkan posisi semua unit di semua site pada satu peta. Filter by site, equipment type, atau status (active/idle/maintenance).

Widget Data Update Interval
Live Fleet Map Posisi semua unit (multi-site) 5 detik
Active Units Count Unit beroperasi vs total fleet 30 detik
Idle Alert Unit idle > 15 menit Real-time
Equipment Availability PA / MA / UA per site 5 menit
Dispatch Queue Antrean per loading point Real-time

Key Technical Implementation:

services/fleet-service/multi_site_aggregator.go
// Multi-Site KPI Aggregator — runs every 5 minutes
type SiteKPI struct {
    SiteID            string  `json:"site_id"`
    SiteName          string  `json:"site_name"`
    ActiveUnits       int     `json:"active_units"`
    TotalUnits        int     `json:"total_units"`
    AvgCycleTime      float64 `json:"avg_cycle_time_min"`
    ProductionTons    float64 `json:"production_tons_today"`
    TargetTons        float64 `json:"target_tons_today"`
    FuelConsumption   float64 `json:"fuel_liters_today"`
    SafeManHours      int64   `json:"safe_man_hours"`
    OpenIncidents     int     `json:"open_incidents"`
    TruckUtilization  float64 `json:"truck_utilization_pct"`
}

func (a *Aggregator) ComputeMultiSiteKPI(ctx context.Context) ([]SiteKPI, error) {
    sites := []string{"KTM", "KTG", "KTR"}
    var results []SiteKPI

    for _, siteID := range sites {
        // Parallel fetch from different data sources
        var wg sync.WaitGroup
        var fleet FleetSummary
        var production ProductionSummary
        var fuel FuelSummary
        var hse HSESummary

        wg.Add(4)
        go func() { defer wg.Done(); fleet = a.fleetService.GetSiteSummary(ctx, siteID) }()
        go func() { defer wg.Done(); production = a.productionService.GetDailySummary(ctx, siteID) }()
        go func() { defer wg.Done(); fuel = a.fuelService.GetDailySummary(ctx, siteID) }()
        go func() { defer wg.Done(); hse = a.hseService.GetSiteSummary(ctx, siteID) }()
        wg.Wait()

        results = append(results, SiteKPI{
            SiteID:           siteID,
            SiteName:         getSiteName(siteID),
            ActiveUnits:      fleet.ActiveCount,
            TotalUnits:       fleet.TotalCount,
            AvgCycleTime:     fleet.AvgCycleTime,
            ProductionTons:   production.ActualTons,
            TargetTons:       production.TargetTons,
            FuelConsumption:  fuel.TotalLiters,
            SafeManHours:     hse.SafeManHours,
            OpenIncidents:    hse.OpenIncidents,
            TruckUtilization: fleet.Utilization,
        })
    }

    // Cache aggregated KPI
    a.cache.Set(ctx, "kpi:multi_site", results, 5*time.Minute)

    // Push to connected dashboards via WebSocket
    a.wsHub.Broadcast("kpi.update", results)

    return results, nil
}
From Weekly Email to Real-Time Visibility

Sebelumnya, manajemen di Jakarta baru mendapat laporan operasional setiap Senin pagi (untuk minggu sebelumnya) dalam format Excel yang dikirim via email. Sekarang, mereka membuka dashboard dan melihat seluruh operasi multi-site secara real-time. Keputusan yang dulunya membutuhkan waktu berhari-hari (misal: realokasi alat antar-site) sekarang bisa diambil dalam hitungan jam.


Feature #5: Edge-to-Cloud Sync Pipeline

Problem: Konektivitas di setiap site berbeda drastis — Site Kaltim memiliki 4G yang cukup stabil, Site Kalteng via radio link, dan Site Kaltara (KMO Bulungan) hanya mengandalkan VSAT 512 kbps shared. Platform harus tetap berjalan normal di semua kondisi.

Solution: Adaptive sync pipeline dengan prioritization dan compression yang disesuaikan per bandwidth tier.

graph TD
    A[Edge Server] --> B{Bandwidth Detection}
    B -->|"4G / Fiber (> 5 Mbps)"| C[Full Sync Mode]
    B -->|"Radio Link (1-5 Mbps)"| D[Optimized Sync Mode]
    B -->|"VSAT (< 1 Mbps)"| E[Minimal Sync Mode]
    B -->|"No Connection"| F[Buffer Mode]

    C --> G["Sync semua data, 5-sec interval<br/>JSON + gzip"]
    D --> H["Sync essential data, 30-sec interval<br/>Protobuf + zstd"]
    E --> I["Sync critical only, 5-min interval<br/>Protobuf + zstd + delta"]
    F --> J["Buffer ke SQLite<br/>Sync saat tersedia"]

    G --> K[Central Cloud]
    H --> K
    I --> K
    J -.->|"Saat koneksi pulih"| K

    style C fill:#d1fae5,stroke:#10b981,color:#000
    style D fill:#fef3c7,stroke:#f59e0b,color:#000
    style E fill:#fed7aa,stroke:#f97316,color:#000
    style F fill:#fee2e2,stroke:#ef4444,color:#000
edge-server/sync_manager.go
// Adaptive Sync Manager — adjusts behavior based on bandwidth
type SyncMode string
const (
    SyncFull      SyncMode = "full"       // > 5 Mbps
    SyncOptimized SyncMode = "optimized"  // 1-5 Mbps
    SyncMinimal   SyncMode = "minimal"    // < 1 Mbps
    SyncBuffer    SyncMode = "buffer"     // No connection
)

func (s *SyncManager) detectMode(ctx context.Context) SyncMode {
    bandwidth := s.bandwidthProbe.Measure(ctx) // Periodic bandwidth test
    switch {
    case bandwidth == 0:
        return SyncBuffer
    case bandwidth < 1_000_000: // < 1 Mbps
        return SyncMinimal
    case bandwidth < 5_000_000: // < 5 Mbps
        return SyncOptimized
    default:
        return SyncFull
    }
}

func (s *SyncManager) SyncLoop(ctx context.Context) {
    for {
        mode := s.detectMode(ctx)
        switch mode {
        case SyncFull:
            s.syncAll(ctx, 5*time.Second, EncodingJSON, CompressionGzip)
        case SyncOptimized:
            s.syncEssential(ctx, 30*time.Second, EncodingProtobuf, CompressionZstd)
        case SyncMinimal:
            s.syncCriticalOnly(ctx, 5*time.Minute, EncodingProtobuf, CompressionZstd)
        case SyncBuffer:
            time.Sleep(10 * time.Second) // Check again in 10s
            continue
        }
    }
}

// Priority: alerts > fleet state > fuel > production > HSE (non-urgent)
func (s *SyncManager) syncCriticalOnly(ctx context.Context, interval time.Duration, enc Encoding, comp Compression) {
    ticker := time.NewTicker(interval)
    defer ticker.Stop()

    for range ticker.C {
        // Only sync: safety alerts + fleet current position + fuel anomalies
        alerts := s.buffer.GetUnsynced(ctx, PriorityCritical, 50)
        if len(alerts) > 0 {
            payload := encode(alerts, enc, comp)
            s.httpClient.Post(ctx, "/api/v1/sync/critical", payload)
            s.buffer.MarkSynced(ctx, alerts)
        }
    }
}

Bandwidth Usage per Sync Mode:

Sync Mode Interval Avg Payload/sync Monthly Est. Use Case
Full 5 sec 12 KB ~6 GB Site dengan fiber/4G
Optimized 30 sec 3 KB (Protobuf) ~260 MB Site dengan radio link
Minimal 5 min 800 bytes ~7 MB Site VSAT (Kaltara KMO)
Buffer — 0 (local only) 0 Koneksi putus total
VSAT Reality Check

Di Site KMO Bulungan, bandwidth VSAT 512 kbps di-share oleh seluruh camp — office, mess, dan operasional. Platform hanya mendapat alokasi ~100 kbps. Dengan mode Minimal Sync menggunakan Protocol Buffers + Zstd compression, kami berhasil mengirim data fleet tracking untuk 40+ unit hanya dengan ~7 MB per bulan. Tanpa optimasi ini, JSON mentah akan membutuhkan ~50 MB — mustahil di bandwidth tersebut.


🚢 6. Implementation & Rollout

Phase 1: Pilot Site — Kutai Kartanegara (Kaltim)

Site terbesar HPU dengan konektivitas terbaik dipilih sebagai pilot. Deploy edge server, pasang GPS tracker di 60 unit, dan launch Fleet Management + basic dashboard. Validasi data accuracy dan user acceptance selama 2 bulan.

Phase 2: Fuel Management Module

Setelah fleet tracking stabil, integrasikan fuel sensor dan flow meter di SPBU site. Deploy anomaly detection rules. Kalibrasi threshold per tipe equipment karena konsumsi HD785 (40-ton) berbeda dengan PC2000 (excavator).

Phase 3: HSE Digital Module

Launch HSE reporting via mobile app untuk supervisor. Migrasi data historis insiden dari Excel ke platform. Training seluruh tim HSE di site untuk menggunakan digital workflow.

Phase 4: Expand ke Site Kalteng (Barito Utara)

Deploy edge server dan GPS tracker. Adaptasi untuk koneksi radio link (optimized sync mode). Penyesuaian mine plan area dan geofence sesuai topografi site.

Phase 5: Expand ke Site Kaltara (KMO Bulungan)

Site paling menantang — VSAT only. Deploy dengan minimal sync mode. Validasi bahwa operasional tetap berjalan normal saat koneksi terputus. Edge server harus 100% reliable secara mandiri.

Phase 6: Central Command Center (Jakarta HQ)

Launch multi-site dashboard di kantor pusat. Training untuk management team. Setup automated daily/weekly report generation menggantikan spreadsheet manual.


🚀 7. Overall Business Impact

Key Numbers
  • Cycle time: turun 26% (35 min → 26 min) — ratusan trip tambahan per hari
  • Truck utilization: naik 22% (65% → 79%) — ROI langsung ke produktivitas
  • Fuel cost: turun 8-12% per tahun melalui anomaly detection dan optimasi idle time
  • HSE reporting time: turun 96% — dari 24-48 jam menjadi < 30 menit
  • Management visibility: dari laporan mingguan via email → real-time multi-site dashboard
  • Fuel theft detected: 3 insiden di bulan pertama (~650 liter, ~Rp 10 juta)
  • Safe man hours: tracking otomatis dan akurat untuk compliance reporting

ROI Summary per Module

# Module Before After Estimated Annual Value
1 Fleet Management 35 min cycle, 65% utilization 26 min, 79% +15-20% production volume
2 Fuel Management 5-8% reconciliation gap < 1% gap + theft detection Rp 2-4 miliar/tahun savings
3 HSE Digital Paper-based, reactive Digital, proactive Priceless (nyawa manusia) + compliance
4 Multi-Site Dashboard Weekly email reports Real-time command center Faster decision making → revenue impact
5 Edge-to-Cloud Sync N/A (no remote site support) Works on 100 kbps VSAT Enabler untuk operasi di remote site

🏢 8. Post-Launch: Tantangan & Evolusi

8.1 GPS Tracker Reliability di Lingkungan Tambang

Tantangan terbesar post-launch adalah hardware reliability:

Problem Penyebab Frekuensi Solusi
GPS drift Debu tebal menutupi antena ~5% unit/hari Auto-detect drift > 50m dalam 1 detik → filter out
Tracker offline Getaran melepas konektor ~3% unit/hari Industrial connector + vibration-dampened mounting
Fuel sensor noise Getaran di jalan tambang Konstan Moving average filter (window 30 detik)
Power spike Engine start/stop Setiap ignition Wide-voltage regulator (9-36V DC) + surge protector

8.2 User Adoption: Dari Radio ke Digital

Resistensi Dispatcher

Dispatcher yang sudah 10+ tahun menggunakan radio HT awalnya menolak transisi ke digital. Pendekatan yang berhasil: bukan mengganti radio, tapi menambah layer informasi. Radio tetap digunakan untuk komunikasi suara, tapi dispatch assignment didukung oleh data real-time di layar. Setelah 2-3 minggu, dispatcher sendiri yang enggan kembali ke cara lama karena informasi di dashboard jauh lebih kaya.

Supervisor Lapangan vs Mobile App

Supervisor lapangan terbiasa dengan clipboard dan form kertas. Beberapa memiliki keterbatasan dalam menggunakan smartphone. Solusi: form input yang sangat sederhana, tombol besar, minimal typing (banyak dropdown dan radio button), dan dukungan foto untuk menggantikan deskripsi tertulis panjang.

Management Expectation vs Data Reality

Saat dashboard pertama kali live, management terkejut melihat angka idle time yang tinggi dan cycle time yang lebih lambat dari yang selama ini dilaporkan manual. Ini bukan karena performa menurun — tapi karena data manual selama ini tidak akurat. Butuh beberapa session untuk menjelaskan bahwa data digital yang "terlihat buruk" justru merupakan realita yang selama ini tertutup oleh estimasi manual yang optimistis.

Shift Handover & Data Continuity

Tantangan unik: operator ganti shift setiap 12 jam, tapi GPS tracker tetap terpasang di unit. Sistem harus mengaitkan data telemetri dengan operator yang sedang bertugas, bukan hanya dengan unit. Solusi: NFC card tap saat shift start/end di kabin kendaraan untuk registrasi operator aktif.

8.3 Evolusi Konektivitas

Konektivitas terus membaik seiring investasi infrastruktur:

graph LR
    A["2024 Q1<br/>🔴 VSAT Only<br/>512 kbps"] --> B["2024 Q3<br/>🟡 VSAT + Radio Link<br/>2 Mbps"]
    B --> C["2025 Q1<br/>🟢 4G Tower<br/>10+ Mbps"]
    C --> D["2025 Q3<br/>🟢 Fiber Backhaul<br/>50+ Mbps"]

    style A fill:#fee2e2,stroke:#ef4444,color:#000
    style B fill:#fef3c7,stroke:#f59e0b,color:#000
    style C fill:#d1fae5,stroke:#10b981,color:#000
    style D fill:#d1fae5,stroke:#10b981,color:#000

Arsitektur adaptive sync yang kami bangun sejak awal terbukti future-proof — saat bandwidth meningkat, platform otomatis memanfaatkan kapasitas tambahan tanpa perubahan kode. Site yang dulunya hanya bisa minimal sync sekarang bisa full sync dengan latency minimal.


🎓 9. Lessons Learned

  • Hub-and-spoke architecture membuktikan bahwa edge independence adalah kunci sukses di operasi tambang terpencil. Tidak ada satu pun site yang berhenti beroperasi karena masalah koneksi ke cloud. - Adaptive sync yang menyesuaikan bandwidth otomatis menghemat biaya VSAT signifikan dan memungkinkan operasi di site ultra-remote. - Golang terbukti ideal untuk edge server: single binary deployment, low memory, high concurrency — edge server berjalan di industrial PC dengan RAM hanya 2GB. - Fuel anomaly detection memberikan ROI tercepat — theft detection di bulan pertama langsung menjustifikasi investasi. - Multi-tenant site isolation memastikan data sensitif kontrak klien tetap aman meski dalam satu platform.
  • HSE digitalization mendapat pujian dari management karena membuat achievement safe man hours lebih terukur dan auditable.

Technical Debt yang Masih Ada

# Debt Impact Priority
1 Predictive maintenance model belum terintegrasi Maintenance masih time-based, belum condition-based High
2 Mine planning integration masih one-way Plan di-push ke platform, tapi aktual belum auto-feedback ke planner High
3 Dashboard belum support dark mode untuk control room malam Operator night shift complain silau Medium
4 Alert fatigue — terlalu banyak low-priority alerts Supervisor mulai ignore non-critical alerts High
5 Data retention policy belum otomatis di InfluxDB Storage cost naik linear, perlu tiered storage Medium
6 Mobile app belum fully offline-capable HSE report di area jauh dari camp harus buffer manual Medium

🎉 Conclusion

Membangun platform digital untuk operasi tambang HPU adalah tentang memecahkan masalah di dua dunia yang bertabrakan — dunia digital yang menuntut konektivitas dan data real-time, versus dunia tambang yang beroperasi di pedalaman Kalimantan dengan debu, getaran, dan sinyal yang kadang ada, kadang tidak.

Keberhasilan platform ini bukan diukur dari secanggih apa teknologinya, tapi dari seberapa transparan teknologi itu bagi penggunanya. Dispatcher tetap fokus pada dispatching, bukan pada debugging. HSE officer tetap fokus pada keselamatan, bukan pada troubleshooting app.

The HPU Way in Digital

HPU memiliki core values: Integrity, Hard Work, Smart Work, Complete Work, and Sincerity. Platform digital ini adalah manifestasi Smart Work — bukan menggantikan kerja keras tim tambang, tapi memperkuat mereka dengan informasi yang tepat, di waktu yang tepat, agar keputusan yang diambil semakin presisi.

Pada akhirnya, setiap baris kode yang ditulis untuk platform ini memiliki satu tujuan: membantu setiap pekerja tambang HPU pulang dengan selamat dan produktif setiap hari.

Artikel terkait

Produk
Produk
Membangun Platform Exchange Crypto Enterprise: Business Logic, Fitur, dan Domain Knowledge

Membangun Platform Exchange Crypto Enterprise: Business Logic, Fitur, dan Domain Knowledge

Di balik layar platform operasional exchange crypto: bagaimana sistem menghandle 500+ aset digital, memproses jutaan transaksi dengan reconciliation engine, menjalankan payment gateway multi-versi, menyaring wallet blockchain lewat AML provider, dan mengelola siklus hidup aset digital dari proposal hingga listing — semua sambil menjaga safeguarding compliance dan audit trail yang immutable.
Faisal Affan
Faisal Affan
Diterbitkan