# LabaBersih — AI Foundation Plan

> Dokumen ini adalah rencana fundamental untuk membangun data intelligence layer.
> Prinsip: "Fondasi harus dibangun dari awal" — data structure yang siap AI SEKARANG,
> bukan retrofit nanti setelah jutaan row tanpa field yang dibutuhkan.
> Approved by: Hafish, 3 April 2026

---

## 1. Visi: Kenapa AI = Moat LabaBersih

```
Competitor (Jubelio, Bukukas, A2X):
  Record data → tampilkan → selesai

LabaBersih:
  Record → Analyze → Recommend → Auto-Act
  
  4 level value:
  Level 1: RECORD — order, stok, jurnal, fee (semua competitor bisa)
  Level 2: ANALYZE — trend, anomaly, pattern (sedikit competitor)
  Level 3: RECOMMEND — "naikkan harga Rp 3.000" (GADA competitor)
  Level 4: AUTO-ACT — 1 klik execute rekomendasi (GADA competitor)
```

### Unique Advantage: Full Funnel Visibility

```
Layer 1: Ad Platform (TikTok/FB/Google)
  impressions → clicks → add_to_cart → purchase
  Source: ad_entries

Layer 2: Order System
  order → dikemas → dikirim → delivered/RTS
  Source: orders + fulfillment

Layer 3: Financial
  revenue → HPP (FEFO aktual) → platform fee → ad spend → NET PROFIT
  Source: journal + reconciliation + lots

GADA tool lain yang punya ketiga layer.
LabaBersih = satu-satunya yang bisa hitung TRUE PROFIT per ad, per product, per customer.
```

### Killer Metric: Profit ROAS

```
ROAS biasa (yang semua orang hitung):
  Revenue / Ad Spend = "5x" → kelihatan bagus

Profit ROAS (yang cuma LabaBersih bisa hitung):
  (Revenue - HPP_aktual - Platform_Fee - Ad_Spend) / Ad_Spend = "0.6x" → realita: RUGI

Kenapa cuma LabaBersih:
  ✅ HPP aktual dari FEFO lot consumption (bukan estimasi)
  ✅ Fee aktual dari per-fee reconciliation (bukan rata-rata)
  ✅ Ad spend per individual ad (bukan per campaign)
  ✅ Revenue per order linked ke attribution
```

### Data Flywheel

```
Seller join → data masuk → AI makin pintar → insight makin akurat
→ seller save/make money → lebih banyak seller join → LOOP

1.000 seller × 189.000 order/bulan = 189 JUTA data points/bulan
→ AI tau: "produk X di TikTok, bulan Ramadan, area Jawa, 
   margin optimal di harga Y, creative video > foto 2.5x"
→ Insight ini GADA di tempat lain. Competitor mulai dari NOL.
```

---

## 2. Tech Stack AI (Elixir-native, Tanpa Python)

```
BUKAN microservice Python terpisah.
SEMUA jalan di dalam Phoenix app yang sama.

Architecture:
  LabaBersih (Phoenix)
  ├── Web layer (LiveView)
  ├── Business logic (Contexts)
  ├── Background jobs (Oban)
  └── AI/ML layer:
      ├── Explorer (DataFrame, analytics)    ← kayak Pandas
      ├── Scholar (classical ML)             ← kayak scikit-learn
      ├── Nx.Serving (model inference)       ← kayak Flask ML API
      └── Claude API (natural language)      ← via Req HTTP client
```

| Library Elixir | Equivalent Python | Fungsi |
|---|---|---|
| Nx | NumPy | Tensor operations, numerical computing |
| EXLA | TensorFlow backend | Compile ke GPU/TPU via Google XLA |
| Explorer | Pandas | DataFrame: filter, group, aggregate |
| Scholar | scikit-learn | Regression, clustering, classification |
| Axon | PyTorch | Neural network (probably gak perlu) |
| Bumblebee | HuggingFace | Pre-trained models (text, image) |
| Nx.Serving | Flask/FastAPI ML | Serve model di dalam Phoenix app |
| Req + Claude API | - | Natural language insights |

### Kenapa gak pakai Python:

```
Python approach:
  Phoenix App → REST API → Python ML Service → Redis → balik
  = 2 service, 2 deploy, 2 monitoring, API latency

Elixir approach:
  Phoenix App → Nx.Serving (same process) → return
  = 1 service, 1 deploy, 1 monitoring, zero latency
  + BEAM concurrency: 100 ML predictions + 100 web requests simultaneously
```

---

## 3. Data Foundation — 11 Gap yang Harus Ditutup

> Semua ini HARUS ada SEBELUM v2 live.
> Cost: ~0 (nullable fields, empty tables).
> Benefit: setiap order yang masuk mulai collect data untuk AI.

### Gap 1: demand_snapshots (Daily Demand Aggregation)
**Blocks:** Demand forecast, seasonality, reorder AI, ABC-XYZ
```sql
CREATE TABLE demand_snapshots (
  id BINARY_ID PK,
  org_id FK, product_id FK, warehouse_id FK,
  snapshot_date DATE NOT NULL,
  qty_ordered INTEGER DEFAULT 0,
  qty_shipped INTEGER DEFAULT 0,
  qty_rts INTEGER DEFAULT 0,
  avg_price DECIMAL,
  total_revenue DECIMAL,
  timestamps
);
CREATE UNIQUE INDEX demand_snapshots_unique 
  ON demand_snapshots(org_id, product_id, warehouse_id, snapshot_date);
```
**Populate:** Oban worker daily @ midnight. Aggregate dari orders + order_items hari itu.

### Gap 2: Structured Address on Orders (sampai Kecamatan)
**Blocks:** Geographic RTS heatmap, area-based courier routing, regional demand, spend vs delivery correlation
```sql
ALTER TABLE orders ADD COLUMN delivery_province VARCHAR;
ALTER TABLE orders ADD COLUMN delivery_city VARCHAR;
ALTER TABLE orders ADD COLUMN delivery_district VARCHAR;   -- kecamatan
ALTER TABLE orders ADD COLUMN delivery_postal_code VARCHAR;

CREATE INDEX orders_delivery_province ON orders(org_id, delivery_province);
CREATE INDEX orders_delivery_city ON orders(org_id, delivery_city);
```
**Populate:** Parse dari XLSX/API saat import. Data sudah ada di platform (alamat pengiriman), tinggal extract + normalize.

### Gap 2b: Region Reference Table (Normalisasi)
**Blocks:** Konsistensi nama region (platform tulis beda-beda: "Kota Medan" vs "Medan" vs "MEDAN")
```sql
CREATE TABLE regions (
  id              BINARY_ID PK,
  province        VARCHAR NOT NULL,     -- "Sumatera Utara"
  city            VARCHAR NOT NULL,     -- "Kota Medan"
  district        VARCHAR,              -- "Medan Tembung"
  postal_code     VARCHAR,
  island          VARCHAR,              -- "Sumatera" (untuk grouping besar)
  timestamps
);
CREATE INDEX regions_province ON regions(province);
CREATE INDEX regions_city ON regions(city);
CREATE INDEX regions_district ON regions(district);
```
**Seed:** BPS data (Badan Pusat Statistik) — 34 provinsi, 514 kab/kota, 7.266 kecamatan. Data publik gratis.
**Fungsi:** Normalize alamat mentah dari platform ke format standar. Lookup saat import order.

### Gap 3: PO Lead Time
**Blocks:** Supplier scoring, reorder point calculation, supplier matching AI
```sql
ALTER TABLE purchase_orders ADD COLUMN expected_arrival_date DATE;
ALTER TABLE purchase_orders ADD COLUMN received_at TIMESTAMPTZ;
```
**Calculate:** `actual_lead_time = received_at - inserted_at` (di application layer)

### Gap 4: Product Price History
**Blocks:** Pricing AI, margin trend, price elasticity analysis
```sql
CREATE TABLE product_price_history (
  id BINARY_ID PK,
  org_id FK, product_id FK,
  old_harga_modal DECIMAL, new_harga_modal DECIMAL,
  old_harga_jual DECIMAL, new_harga_jual DECIMAL,
  changed_at TIMESTAMPTZ NOT NULL,
  changed_by FK users,
  reason VARCHAR,
  timestamps
);
```
**Populate:** Ecto hook di `update_product` — auto-insert saat harga berubah.

### Gap 5: Fee Change History
**Blocks:** Margin trend analysis, fee negotiation data
```sql
CREATE TABLE store_fee_history (
  id BINARY_ID PK,
  org_id FK, store_id FK,
  fee_mapping_before JSONB,
  fee_mapping_after JSONB,
  changed_at TIMESTAMPTZ NOT NULL,
  changed_by FK users,
  timestamps
);
```
**Populate:** Ecto hook di `update_store` — auto-insert saat fee_mapping berubah.

### Gap 6: RTS Geographic (sampai Kecamatan)
**Blocks:** RTS heatmap per area, courier quality per region, blacklist area
```sql
ALTER TABLE rts_tickets ADD COLUMN destination_province VARCHAR;
ALTER TABLE rts_tickets ADD COLUMN destination_city VARCHAR;
ALTER TABLE rts_tickets ADD COLUMN destination_district VARCHAR;  -- kecamatan

CREATE INDEX rts_tickets_province ON rts_tickets(org_id, destination_province);
CREATE INDEX rts_tickets_city ON rts_tickets(org_id, destination_city);
```
**Populate:** Copy dari order.delivery_province/city/district saat RTS detected.

### Gap 7: Calendar Events (Seasonality)
**Blocks:** Demand forecast accuracy, campaign planning
```sql
CREATE TABLE calendar_events (
  id BINARY_ID PK,
  org_id FK,
  name VARCHAR NOT NULL,
  start_date DATE NOT NULL,
  end_date DATE NOT NULL,
  event_type VARCHAR NOT NULL,  -- religious / platform_promo / national / custom
  expected_demand_multiplier DECIMAL DEFAULT 1.0,
  notes TEXT,
  timestamps
);
```
**Seed:** Ramadan, Harbolnas 10.10/11.11/12.12, Lebaran, Natal, dll.

### Gap 8: Ad Spend Tracking (per AD level)
**Blocks:** Marketing ROI, Profit ROAS, budget optimization AI
```sql
CREATE TABLE ad_entries (
  id              BINARY_ID PK,
  org_id          FK organizations,
  store_id        FK stores,
  platform        VARCHAR NOT NULL,
  -- 4-level hierarchy
  campaign_id     VARCHAR,
  campaign_name   VARCHAR,
  adgroup_id      VARCHAR,
  adgroup_name    VARCHAR,
  ad_id           VARCHAR,
  ad_name         VARCHAR,
  -- Creative data
  creative_type   VARCHAR,      -- video / image / carousel / search
  product_id_ext  VARCHAR,      -- SKU yang di-promote (dari platform)
  keyword         VARCHAR,      -- Google Ads keyword
  date            DATE NOT NULL,
  -- Spend
  spend           DECIMAL DEFAULT 0,
  -- Funnel metrics
  impressions     INTEGER DEFAULT 0,
  reach           INTEGER DEFAULT 0,
  frequency       DECIMAL,
  clicks          INTEGER DEFAULT 0,
  landing_page_views INTEGER DEFAULT 0,
  content_views   INTEGER DEFAULT 0,
  add_to_cart     INTEGER DEFAULT 0,
  initiate_checkout INTEGER DEFAULT 0,
  purchases       INTEGER DEFAULT 0,
  purchase_value  DECIMAL DEFAULT 0,
  leads           INTEGER DEFAULT 0,
  -- Calculated
  cpc             DECIMAL,
  cpm             DECIMAL,
  ctr             DECIMAL,
  cvr             DECIMAL,
  roas            DECIMAL,
  cpa             DECIMAL,
  cost_per_lead   DECIMAL,
  -- Targeting (dari ad platform — max level kota)
  targeting_provinces VARCHAR[],  -- ["Sumatera Utara", "Jawa Timur"]
  targeting_cities    VARCHAR[],  -- ["Medan", "Surabaya"]
  targeting_scope     VARCHAR,    -- "nasional" / "regional" / "kota"
  -- Raw (simpan semua, analisis nanti)
  raw_metrics     JSONB DEFAULT '{}',
  timestamps
);
CREATE UNIQUE INDEX ad_entries_unique
  ON ad_entries(org_id, platform, COALESCE(ad_id,''), COALESCE(keyword,''), date);
CREATE INDEX ad_entries_org_date ON ad_entries(org_id, date);
```
**Populate:** Oban sync workers (hourly) — sama kayak v1 cron pattern.

### Gap 9: Order Attribution
**Blocks:** CAC calculation, channel attribution, ad → profit tracking
```sql
CREATE TABLE order_attributions (
  id              BINARY_ID PK,
  org_id          FK organizations,
  order_id        VARCHAR FK orders,
  ad_entry_id     FK ad_entries,
  campaign_id     VARCHAR,
  platform        VARCHAR,
  attribution_type VARCHAR,     -- first_click / last_click / assisted
  click_at        TIMESTAMPTZ,
  order_at        TIMESTAMPTZ,
  time_to_convert INTEGER,      -- menit dari klik ke order
  timestamps
);
CREATE INDEX order_attributions_order ON order_attributions(order_id);
CREATE INDEX order_attributions_ad ON order_attributions(ad_entry_id);
```
**Populate:** Match by platform order data → ad campaign window.

### Gap 10: Daily Marketing Summary (Pre-aggregated)
**Blocks:** Fast marketing dashboard, trend analysis
```sql
CREATE TABLE daily_marketing_summary (
  id              BINARY_ID PK,
  org_id          FK organizations,
  date            DATE NOT NULL,
  platform        VARCHAR NOT NULL,
  store_id        FK stores,
  -- Spend
  total_spend     DECIMAL DEFAULT 0,
  -- Revenue
  total_revenue   DECIMAL DEFAULT 0,
  total_orders    INTEGER DEFAULT 0,
  -- True profitability
  total_hpp       DECIMAL DEFAULT 0,
  total_fees      DECIMAL DEFAULT 0,
  net_profit      DECIMAL DEFAULT 0,
  -- Metrics
  roas            DECIMAL,
  profit_roas     DECIMAL,          -- THE killer metric
  cac             DECIMAL,
  new_customers   INTEGER DEFAULT 0,
  returning_customers INTEGER DEFAULT 0,
  timestamps
);
CREATE UNIQUE INDEX daily_marketing_unique
  ON daily_marketing_summary(org_id, date, platform, COALESCE(store_id, '00000000-0000-0000-0000-000000000000'));
```
**Populate:** Oban worker daily, aggregate dari ad_entries + orders + journals.

### Gap 11: Daily Sales Summary (Pre-aggregated)
**Blocks:** Fast dashboard, demand analysis, ML feature engineering
```sql
CREATE TABLE daily_sales_summary (
  id              BINARY_ID PK,
  org_id          FK organizations,
  date            DATE NOT NULL,
  store_id        FK stores,
  product_id      FK products,
  -- Volume
  qty_ordered     INTEGER DEFAULT 0,
  qty_shipped     INTEGER DEFAULT 0,
  qty_rts         INTEGER DEFAULT 0,
  qty_cancelled   INTEGER DEFAULT 0,
  -- Financial
  gross_revenue   DECIMAL DEFAULT 0,
  total_hpp       DECIMAL DEFAULT 0,
  total_fees      DECIMAL DEFAULT 0,
  net_revenue     DECIMAL DEFAULT 0,
  -- Counts
  order_count     INTEGER DEFAULT 0,
  timestamps
);
CREATE UNIQUE INDEX daily_sales_unique
  ON daily_sales_summary(org_id, date, COALESCE(store_id, '00000000-0000-0000-0000-000000000000'), COALESCE(product_id, '00000000-0000-0000-0000-000000000000'));
```
**Populate:** Oban worker daily @ midnight.

---

## 4. AI Feature Roadmap

### Phase 1: Foundation (SEKARANG — sebelum v2 live)
- [ ] Migration: 11 tables/fields di atas
- [ ] Oban workers: demand_snapshots + daily_sales_summary (daily)
- [ ] Ecto hooks: price_history + fee_history (on update)
- [ ] Seed: calendar_events (Ramadan, Harbolnas, dll)
- [ ] Parse address dari XLSX/API ke structured fields

### Phase 2: Rule-Based Intelligence (setelah v2 stable, +1-2 bulan)
- [ ] ABC-XYZ classification (dari demand_snapshots)
- [ ] Reorder suggestions (demand + lead_time + safety stock)
- [ ] RTS rate alerts per courier/area/customer
- [ ] Margin alert per toko (kalau turun > 3%)
- [ ] Piutang aging alert (> 14 hari belum settled)

### Phase 3: Statistical Analysis (+ 3-4 bulan)
- [ ] Explorer DataFrame: trend analysis dashboards
- [ ] Demand forecasting (moving average + seasonality)
- [ ] Spike detection (vs 14-day baseline)
- [ ] Supplier performance scoring (lead_time + cost trend)
- [ ] Campaign impact analysis (demand during vs before/after)

### Phase 4: Marketing Intelligence (+ 4-5 bulan)
- [ ] Ad sync workers (TikTok Ads, Facebook, Google — port dari v1)
- [ ] Profit ROAS calculation (ad spend + HPP + fee)
- [ ] Per-ad performance dashboard (level ad, bukan campaign)
- [ ] Budget allocation recommendation (cross-platform)
- [ ] Creative type analysis (video vs foto vs carousel)
- [ ] CAC vs LTV per channel

### Phase 5: LLM Integration (+ 6 bulan)
- [ ] Claude API integration (Req HTTP client)
- [ ] Natural language insights on dashboard
- [ ] Anomaly explanation ("margin turun karena...")
- [ ] Action recommendations with 1-click execute
- [ ] Weekly digest email (auto-generated by Claude)

### Phase 6: Advanced (+ 12 bulan)
- [ ] Cross-seller benchmarks (anonymized multi-org)
- [ ] Market intelligence
- [ ] Nx.Serving for real-time scoring
- [ ] Custom ML models if needed (probably never — Claude API enough)

---

## 5. Readiness per Feature

| Feature | Timeline | Readiness (setelah foundation) |
|---|---|---|
| Auto-reorder | 6 bulan | 90% (demand_snapshots + lead_time) |
| Margin optimizer | 6 bulan | 95% (HPP + fee + price history) |
| RTS prevention | 6 bulan | 90% (RTS data + geographic + customer) |
| Marketing ROI / Profit ROAS | 6 bulan | 95% (ad_entries + HPP + fee) |
| Demand forecast | 1 tahun | 85% (demand_snapshots + calendar_events) |
| Pricing AI | 1 tahun | 70% (price_history + demand + margin) |
| Supplier matching | 1 tahun | 80% (PO lead_time + cost trend) |
| Budget allocation AI | 1 tahun | 85% (cross-platform ad data + profit) |
| Cross-seller benchmark | 2 tahun | 30% (needs multi-org infrastructure) |
| Market intelligence | 2 tahun | 20% (needs external data sources) |

---

## 6. Pertanyaan untuk Hafish (Review Decisions)

| Keputusan | Opsi | Dampak |
|---|---|---|
| Ad data retention | Berapa lama simpan? 1 tahun? 3 tahun? Unlimited? | Storage cost vs historical analysis depth |
| Cross-seller data sharing | Anonymized benchmarks antar seller? | Privacy concern vs network effect value |
| Claude API budget | Berapa maks/bulan untuk AI insights? | Rp 50K-500K/bulan tergantung volume |
| Attribution model | First-click vs last-click vs multi-touch? | Accuracy vs complexity |

---

## 7. Scope Boundary — LabaBersih vs Quant Marketing (KRITIS)

> LabaBersih = SaaS untuk SEMUA online seller (horizontal platform).
> Quant Marketing = intelligence untuk industri SPESIFIK (vertical, terpisah).
> JANGAN campur keduanya.

### Yang MASUK LabaBersih (generic, semua seller butuh):

| Data/Feature | Kenapa generic |
|---|---|
| Profit ROAS / True Margin | Semua seller punya ad spend + HPP + fee |
| Channel costs (gaji per channel) | Semua seller punya tim |
| Ad-level spend tracking | Semua seller ngiklan |
| Creative tags (video/foto/angle) | Semua seller bikin content |
| Calendar events (Ramadan, Harbolnas) | Semua seller kena |
| Demand snapshots | Semua seller punya order history |
| RTS geographic | Semua seller kirim paket |
| Price history, fee history | Semua seller punya |
| Budget allocation based on margin | Semua seller butuh |

### Yang TIDAK BOLEH masuk LabaBersih (industry-specific):

| Data/Feature | Kenapa gak boleh | Milik |
|---|---|---|
| Musim tanam per region | Cuma agri/pupuk | Quant Marketing |
| Cuaca → demand signal | Cuma agri/outdoor | Quant Marketing |
| Harga komoditas global (urea, DAP) | Cuma yang HPP-nya import | Quant Marketing |
| Kurs USD/IDR → HPP impact | Bisa generic tapi too niche | Quant Marketing |
| Regime detection | Regime-nya BEDA tiap industri | Quant Marketing |
| Derived demand modeling | Setiap industri beda driver | Quant Marketing |
| Planting calendar | Cuma agri | Quant Marketing |

### Data Flow

```
LabaBersih (horizontal SaaS):
  └── Data: orders, HPP, fees, ads, channel costs, creative tags
       ↓ (read-only access)
Quant Marketing (vertical, terpisah):
  ├── Reads from LabaBersih DB
  ├── + External data: PIHPS, BMKG, World Bank, BI JISDOR
  ├── + Industry logic: regime detection, derived demand
  └── Output: weekly brief, channel allocation, creative rotation

LabaBersih GAK TAU Quant Marketing exist.
```

### Prinsip

- LabaBersih gak boleh opinionated tentang industri user
- Seller kosmetik lihat fitur "musim tanam" = bingung, churn
- Kalau fitur cuma relevan untuk <20% user = JANGAN masuk LabaBersih
- External data ingestion = risk (API berubah/mati) → isolasi di produk terpisah

---

## 8. Gap 12-13: Channel Costs & Creative Tags

> Tambahan dari diskusi Quant Marketing. Ini GENERIC, masuk LabaBersih.

### Gap 12: Channel Operating Costs
**Blocks:** True Margin (ROAS Berbohong), channel profitability comparison
```sql
CREATE TABLE channel_costs (
  id              BINARY_ID PK,
  org_id          FK organizations,
  store_id        FK stores,
  period_month    INTEGER NOT NULL,
  period_year     INTEGER NOT NULL,
  -- Biaya tim
  gaji_cs         DECIMAL DEFAULT 0,
  gaji_advertiser DECIMAL DEFAULT 0,
  gaji_content    DECIMAL DEFAULT 0,
  headcount_cs    INTEGER DEFAULT 0,
  headcount_advertiser INTEGER DEFAULT 0,
  headcount_content INTEGER DEFAULT 0,
  -- Biaya operasional channel
  ongkir_subsidi  DECIMAL DEFAULT 0,
  platform_subscription DECIMAL DEFAULT 0,
  other_costs     DECIMAL DEFAULT 0,
  notes           TEXT,
  timestamps
);
CREATE UNIQUE INDEX channel_costs_unique
  ON channel_costs(org_id, store_id, period_year, period_month);
```
**Input:** CEO/finance input manual 1x/bulan. Simple form.
**Impact:** Profit ROAS yang LENGKAP — include biaya manusia, bukan cuma ad spend.

### Gap 13: Creative Metadata Tags
**Blocks:** Creative performance analysis, fatigue detection, content strategy
```sql
CREATE TABLE creative_tags (
  id              BINARY_ID PK,
  org_id          FK organizations,
  ad_entry_id     FK ad_entries,
  -- Tags
  angle           VARCHAR,     -- testimoni / unboxing / demo / promo / edukasi
  hook_type       VARCHAR,     -- problem / solution / social_proof / urgency
  target_audience VARCHAR,     -- umum / agen / reseller
  product_shown   VARCHAR,     -- SKU atau kategori
  format_detail   VARCHAR,     -- 15s / 30s / 60s / carousel_3 / static
  fatigue_days    INTEGER,     -- berapa hari sudah jalan (calculated)
  timestamps
);
CREATE INDEX creative_tags_ad ON creative_tags(ad_entry_id);
```
**Input:** Tim marketing tag per creative. Bisa juga auto-tag via Claude API (future).
**Impact:** "Video unboxing ROAS 3x > foto produk" → data-driven content strategy.

---

## 9. Anti-Pattern

1. ❌ JANGAN bikin AI feature sebelum data fondasi lengkap
2. ❌ JANGAN pakai Python/microservice kalau bisa Elixir-native
3. ❌ JANGAN bikin model ML custom kalau Claude API bisa handle
4. ❌ JANGAN bikin semua AI feature sekaligus — 1 feature, validate, iterate
5. ❌ JANGAN collect data tanpa purpose — setiap field punya alasan
6. ❌ JANGAN hitung ROAS tanpa HPP — itu bukan ROI, itu self-deception
7. ❌ JANGAN generalize marketing metrics lintas platform — setiap platform beda
8. ❌ JANGAN masukkan fitur industry-specific ke LabaBersih — LabaBersih = generic
9. ❌ JANGAN ingest external data di LabaBersih — external data = risk, isolasi di produk terpisah
10. ❌ JANGAN assume semua seller butuh regime detection — setiap industri beda driver
