Lewati ke konten utama

Analytics API — Dokumentasi

Versi: 1.0 • Terakhir diperbarui: 2025-11-04 04:17:39 (Asia/Jakarta)
Komponen: app/routes/analytics_model.py (Blueprint Flask)


Ringkasan

Analytics API ini merekam dan menganalisis trafik web melalui tiga tabel utama: page_views, sessions, dan visitors.
Blueprint berada pada url_prefix="/analytics". Semua waktu/timestamp yang dikembalikan adalah RAW sesuai zona waktu server/DB (tidak ada konversi timezone di layer aplikasi).

Fitur inti:

  • Koleksi event kunjungan (endpoint /collect) dengan rate gate 60 menit per client_id.
  • Ringkasan metrik (KPI, harian, per jam, top pages, browser share, active now).
  • Akses data mentah (visitors, sessions, page_views, joined 3 tabel).
  • Reset data (opsional, non-produksi).

Catatan: Tidak ada autentikasi/otorisasi di kode ini. Tambahkan lapisan auth (JWT/session) untuk produksi.


Skema Database

1) page_views

KolomTipeKeterangan
idBIGINT UNSIGNED PKAuto increment
client_idVARCHAR(64)ID klien (mis. fingerprint/cookie)
session_uuidCHAR(36)UUID sesi (format 8-4-4-4-12)
pathTEXTPath URL yang dikunjungi
titleTEXT NULLJudul halaman (opsional)
tsDATETIMEWaktu event (default CURRENT_TIMESTAMP())
ip_hashCHAR(64) NULLSHA-256 dari IP
ip_maskVARCHAR(45) NULLIP yang sudah dimask (IPv4: octet ke-4=0; IPv6: empat hextet pertama + ::)
user_agentTEXT NULLUser-Agent
browser_nameVARCHAR(80) NULLNama browser yang diringkas
device_typeVARCHAR(30) NULLJenis perangkat (mis. mobile/desktop)

Index: idx_pv_client (client_id), idx_pv_ts (ts), idx_pv_ipmask (ip_mask)


2) sessions

KolomTipeKeterangan
idBIGINT UNSIGNED PKAuto increment
client_idVARCHAR(64)Mengacu ke pengunjung
session_uuidCHAR(36) UNIQUEUUID sesi
started_atDATETIMEWaktu sesi dimulai
last_event_atDATETIMEWaktu event terakhir (diupdate on write)

Index: uk_session_uuid (session_uuid), idx_sessions_client (client_id)


3) visitors

KolomTipeKeterangan
idBIGINT UNSIGNED PKAuto increment
client_idVARCHAR(64) UNIQUEKey pengunjung
first_seenDATETIMEPertama kali terlihat
last_seenDATETIMETerakhir terlihat (diupdate on write)

Alur Data & Privasi

Koleksi Event (POST /collect)

  1. Ambil body JSON dan header:
    • client_id (≤ 64 char) wajib
    • path wajib
    • session_uuid (opsional; auto-generate jika kosong)
    • title, browser_name, device_type (opsional)
    • user_agent: diprioritaskan dari HTTP header User-Agent, fallback dari body
  2. Dapatkan IP client dari X-Forwarded-For (jika ada) atau remote_addr.
  3. Masking dan hashing IP:
    • IPv4 → octet ke-4 diganti 0 (mis. 192.168.10.5192.168.10.0)
    • IPv6 → simpan empat hextet awal lalu :: (mis. 2001:db8:85a3::8a2e:370:73342001:db8:85a3:0000::)
    • Hash → sha256(ip)
  4. Rate gate 60 menit per client_id: jika sudah ada page_views pada 60 menit terakhir, tidak insert baru, tapi tetap update visitors & sessions.
  5. Insert page_views jika lolos gate.

Privasi

  • IP tidak disimpan utuh: hanya hash dan mask.
  • Data waktu disimpan apa adanya sesuai zona waktu server/DB.

Base URL

Blueprint: url_prefix="/analytics"
Jika aplikasi utama dipasang di bawah /api, maka base URL: /api/analytics.

Contoh di bawah menggunakan prefix /api.


Endpoints: Ringkasan (Summary)

1) KPI Global

GET /api/analytics/summary/kpis?from=YYYY-MM-DD&to=YYYY-MM-DD

  • Query (opsional): from, to (YYYY-MM-DD atau YYYY-MM-DD HH:MM:SS)
  • Default: 30 hari terakhir (mulai 00:00:00 hingga sekarang, RAW)
  • Metode: menghitung total visits, unique visitors, visits today (sejak CURDATE()), dan active now (5 menit terakhir)
  • Response 200
{
"success": true,
"data": {
"range_from": "2025-10-06 00:00:00",
"range_to": "2025-11-04 10:30:21",
"visits": 1234,
"unique_visitors": 456,
"visits_today": 78,
"active_now": 5
}
}

2) Kunjungan Harian

GET /api/analytics/summary/visits_daily?from=YYYY-MM-DD&to=YYYY-MM-DD

  • Default: 30 hari terakhir
  • Response 200
{
"success": true,
"data": [
{"day": "2025-10-10", "visits": 20},
{"day": "2025-10-11", "visits": 35}
],
"range_from": "2025-10-06 00:00:00",
"range_to": "2025-11-04 10:30:21"
}

3) Kunjungan per Jam (24 jam)

GET /api/analytics/summary/visits_hourly?from=YYYY-MM-DD HH:MM:SS&to=YYYY-MM-DD HH:MM:SS

  • Default: 24 jam terakhir (RAW)
  • Bucket: DATE_FORMAT(ts, '%Y-%m-%d %H:00:00')
  • Response 200
{
"success": true,
"data": [
{"hour_bucket": "2025-11-03 11:00:00", "visits": 5},
{"hour_bucket": "2025-11-03 12:00:00", "visits": 8}
],
"range_from": "2025-11-03 10:30:21",
"range_to": "2025-11-04 10:30:21"
}

4) Top Pages

GET /api/analytics/summary/top_pages?from=YYYY-MM-DD&to=YYYY-MM-DD&limit=20

  • Default: 30 hari, limit=20
  • Response 200
{
"success": true,
"data": [
{"path": "/home", "visits": 120},
{"path": "/jobs", "visits": 90}
],
"range_from": "2025-10-06 00:00:00",
"range_to": "2025-11-04 10:30:21"
}

5) Browser Share

GET /api/analytics/summary/browsers?from=YYYY-MM-DD&to=YYYY-MM-DD

  • browser_name yang NULL di-normalisasi menjadi "Unknown"
  • Response 200
{
"success": true,
"data": [
{"browser": "Chrome", "visits": 300},
{"browser": "Safari", "visits": 120},
{"browser": "Unknown", "visits": 10}
],
"range_from": "2025-10-06 00:00:00",
"range_to": "2025-11-04 10:30:21"
}

6) Active Now

GET /api/analytics/summary/active_now

  • Definisi: jumlah client_id unik pada page_views selama 5 menit terakhir
  • Response 200
{ "success": true, "data": { "active_now": 7 } }

Endpoints: Data Mentah (Raw)

7) Visitors

GET /api/analytics/visitors?limit=100

  • Query: limit (opsional)
  • Sort: ORDER BY last_seen DESC
  • Response 200
{ "success": true, "data": [ { "id": 1, "client_id": "abc...", "first_seen": "...", "last_seen": "..." } ] }

8) Sessions

GET /api/analytics/sessions?limit=100

  • Query: limit (opsional)
  • Sort: ORDER BY last_event_at DESC
  • Response 200
{ "success": true, "data": [ { "id": 1, "client_id": "abc...", "session_uuid": "...", "started_at": "...", "last_event_at": "..." } ] }

9) Page Views

GET /api/analytics/page_views?limit=100

  • Query: limit (opsional)
  • Sort: ORDER BY ts DESC
  • Response 200
{ "success": true, "data": [ { "id": 1, "client_id": "abc...", "path": "/home", "ts": "...", "...": "..." } ] }

10) Joined (3 Tabel)

GET /api/analytics/joined?limit=100&since=YYYY-MM-DD HH:MM:SS

  • Query: limit (opsional), since (opsional) — filter pv.ts >= since
  • Join: page_views (pv) LEFT JOIN sessions (s) LEFT JOIN visitors (v)
  • Response 200
{
"success": true,
"data": [
{
"pv_id": 1,
"ts": "2025-11-04 09:00:00",
"path": "/home",
"title": "Home",
"client_id": "abc",
"session_uuid": "uuid-...",
"ip_hash": "sha256...",
"ip_mask": "192.168.1.0",
"user_agent": "Mozilla/...",
"browser_name": "Chrome",
"device_type": "desktop",
"session_started_at": "2025-11-04 08:55:00",
"session_last_event_at": "2025-11-04 09:05:00",
"visitor_first_seen": "2025-10-01 10:00:00",
"visitor_last_seen": "2025-11-04 09:05:00"
}
]
}

Endpoint: Koleksi Event

11) Collect (Upsert + Insert, Rate Gate 60 mnt)

POST /api/analytics/collect

Body (JSON)

  • client_id (string ≤64, wajib)
  • path (string, wajib)
  • session_uuid (string, opsional; auto-generate jika kosong)
  • title (string, opsional)
  • browser_name (string ≤80, opsional)
  • device_type (string ≤30, opsional)
  • user_agent (string, opsional; default dari header User-Agent)

Response 201 (insert baru)

{ "success": true, "page_view_id": 999, "message": "Collected" }

Response 204 (rate gate)

  • Jika sudah ada page_views untuk client_id yang sama dalam 60 menit terakhir.
  • Visitor & session tetap di-upsert, tapi tidak ada record page_view baru.

Response 400

{ "success": false, "message": "client_id & path wajib" }

Response 500

{ "success": false, "message": "penjelasan kesalahan" }

Endpoint: Reset (Non-Produksi)

12) Reset Semua Data

DELETE /api/analytics/reset

  • Efek: menghapus semua data dari page_views, sessions, dan visitors.
  • Hanya untuk development/testing.

Response 200

{ "success": true, "message": "Semua data dihapus" }

Contoh curl

Ganti {{HOST}} sesuai host Anda.

KPI 7 hari ke belakang

curl -s "https://{{HOST}}/api/analytics/summary/kpis?from=$(date -d '-6 days' +%F)&to=$(date +%F)"

Visits per jam default (24 jam terakhir)

curl -s "https://{{HOST}}/api/analytics/summary/visits_hourly"

Top pages 30 hari (limit 10)

curl -s "https://{{HOST}}/api/analytics/summary/top_pages?limit=10"

Collect event sederhana

curl -s -X POST "https://{{HOST}}/api/analytics/collect"   -H "Content-Type: application/json"   -d '{"client_id":"abc123","path":"/home","title":"Home"}' -i

Joined data sejak timestamp tertentu

curl -s "https://{{HOST}}/api/analytics/joined?since=2025-11-01%2000:00:00&limit=50"

Validasi & Edge Cases

  • Semua waktu di-parse apa adanya (RAW). Param from/to menerima YYYY-MM-DD (dianggap 00:00:00) atau YYYY-MM-DD HH:MM:SS.
  • Tidak ada pagination offset pada endpoints summary; raw endpoints mendukung limit sederhana.
  • Jika aplikasi berjalan di belakang proxy/load balancer, pastikan header X-Forwarded-For terpercaya untuk IP asli.
  • browser_name bisa NULL → dinormalisasi menjadi "Unknown" pada ringkasan browser.

Rekomendasi Produksi

  • Tambahkan auth (JWT) dan rate limiting (khususnya pada /collect dan /reset).
  • Gunakan connection pooling untuk MySQL (sekarang koneksi per request).
  • Tambahkan index tambahan: (client_id, ts) pada page_views bila query frekuen.
  • Sediakan retention policy (mis. hapus data mentah > 180 hari).
  • Audit & logging terstruktur (request-id, trace-id).

Perubahan vs Versi Sebelumnya

  • Initial release dokumentasi berdasarkan implementasi analytics_model.py tanpa modifikasi perilaku.

Struktur Respons (Konvensi)

  • Sukses: { "success": true, ... }
  • Gagal: { "success": false, "message": "..." }