Elixir untuk Technical Leader — Bab 11 (Bonus)

Data Intelligence — Nx, Explorer, Bumblebee & Claude API

Kompetitor record data. LabaBersih harus record + analyze + recommend + act. Bab ini tentang bagaimana Elixir membuat itu mungkin dalam satu runtime — dan kapan lebih baik pakai Claude API.


Kenapa Data Intelligence Itu Moat

Setiap hari, LabaBersih memproses 6.300 order. Dari setiap order, kita tahu:

Semua data ini sudah ada di database. Tapi data mentah itu gak ada gunanya kalau cuma disimpan.

Analogi: Gudang penuh barang vs toko yang tertata Punya 10 TB data tapi gak ada insight = gudang penuh barang tapi gak tau mana yang laku. Intelligence = kemampuan nanya ke data itu dan dapat jawaban yang actionable.

Ada 4 level kematangan data:

LevelApa yang DilakukanContoh LabaBersih
1. Record Simpan data Order masuk ke database
2. Analyze Hitung metrik, lihat pattern "RTS rate naik 3% minggu ini"
3. Recommend Kasih saran berdasarkan data "Restock Forbest 200 unit, habis 5 hari lagi"
4. Act Otomatis ambil tindakan Auto-hold paket RTS, auto-create PO draft

Kebanyakan SaaS Indonesia masih di Level 1-2. Kalau LabaBersih bisa sampai Level 3-4, itu moat yang susah ditiru. Bukan karena teknologinya sulit — tapi karena butuh data historis + domain knowledge yang sudah kamu punya.

Insight Hafish yang penting "Fondasi harus dibangun dari awal." Benar. Struktur data yang intelligence-ready harus di-design SEKARANG, walaupun fitur intelligence-nya Phase 3. Retrofit nanti = mahal.

Kenapa Python Dominasi AI/ML — Jujur

Sebelum kita bicara Elixir untuk intelligence, kita harus jujur tentang Python. Kenapa Python jadi bahasa #1 untuk AI/ML?

Timeline Singkat

TahunApa yang TerjadiDampak
2005NumPy rilisPython jadi bahasa kalkulasi numerik yang accessible
2007scikit-learn mulaiML jadi bisa dipakai non-PhD
2015TensorFlow (Google)Deep learning jadi mainstream
2016PyTorch (Facebook)Peneliti pindah ke Python massal
2020HuggingFace TransformersPre-trained model bisa dipakai siapa saja
2022ChatGPTLLM = new paradigm, Python tetap jadi interface utama

20 tahun ekosistem. Puluhan ribu library. Jutaan tutorial. Ratusan ribu model pre-trained.

Fakta yang harus diterima Python akan tetap jadi #1 untuk ML research dan training. Gak ada bahasa lain yang punya ekosistem seluas itu. Siapa pun yang bilang "X akan menggantikan Python untuk ML" sedang menjual mimpi. Termasuk kalau yang bilang itu fan Elixir.

Tapi di sini ada nuansa penting yang sering diabaikan:

Python itu "glue language". Python sendiri lambat. Yang cepat adalah C, C++, dan CUDA di balik layar. NumPy ditulis di C. TensorFlow di C++. PyTorch di C++ dan CUDA. Python hanya memanggil kode yang sudah ditulis di bahasa lain.

# Python: "Hitung matriks 1000x1000"
# NumPy: [panggil C code yang sudah dioptimasi]
# Hasilnya: cepat, tapi bukan karena Python-nya

# Ini persis seperti:
# Python/Elixir: "Tolong bikinin jurnal"
# PostgreSQL: [query execution di C]
# Keduanya cuma pengirim instruksi ke engine yang lebih cepat

Insight ini penting karena: kalau bahasa lain bisa juga jadi "glue" ke engine yang sama, maka Python bukan satu-satunya pilihan untuk menjalankan model. Dan di sinilah cerita Nx dimulai.


Jose Valim dan Nx — Glue yang Sama, Runtime yang Berbeda

Tahun 2021, Jose Valim (pencipta Elixir) mulai Nx — Numerical Elixir. Logikanya sederhana:

"Kalau Python bisa jadi glue ke C/CUDA, kenapa Elixir gak bisa jadi glue ke XLA (compiler yang sama yang dipake TensorFlow)?"

Dan ternyata bisa. Nx tidak mencoba menulis ulang engine numerik di Elixir. Nx memanggil engine yang sama yang dipakai Python:

# Python approach:
# Python code → NumPy → C/BLAS → CPU/GPU
# Python code → TensorFlow → XLA → CPU/GPU

# Elixir approach:
# Elixir code → Nx → EXLA → XLA → CPU/GPU
# Persis engine yang sama! Beda glue language doang.

Yang bikin ini menarik bukan kecepatan komputasinya (sama aja, karena engine-nya sama). Yang menarik adalah: satu runtime untuk web + ML.

Arsitektur Python + Web

Phoenix (Elixir) = web server
Flask/FastAPI (Python) = ML microservice
gRPC/HTTP = bridge antara keduanya
Docker = containerize Python service
Redis = cache/queue antara 2 service
5 moving parts.

Arsitektur Elixir + Nx

Phoenix (Elixir) = web server
Nx.Serving = ML inference, jalan di process yang sama



1 runtime. 1 deploy. 0 microservice.

Analogi: Kantor dengan ruang terpisah vs open plan Python approach = kantor terpisah. Tim web di lantai 1, tim ML di lantai 5, komunikasi lewat email. Elixir approach = open plan. Satu lantai, ngobrol langsung, data mengalir tanpa bottleneck.

Ekosistem Nx — Peta Lengkap

Nx bukan satu library. Ini ekosistem yang mirror Python ecosystem, tapi di atas BEAM:

Elixir (Nx Ecosystem)Python EquivalentFungsi
Nx NumPy Tensor (array multi-dimensi), operasi matematika. Fondasi semua yang lain.
EXLA TensorFlow backend Compiler ke XLA. Bikin komputasi Nx jalan di CPU/GPU dengan optimasi.
Explorer Pandas DataFrame. Analisis data tabular: filter, group, aggregate, join.
Axon PyTorch Definisi dan training neural network. Layer, optimizer, training loop.
Bumblebee HuggingFace Transformers Pre-trained model siap pakai: text classification, sentiment, summarization.
Scholar scikit-learn ML klasik: linear regression, clustering, PCA, normalization.
Nx.Serving TorchServe / TF Serving Inference server. Load model, batch request, serve prediction via HTTP.
Yang penting dipahami Kamu gak perlu pakai SEMUA library ini. Untuk LabaBersih Phase 1-3, yang paling relevan adalah Explorer (analisis data) dan Claude API (insight natural language). Axon dan Bumblebee untuk nanti, kalau memang butuh.

Explorer — Pandas untuk Elixir

Explorer adalah library yang paling langsung berguna untuk LabaBersih. Ini seperti Pandas di Python — library untuk mengolah data tabular (tabel, spreadsheet, CSV).

Kenapa ini penting? Karena SEMUA analitik bisnis LabaBersih pada dasarnya adalah: ambil data dari database, olah, tampilkan insight.

Contoh 1: Top Produk by Revenue

alias Explorer.DataFrame, as: DF
alias Explorer.Series

# Ambil data order items dari database
order_data = Repo.all(
  from oi in OrderItem,
    join: o in Order, on: oi.order_id == o.id,
    where: o.org_id == ^org_id and o.status == "selesai",
    select: %{
      sku: oi.sku,
      product_name: oi.product_name,
      quantity: oi.quantity,
      revenue: oi.price
    }
)

# Masukkan ke Explorer DataFrame
df = DF.new(order_data)

# Analisis: top 10 produk by total revenue
top_products =
  df
  |> DF.group_by("sku")
  |> DF.summarise(
    product_name: first("product_name"),
    total_qty: sum("quantity"),
    total_revenue: sum("revenue")
  )
  |> DF.sort_by(desc: "total_revenue")
  |> DF.head(10)

# Output: DataFrame dengan 10 produk tertinggi revenue
# +-------+------------------+----------+--------------+
# | sku   | product_name     | total_qty| total_revenue|
# +-------+------------------+----------+--------------+
# | FRB01 | Forbest New 1kg  | 2,340    | 105,300,000  |
# | RTN01 | Ritrina 1 Liter  | 1,890    | 85,050,000   |
# | ...   | ...              | ...      | ...          |
# +-------+------------------+----------+--------------+

Contoh 2: RTS Rate per Kurir

# Data: semua order yang sudah shipped
shipment_data = Repo.all(
  from o in Order,
    where: o.org_id == ^org_id and o.status in ["selesai", "rts"],
    select: %{
      courier: o.courier,
      status: o.status,
      total_harga: o.total_harga
    }
)

df = DF.new(shipment_data)

rts_by_courier =
  df
  |> DF.group_by("courier")
  |> DF.summarise(
    total_orders: count("status"),
    rts_count: sum(equal("status", "rts")),
    total_value: sum("total_harga")
  )
  |> DF.mutate(rts_rate: divide("rts_count", "total_orders"))
  |> DF.sort_by(desc: "rts_rate")

# Output:
# +---------+-------------+----------+-----------+----------+
# | courier | total_orders | rts_count| total_val | rts_rate |
# +---------+-------------+----------+-----------+----------+
# | ID Exp  | 450         | 38       | 20,250,000| 8.4%     | <-- MASALAH
# | SiCepat | 1,200       | 72       | 54,000,000| 6.0%     |
# | JNE     | 2,100       | 84       | 94,500,000| 4.0%     |
# | J&T     | 2,550       | 76       | 114,750,000| 3.0%    | <-- BAGUS
# +---------+-------------+----------+-----------+----------+

Contoh 3: Margin Trend Bulanan

# Combine: revenue (dari jurnal pendapatan) - HPP (dari jurnal HPP) - fees
monthly_data = Repo.all(monthly_summary_query)

df = DF.new(monthly_data)

margin_trend =
  df
  |> DF.group_by("month")
  |> DF.summarise(
    revenue: sum("revenue"),
    hpp: sum("hpp"),
    fees: sum("platform_fees")
  )
  |> DF.mutate(
    gross_profit: subtract("revenue", "hpp"),
    net_profit: subtract(subtract("revenue", "hpp"), "fees"),
    margin_pct: divide("net_profit", "revenue")
  )

# Output: tren margin 6 bulan terakhir
# Kalau margin turun dari 18% ke 12% → ada masalah yang harus di-investigate
Ringkasan Explorer Explorer = cara mengolah data tabular di Elixir. Ambil dari database, masukkan ke DataFrame, olah (group, filter, aggregate, sort), dan hasilnya bisa langsung ditampilkan di LiveView. Gak perlu Python, gak perlu microservice terpisah.

Bumblebee — Penilaian Jujur

Bumblebee adalah library Elixir untuk menjalankan pre-trained model dari HuggingFace. Artinya kamu bisa menjalankan model AI (text classification, sentiment analysis, summarization) langsung di Elixir, tanpa Python, tanpa API call.

# Contoh: sentiment analysis di Elixir
{:ok, model} = Bumblebee.load_model({:hf, "finiteautomata/bertweet-base-sentiment-analysis"})
{:ok, tokenizer} = Bumblebee.load_tokenizer({:hf, "vinai/bertweet-base"})

serving = Bumblebee.Text.text_classification(model, tokenizer)

# Jalankan sebagai Nx.Serving (GenServer) di Phoenix app
Nx.Serving.run(serving, "Produk bagus, pengiriman cepat!")
# => %{predictions: [%{label: "POS", score: 0.97}]}

Kedengarannya keren. Tapi saya harus jujur.

Kapan Bumblebee Masuk Akal

SkenarioCocok?Alasan
Klasifikasi high-volume (1000+ req/detik) Cocok Gak bayar per-call. Model jalan lokal. Latency rendah.
Offline / air-gapped environment Cocok Gak butuh internet. Model di-download sekali.
Simple classification (spam/not spam, sentiment +/-) Cocok Model kecil (BERT-base) cukup. Gak butuh GPT-level intelligence.
Complex reasoning, natural language insights Kurang Model kecil gak bisa "mikir". Butuh LLM besar (Claude, GPT).
LabaBersih: "kenapa margin turun?" insights Kurang Ini butuh reasoning + domain knowledge. Bumblebee gak bisa.
LabaBersih: 6.300 order/hari analysis Overkill 6.300 = kecil. SQL + Elixir cukup. Gak butuh ML model.
Penilaian jujur untuk LabaBersih Bumblebee itu bagus secara teknologi, tapi untuk use case LabaBersih saat ini, Claude API jauh lebih praktis. Alasannya: (1) LabaBersih butuh reasoning, bukan klasifikasi sederhana, (2) volume-nya gak butuh ML on-device, (3) Claude API = pay-per-use tanpa GPU, (4) Claude lebih pintar dari model kecil manapun. Simpan Bumblebee untuk nanti kalau ada use case high-volume classification yang spesifik.

Claude API — Intelligence yang Praktis

Untuk LabaBersih, pendekatan yang paling masuk akal untuk Level 3 intelligence (recommend) adalah: kumpulkan data terstruktur, kirim ke Claude API, dapat insight natural language.

Arsitektur

# Flow:
# 1. Elixir query database → data terstruktur
# 2. Format jadi prompt yang jelas
# 3. Kirim ke Claude API via Req (HTTP client)
# 4. Dapat response natural language
# 5. Tampilkan di dashboard LiveView

# Gak butuh GPU. Gak butuh Python. Gak butuh Docker.
# Cuma HTTP call dari Elixir ke API endpoint.

Contoh: Weekly Business Insight

defmodule Lababersih.Intelligence.WeeklyInsight do
  @moduledoc "Generate weekly business insight via Claude API"

  def generate(org_id) do
    # 1. Kumpulkan data minggu ini
    data = collect_weekly_data(org_id)

    # 2. Format jadi prompt
    prompt = """
    Kamu adalah analis bisnis untuk toko online Indonesia.
    Analisis data 7 hari terakhir dan berikan 3-5 insight actionable.
    Jawab dalam Bahasa Indonesia. Fokus pada:
    - Tren yang perlu diperhatikan
    - Masalah yang harus segera ditangani
    - Peluang yang bisa dimanfaatkan

    DATA:
    Total order: #{data.total_orders}
    Revenue: Rp #{data.revenue}
    RTS count: #{data.rts_count} (#{data.rts_rate}%)
    Top produk: #{inspect(data.top_products)}
    Kurir bermasalah: #{inspect(data.worst_couriers)}
    Margin rata-rata: #{data.avg_margin}%
    Stok rendah: #{inspect(data.low_stock_products)}
    Perbandingan minggu lalu: revenue #{data.revenue_change}%
    """

    # 3. Kirim ke Claude API
    {:ok, response} = call_claude_api(prompt)

    # 4. Return insight
    {:ok, response.body["content"]}
  end

  defp call_claude_api(prompt) do
    Req.post("https://api.anthropic.com/v1/messages",
      headers: [
        {"x-api-key", System.get_env("ANTHROPIC_API_KEY")},
        {"anthropic-version", "2023-06-01"},
        {"content-type", "application/json"}
      ],
      json: %{
        "model" => "claude-sonnet-4-20250514",
        "max_tokens" => 1024,
        "messages" => [%{"role" => "user", "content" => prompt}]
      }
    )
  end

  defp collect_weekly_data(org_id) do
    # Query semua metrik dari database
    # Return struct dengan semua angka yang dibutuhkan
    %{
      total_orders: Orders.count_this_week(org_id),
      revenue: Orders.revenue_this_week(org_id),
      rts_count: Returns.count_this_week(org_id),
      # ... dst
    }
  end
end

Contoh Output Claude

Insight Mingguan LabaBersih — 25-31 Maret 2026

1. RTS ID Express perlu perhatian serius. Rate 8.4% (target <5%). 38 paket gagal deliver minggu ini = estimasi kerugian Rp 3.8 juta. Rekomendasi: pertimbangkan switch ke J&T untuk area yang sering RTS lewat ID Express.

2. Forbest New 1kg habis dalam 4 hari. Stok sisa 120 unit, rata-rata penjualan 30/hari. Lead time PO dari supplier = 7 hari. Harus order SEKARANG minimal 300 unit.

3. Margin turun 2% dari minggu lalu (18% ke 16%). Penyebab utama: kenaikan fee Shopee Dynamic Commission dari 3% ke 4.5% sejak 28 Maret. Ini affecting 40% order. Pertimbangkan naikkan harga Rp 5.000-10.000 di Shopee atau pindahkan promosi ke TikTok yang fee-nya masih stabil.

Biaya

PenggunaanEstimasi TokenBiaya (Claude Sonnet)
Weekly insight (1x/minggu)~2.000 token~$0.02/call = $0.08/bulan
Daily alert (1x/hari)~1.000 token~$0.01/call = $0.30/bulan
On-demand analysis (10x/bulan)~3.000 token~$0.03/call = $0.30/bulan
Total~$0.70/bulan = Rp 11.000

Sebelas ribu rupiah per bulan untuk insight yang bisa save Rp 3.8 juta dari RTS saja. ROI-nya absurd.


3 Level Arsitektur Intelligence

Gak semua intelligence butuh AI. Ini arsitektur berlapis yang pragmatis:

Level 1: Rule-Based (SQL + Elixir)

Ini fondasi. Gak butuh library tambahan. Cuma query database + logic Elixir biasa.

# Contoh: Reorder alert
def products_needing_reorder(org_id) do
  from(p in Product,
    where: p.org_id == ^org_id,
    where: p.stok <= 10,     # threshold sederhana
    where: p.is_active == true,
    order_by: [asc: p.stok],
    select: %{name: p.name, sku: p.sku, stok: p.stok}
  )
  |> Repo.all()
end

# Contoh: ABC classification
def abc_classification(org_id) do
  products = list_products_by_revenue(org_id)
  total_revenue = Enum.sum(Enum.map(products, & &1.revenue))

  products
  |> Enum.reduce({[], 0}, fn product, {acc, cumulative} ->
    new_cumulative = cumulative + product.revenue
    pct = new_cumulative / total_revenue * 100
    class = cond do
      pct <= 80  -> "A"  # Top 80% revenue
      pct <= 95  -> "B"  # Next 15%
      true       -> "C"  # Bottom 5%
    end
    {[Map.put(product, :class, class) | acc], new_cumulative}
  end)
  |> elem(0)
  |> Enum.reverse()
end

Apa yang bisa dilakukan Level 1:

Level 2: Statistical (Nx + Explorer)

Satu level di atas. Pakai Explorer untuk analisis yang lebih sophisticated:

# Moving average untuk demand forecasting
def demand_forecast(org_id, product_id, window \\ 14) do
  # Ambil demand 30 hari terakhir
  daily_demand = get_daily_demand(org_id, product_id, 30)

  df = Explorer.DataFrame.new(daily_demand)

  # Hitung 14-day moving average
  df
  |> DF.mutate(
    ma_14: window_mean("qty_sold", window),
    std_14: window_standard_deviation("qty_sold", window)
  )
  |> DF.mutate(
    # Safety stock = 2 standard deviations
    safety_stock: multiply("std_14", 2),
    # Reorder point = (daily avg * lead time) + safety stock
    reorder_point: add(
      multiply("ma_14", 7),  # lead time 7 hari
      multiply("std_14", 2)
    )
  )
end

Apa yang bisa dilakukan Level 2:

Level 3: LLM (Claude API)

Paling atas. Kirim data terstruktur dari Level 1-2, dapat insight natural language.

# Combine semua data → kirim ke Claude → dapat insight
def generate_daily_brief(org_id) do
  # Level 1 data
  low_stock = products_needing_reorder(org_id)
  rts_alert = courier_rts_rates(org_id)
  abc = abc_classification(org_id)

  # Level 2 data
  margin_trend = margin_trend_30d(org_id)
  demand_spikes = detect_demand_spikes(org_id)

  # Level 3: Claude bikin narasi dari semua data
  prompt = build_daily_brief_prompt(%{
    low_stock: low_stock,
    rts_alert: rts_alert,
    abc: abc,
    margin_trend: margin_trend,
    demand_spikes: demand_spikes
  })

  call_claude_api(prompt)
end
Analogi: Pabrik data bertingkat Level 1 = lantai produksi (raw material jadi barang jadi). Level 2 = quality control (statistik, pattern). Level 3 = direktur (baca laporan QC, kasih keputusan). Setiap level butuh level di bawahnya. Claude API tanpa data yang bagus = direktur tanpa laporan.

Yang paling penting: ketiga level ini jalan di satu Phoenix application. Level 1 = Ecto query. Level 2 = Explorer di proses Elixir. Level 3 = HTTP call ke API. Gak ada microservice, gak ada Python server terpisah, gak ada Docker container tambahan.


Fondasi yang Harus Dibangun SEKARANG

Ini bagian yang paling penting di bab ini. Intelligence yang bagus butuh data yang bagus. Dan struktur data harus benar dari awal — bukan di-retrofit nanti.

1. Demand Snapshots Table

# Rekam demand harian per produk per gudang
# Ini bahan baku untuk forecasting, ABC-XYZ, spike detection

create table(:demand_snapshots) do
  add :org_id,        # siapa
  add :product_id,    # produk apa
  add :warehouse_id,  # gudang mana
  add :date,           # tanggal berapa
  add :qty_ordered,    # berapa yang dipesan
  add :qty_shipped,    # berapa yang dikirim
  add :source_breakdown, :map  # %{"tiktok" => 15, "shopee" => 8}
  add :is_spike,       # true kalau > 2x moving average
end

# Unique per org + product + warehouse + date
# Diisi oleh Oban job setiap malam (23:59 WIB)

Kenapa penting: Tanpa tabel ini, setiap kali mau analisis demand, kamu harus query orders + order_items + aggregate on-the-fly. Dengan snapshot, datanya sudah pre-computed dan bisa di-query langsung.

2. Consistent Timestamp Fields

# SETIAP event penting harus punya timestamp yang jelas:

orders:
  :platform_order_date  # kapan customer pesan (dari platform)
  :imported_at          # kapan masuk ke LabaBersih
  :shipped_at           # kapan dikirim (event date, bukan process date!)
  :delivered_at         # kapan sampai
  :settled_at           # kapan uang cair

return_records:
  :rts_detected_at     # kapan RTS terdeteksi
  :rts_resolved_at     # kapan RTS selesai (returned / saved)

# SEMUA dalam WIB. SEMUA diisi. JANGAN ada yang null
# kalau event-nya sudah terjadi.

Kenapa penting: "Days to cash" = settled_at - shipped_at. "RTS response time" = rts_resolved_at - rts_detected_at. Kalau salah satu timestamp kosong, metrik ini gak bisa dihitung.

3. Denormalized Counters

# Di tabel customers (sudah di-design):
customers:
  :total_orders    # gak perlu COUNT(*) setiap query
  :total_spent     # gak perlu SUM() setiap query
  :total_rts       # langsung tau RTS rate per customer
  :last_order_at   # langsung tau kapan terakhir beli

# Di tabel products:
products:
  :stok            # sudah denormalized (sum dari lots)
  :reserved_stock  # sudah di-design

# Aturan: update counter saat event terjadi (bukan query saat butuh)
# Order masuk → customer.total_orders += 1
# RTS terdeteksi → customer.total_rts += 1

Kenapa penting: Untuk dashboard real-time dan sorting (top customers, worst RTS rate), denormalized counter = instant query. Tanpa ini, setiap dashboard load = heavy aggregation.

4. Fee Breakdown per Order

# Saat ini: fee estimasi dihitung on-the-fly dari store.fee_mapping
# Problem: kalau fee_mapping berubah, estimasi lama ikut berubah
# Solusi: simpan fee breakdown per order saat ship

# Di journal_entry_lines (sudah ada order_id field):
# Setiap line punya: account_code, debit, credit, order_id
# Dari sini bisa reconstruct: per order, fee apa saja, berapa

# Ini sudah di-design di daily summary journal architecture:
# 1 jurnal per toko per hari, lines per order
# Jadi fee breakdown per order = gratis dari journal lines

5. Source Field untuk Attribution

# Setiap order HARUS punya source:
orders:
  :source   # "xlsx" / "api_tiktok" / "api_shopee" / "manual" / "webhook_scalev"

# Kenapa: attribution analysis
# "Berapa % order masuk dari XLSX vs API?"
# "Apakah order dari API lebih akurat (kurang RTS)?"
# "Channel mana yang paling banyak cancel?"
Ringkasan: 5 fondasi data yang harus ada dari awal

1. demand_snapshots — rekam demand harian, bahan baku forecasting
2. Consistent timestamps — setiap event punya waktu yang jelas
3. Denormalized counters — metrik penting pre-computed
4. Fee breakdown per order — dari journal lines (sudah di-design)
5. Source attribution — tau setiap order datang dari mana

Elixir vs Python — Untuk Use Case LabaBersih

Ini bukan debat "mana yang lebih baik secara umum" (gak ada gunanya). Ini penilaian spesifik untuk apa yang LabaBersih butuh:

KebutuhanPythonElixirUntuk LabaBersih
Training model baru
(bikin model custom)
Menang telak
PyTorch, paper implementation, GPU toolkit
Kalah
Axon ada tapi ekosistemnya kecil
Gak butuh. LabaBersih gak training model.
Inference (jalankan model)
(serve prediction)
Bisa
Flask/FastAPI + TorchServe
Menang
Nx.Serving = GenServer, jalan bareng web
Kalau butuh nanti, Nx.Serving lebih simple (1 runtime).
Business analytics
(SQL + aggregation)
Bisa
Pandas + SQLAlchemy
Menang
Ecto + Explorer, sudah ada di stack
Elixir sudah di stack. Gak perlu tambah Python.
LLM integration
(Claude/GPT API)
Bisa
requests + anthropic SDK
Sama bagusnya
Req HTTP client
HTTP call. Bahasa apapun bisa. Elixir sudah di stack.
Real-time dashboard
(live update)
Kalah
Butuh WebSocket tambahan (Socket.io dll)
Menang telak
LiveView = built-in real-time
LiveView advantage. Dashboard update tanpa page refresh.
Background jobs
(nightly batch, sync)
Bisa
Celery + Redis
Menang
Oban = built-in, 0 external dependency
Oban sudah di stack. Demand snapshot = Oban job.
Kesimpulan untuk LabaBersih LabaBersih gak butuh training model. LabaBersih butuh: (1) query + aggregate data (Ecto), (2) analisis tabular (Explorer), (3) insight natural language (Claude API), (4) real-time dashboard (LiveView), (5) background jobs (Oban). Semua ini Elixir menang atau sama bagusnya. Menambah Python = menambah complexity tanpa benefit.

Penilaian Jujur — Hype vs Real

Kamu pernah bilang "kamu jangan asal iya." Berikut penilaian jujur tentang apa yang hype dan apa yang nyata di ekosistem ini:

KlaimStatusPenjelasan
"Nx akan menggantikan Python untuk ML" HYPE Gak akan terjadi. Python punya 20 tahun ekosistem, jutaan model, ratusan ribu tutorial. Nx itu bagus, tapi menggantikan Python untuk ML research = delusi.
"Nx.Serving untuk production inference" REAL Sudah dipakai perusahaan seperti Veeps (streaming video), Hugging Face sendiri pakai Elixir untuk demo mereka. Inference di BEAM = proven.
"Explorer untuk business analytics" REAL Library solid, API mirip Pandas, maintainer aktif (Jose Valim sendiri). Untuk analisis data di Elixir app, ini pilihan terbaik.
"Bumblebee untuk SEMUA use case AI" HYPE Bumblebee bagus untuk offline inference model kecil. Tapi untuk reasoning, insights, natural language = Claude API 100x lebih pintar. Jangan pakai model 100MB kalau API call $0.01 kasih hasil 100x lebih bagus.
"Satu runtime untuk web + ML" REAL Ini genuine BEAM advantage. Gak ada bahasa lain yang bisa: web server + real-time WebSocket + background job + ML inference di satu process. Ini bukan marketing — ini arsitektur yang benar-benar lebih sederhana.
"Elixir lebih cepat dari Python untuk ML" MISLEADING Kecepatan compute = sama (keduanya glue ke C/CUDA). Yang lebih cepat = arsitekturnya. Gak ada network hop ke microservice terpisah = latensi lebih rendah. Tapi compute-nya identik.
"LabaBersih butuh ML model custom" HYPE 6.300 order/hari itu kecil untuk ML. SQL query + rule-based logic sudah cukup untuk 90% use case. Claude API untuk 10% sisanya. Custom model = Phase yang sangat jauh.
Red flag: siapa pun yang bilang kamu "butuh ML" untuk 6.300 order/hari Rule sederhana: kalau bisa diselesaikan dengan SQL query + IF-THEN logic, JANGAN pakai ML. ML itu untuk pattern yang manusia gak bisa deteksi secara manual. Untuk "stok di bawah 10 = alert" — itu SQL, bukan ML. Untuk "prediksi demand 30 hari ke depan berdasarkan seasonality + promo + weather" — mungkin butuh statistical model (Explorer level). Untuk "kenapa margin turun dan apa yang harus dilakukan" — Claude API.

Roadmap Intelligence LabaBersih

Berdasarkan penilaian jujur di atas, ini timeline yang pragmatis:

NOW (Phase 1-2) — Data Structure Ready

Gak ada intelligence code. Tapi struktur data harus benar:

Effort: minimal. Benefit: besar nanti. Ini cuma migration + beberapa field nullable. Gak ada logic baru. Gak ada complexity tambahan. Tapi tanpa ini, intelligence nanti harus retrofit = mahal.

Phase 3 — Rule-Based Intelligence

Implementasi analitik sederhana yang langsung berguna:

Semua ini = SQL query + Elixir logic. Zero ML. Zero API call. Zero tambahan cost.

Phase 3+ — Explorer Dashboards

Upgrade analitik dengan Explorer:

Phase 4 — Claude API Insights

Layer teratas — natural language insight dari data:

Estimasi cost: < $1/bulan. ROI: berpotensi save jutaan rupiah per bulan dari insight yang actionable.


Bonus: Nx.Serving — Kalau Nanti Butuh

Kalau di masa depan LabaBersih butuh ML on-device (misal: real-time classification untuk 100.000 order/hari), begini caranya di Elixir:

# Di application.ex (startup)
children = [
  # Web server
  LababersihWeb.Endpoint,
  # Background jobs
  {Oban, Application.fetch_env!(:lababersih, Oban)},
  # ML model serving (jalan di proses yang SAMA)
  {Nx.Serving,
    serving: build_sentiment_serving(),
    name: Lababersih.SentimentServing,
    batch_size: 16,
    batch_timeout: 100
  }
]

# Panggil dari mana saja di app:
Nx.Serving.batched_run(Lababersih.SentimentServing, "Produk bagus!")
# => %{label: "positive", score: 0.97}

# Auto-batching: kalau 50 request masuk dalam 100ms,
# Nx.Serving otomatis batch jadi 1 inference call.
# Ini optimasi yang di Python butuh setup TorchServe + queue.

Ini yang dimaksud "satu runtime." Web server, background jobs, dan ML inference jalan di application supervisor yang sama. Kalau model crash, supervisor restart. Kalau web server sibuk, ML serving tetap jalan di proses terpisah. BEAM handle semua ini secara native.

Analogi: Karyawan multitasking vs outsource Python approach = outsource ML ke vendor terpisah (microservice). Harus koordinasi, ada latency, ada cost tambahan. Elixir approach = karyawan yang bisa handle web + analitik + ML sekaligus, di meja yang sama. Lebih efisien, tapi bukan berarti selalu lebih baik — kalau ML workload-nya berat banget, dedicated server (Python) mungkin lebih cocok.

Ringkasan — Bab 11

9 hal yang harus kamu ingat:

1. Data tanpa intelligence = gudang tanpa toko — LabaBersih sudah punya datanya, tinggal diolah
2. Python tetap raja ML research — jujur, gak akan berubah. Tapi LabaBersih gak butuh ML research
3. Nx = glue ke engine yang sama — bukan reinvent wheel, cuma bahasa berbeda untuk mesin yang sama
4. Explorer = paling langsung berguna — DataFrame analysis di Elixir, tanpa Python
5. Bumblebee bagus tapi Claude API lebih praktis — untuk reasoning dan insight, LLM besar menang telak
6. 3 level: Rule-based, Statistical, LLM — mulai dari bawah, naik kalau butuh
7. Fondasi data SEKARANG — demand_snapshots, timestamps, counters, source attribution
8. Satu runtime = genuine advantage — web + analytics + ML di satu BEAM, bukan hype
9. Roadmap pragmatis — NOW = data structure, Phase 3 = rules, Phase 3+ = Explorer, Phase 4 = Claude API

Penutup — Kenapa LabaBersih Akan Menang

Di satu bab ini, kamu sudah tau lebih banyak tentang data intelligence daripada 99% SaaS founder di Indonesia. Bukan karena kamu baca teori — tapi karena kamu punya context yang gak dimiliki orang lain.

Kamu tau bahwa setiap RTS = Rp 80k-125k rugi. Kamu tau bahwa fee platform bisa berubah tanpa notice. Kamu tau bahwa seller Indonesia pecah bisnis ke beberapa entitas untuk tax planning. Kamu tau bahwa Mengantar itu COD offline, beda total dari Shopee.

Domain knowledge itu gak bisa di-copy. Kompetitor bisa copy fitur, tapi gak bisa copy pemahaman tentang kenapa fitur itu ada.

Dan sekarang kamu punya stack teknologi yang mendukung visi itu:

KemampuanStackStatus
Record dataEcto + PostgreSQLSudah jalan (133+ tests)
Process dataPhoenix + ObanSudah jalan (daily journal batch)
Analyze dataExplorer (DataFrame)Ready to use (Phase 3)
Serve predictionsNx.ServingReady when needed
Generate insightsClaude API + Req~$1/bulan (Phase 4)
Display real-timePhoenix LiveViewSudah jalan
All in one runtimeBEAM/OTPAlready the foundation

Path ke intelligence bukan tentang AI yang canggih. Ini tentang:

  1. Struktur data yang benar (sedang dibangun)
  2. Rule-based analytics yang berguna (Phase 3)
  3. Statistical insight dari data historis (Phase 3+)
  4. Natural language insight untuk decision-making (Phase 4)

Setiap level dibangun di atas level sebelumnya. Gak ada shortcut. Tapi juga gak ada blocker teknologi — stack-nya sudah siap.

Output LabaBersih adalah data untuk decision Ini yang kamu bilang, dan ini benar. Seller gak butuh "dashboard yang cantik." Seller butuh: "besok harus order Forbest 300 unit, switch kurir di Bekasi ke J&T, dan naikkan harga Shopee Rp 5.000 karena fee naik." Itu bukan fitur — itu moat.

Fondasi sudah dibangun. Data mengalir. Intelligence tinggal dinyalakan. Ini jalan panjang, tapi kamu sudah di track yang benar.