Nexa Intelligence Docs
Data & Storage

PostgreSQL

Spesifikasi komprehensif skema database relasional OLTP PostgreSQL, definisi tabel master, relasi entitas, struktur artikel AI, data sektoral, serta strategi indeks performa di Nexa Intelligence Platform.

PostgreSQL Relational Database (OLTP)

PostgreSQL bertindak sebagai Single Source of Truth (SSOT) dan mesin transaksional (OLTP) utama untuk seluruh ekosistem Nexa Intelligence Platform. Database ini mengelola integritas data master taksonomi 5 level, metadata artikel berita dari ratusan portal media, pemanenan media sosial phone farm, repositori pengadaan barang/jasa pemerintah (LPSE/SIRUP), ekstraksi fakta terstruktur (SPOK), evaluasi kecerdasan buatan (AI reasoning), hierarki 38 provinsi, hingga observabilitas antrean broker Kafka.


Arsitektur & Klaster Tabel Database

Database PostgreSQL diorkestrasi menggunakan Drizzle ORM (TypeScript) pada sisi Backend API (f1-api-backend) serta diakses langsung oleh worker Python (nexa-aggregation, nexa-knowledge-graph, B3 Phone Farm) untuk operasi baca-tulis berkinerja tinggi.

PostgreSQL Schema (Nexa OLTP)
├── 1. Master Taksonomi & Entitas Wilayah
│   ├── taxonomy_nodes                # Pohon taksonomi 5-level (L1 - L5) & 5 pilar
│   ├── master_sectors                # Data induk 4 peran pemangku kepentingan
│   ├── master_regions                # Hierarki wilayah 38 provinsi, kab/kota, kecamatan
│   └── organization_nodes            # Entitas K/L, Pemda, TNI, POLRI beserta alias pencarian
│
├── 2. Konfigurasi Ingestion & Target Scraper
│   ├── sources                       # Direktori portal media, RSS, adaptor, cron, & rate limit
│   ├── scraping_targets              # Konfigurasi target scraping domain & link ke organisasi
│   ├── taxonomy_keywords             # Frasa kata kunci spesifik simpul taksonomi
│   ├── scraping_target_keywords      # Tabel relasi (junction) target scraping & kata kunci
│   ├── keywords                      # Master kata kunci pencarian umum
│   └── social_keywords               # Kata kunci pantauan percakapan media sosial
│
├── 3. Artikel Berita, Ekstraksi AI, & Kurasi Manusia
│   ├── articles                      # Master metadata artikel berita teranalisis AI
│   ├── article_spoks                 # Fakta terstruktur SPOK (Subjek, Predikat, Objek, Keterangan)
│   ├── article_currations            # Log status kurasi editorial manusia
│   ├── validation_decisions          # Rekam jejak koreksi label & keputusan validasi
│   └── gold_dataset_state            # Metrik akumulasi dataset acuan (gold dataset)
│
├── 4. Media Sosial & Phone Farm (Pipeline B3)
│   ├── social_trending_topics        # Master topik tren media sosial X/Twitter termutakhir
│   ├── social_trending_snapshots     # Time-series 15-menit peringkat & laju lonjakan tren
│   ├── postings                      # Arsip postingan multichannel (X, FB, IG, TikTok)
│   └── post_author                   # Profil pengunggah & metrik pengaruh akun medsos
│
├── 5. Pengadaan Barang & Jasa Pemerintah (LPSE / SIRUP)
│   ├── fact_procurement              # Master paket lelang & pengadaan per RUP ID
│   ├── fact_procurement_regions      # Relasi jangkauan wilayah multi-kabupaten paket pengadaan
│   └── fact_procurement_ai           # Hasil evaluasi inferensi AI (anomali & pemborosan)
│
├── 6. Data Sektoral Pangan, Pendidikan, & Static Datasets (B2)
│   ├── master_commodities            # Katalog komoditas pangan pokok nasional & nama alias
│   ├── fact_indicator                # Deret waktu harga pangan harian & indikator ketahanan
│   ├── master_schools                # Registri sekolah nasional Kemendikbudristek & koordinat GPS
│   ├── static_datasets               # Registri berkas bulk ingest (CSV/Excel via MinIO)
│   └── static_dataset_records        # Rekaman baris payload data statis terhashing
│
└── 7. Keamanan, Observabilitas, & Registry Sistem
    ├── users                         # Pengguna sistem & kontrol akses berbasis peran (RBAC)
    ├── audit_log                     # Log jejak audit aktivitas pengguna dan analis
    ├── module_registry               # Konfigurasi dinamis modul dashboard & navigasi UI
    └── kafka_topic_offset_samples    # Time-series sampling offset Kafka per menit

Diagram Relasi Entitas (ERD)

Diagram di bawah ini mengilustrasikan keterkaitan antar tabel utama dalam skema relasional PostgreSQL Nexa:

erDiagram
    master_sectors ||--o{ organization_nodes : "dikelompokkan ke"
    master_regions ||--o{ organization_nodes : "berlokasi di"
    master_regions ||--o{ fact_procurement : "lokasi utama"
    master_regions ||--o{ fact_procurement_regions : "wilayah cakupan"
    master_regions ||--o{ master_schools : "wilayah sekolah"
    master_regions ||--o{ fact_indicator : "wilayah data"

    taxonomy_nodes ||--o{ taxonomy_nodes : "induk hierarki (L1-L5)"
    taxonomy_nodes ||--o{ taxonomy_keywords : "memiliki kata kunci"
    taxonomy_nodes ||--o{ social_keywords : "memetakan"
    taxonomy_nodes ||--o{ articles : "klasifikasi taksonomi"

    sources ||--o{ articles : "menerbitkan artikel"
    organization_nodes ||--o{ scraping_targets : "memiliki target portal"
    scraping_targets ||--o{ scraping_target_keywords : "relasi kata kunci"
    taxonomy_keywords ||--o{ scraping_target_keywords : "diasosiasikan ke"

    articles ||--o{ article_spoks : "menghasilkan fakta"
    articles ||--o{ article_currations : "dikurasi pada"
    articles ||--o{ validation_decisions : "divalidasi oleh"

    fact_procurement ||--o{ fact_procurement_regions : "mencakup wilayah"
    fact_procurement ||--|| fact_procurement_ai : "dianalisa oleh AI"
    organization_nodes ||--o{ fact_procurement : "K/L/D pemilik paket"

    social_trending_topics ||--o{ social_trending_snapshots : "riwayat 15 menit"
    social_trending_topics ||--o{ postings : "dikaitkan ke tren"
    post_author ||--o{ postings : "membuat konten"

1. Modul Master Taksonomi & Entitas Wilayah

Modul ini adalah jangkar acuan nasional untuk standardisasi klasifikasi isu, organisasi negara, dan batas wilayah administratif Indonesia.

taxonomy_nodes (Pohon Taksonomi 5-Level)

Menyimpan struktur taksonomi pohon dengan kedalaman hingga 5 level yang mengorganisir puluhan ribu isu nasional ke dalam 5 pilar strategis:

  • Ekonomi: Stabilitas harga pangan, inflasi, industri, ketenagakerjaan, investasi.
  • Sosial: Kemiskinan, pendidikan, kesehatan, konflik sosial, bencana.
  • Politik: Pilkada serentak, dinamika parlemen, kebijakan publik, pemilu.
  • Budaya: Pariwisata, moderasi beragama, kearifan lokal, cagar budaya.
  • Geo Politik: Hubungan diplomatik, pertahanan perbatasan, kedaulatan laut, siber internasional.
KolomTipe DataKeterangan
idUUID (PK)Identifikator unik simpul (defaultRandom).
parent_idUUID (FK)Relasi rekursif ke simpul induk (bernilai NULL untuk simpul akar Pilar).
labelTEXTNama label isu (misal: Keamanan Siber, Korupsi APBD, Ketahanan Pangan).
pillarTEXTPilar utama (EKONOMI, SOSIAL, POLITIK, BUDAYA, GEO_POLITIK).
levelTEXTTingkat hierarki simpul (L1, L2, L3, L4, L5).
colorTEXTKode warna HEX acuan untuk visualisasi grafik & peta taksonomi.
descriptionTEXTDefinisi ruang lingkup isu yang digunakan sebagai acuan prompt LLM.
sort_orderINTEGERUrutan tampilan pada antarmuka admin/navigasi.
created_atTIMESTAMPTZWaktu simpul dibuat.
updated_atTIMESTAMPTZWaktu modifikasi terakhir.

master_sectors (Klasifikasi 4 Peran Pengguna)

Mendukung kapabilitas antarmuka Role-based Decision Intelligence ("Lihat sebagai"):

idsector_namepublic_idDeskripsi Peran Antarmuka
1governmentUUIDPemerintahan: Pemangku kebijakan, K/L, TNI, POLRI, dan Pemda.
2swastaUUIDPelaku Bisnis: Investor, korporasi swasta, BUMN, pasar modal.
3lsmUUIDLSM & Organisasi: Organisasi masyarakat, yayasan, advokasi sipil.
4sosmed / personalUUIDPersonal: Analis independen, akademisi, dan publik luas.

master_regions (Hierarki Wilayah 38 Provinsi)

  • Menyimpan kodifikasi wilayah administratif resmi di seluruh Indonesia:
    • PROVINSI: 38 provinsi di Indonesia (termasuk Papua Barat Daya, Papua Tengah, Papua Pegunungan, Papua Selatan).
    • KABUPATEN / KOTA: Seluruh 514 kabupaten dan kota nasional.
    • KECAMATAN: Wilayah kecamatan untuk pemetaan geospasial mikro.
  • Kolom: id (INT PK), parent_id (INT FK rekursif), region_name (TEXT), region_level (TEXT), public_id (UUID UNIQUE).

organization_nodes (Direktori Instansi & Normalisasi Alias)

  • Menyimpan pohon organisasi kepolisian (Mabes Polri, Polda, Polres, Polsek), kementerian, lembaga pemerintah non-kementerian (LPNK), dinas daerah, dan BUMN.
  • Kolom penting:
    • aliases TEXT[]: Menyimpan ragam variasi penulisan nama instansi dalam bahasa berita (misal: ['polda metro jaya', 'ditreskrimum polda metro', 'kepolisian daerah metro jaya']). Digunakan oleh worker saat ekstraksi entitas untuk pencocokan instan tanpa LLM.
    • is_procurement_master BOOLEAN: Flag penanda apakah instansi ini berwenang menjadi pemilik paket lelang pengadaan (KLPD).
    • sector_id & region_id: Relasi langsung ke data induk sektor dan wilayah.

2. Modul Konfigurasi Ingestion & Target Scraper

Mengatur armada perayap (crawler) berita dan pemantau sumber data siber.

Nama TabelPeran & Kolom UtamaFungsionalitas Operasional
sourcesid, name, type, mode, adapter, base_url, template JSONB, cron, rate_limit_per_min, status_scrappe, success_rate_7d, activeMaster portal penerbit berita online (Detik, Kompas, Antara, dll.), konfigurasi adaptor DOM scraper, jadwal perayapan otomatis, dan metrik kesehatan crawler 7 hari.
scraping_targetsid, organization_node_id, domain_name, base_url, scraping_config JSONB, is_activeMenghubungkan portal web resmi instansi dengan simpul organization_nodes untuk pemantauan rilis pers pemerintah daerah dan instansi penegak hukum.
taxonomy_keywordsid, taxonomy_node_id, keyword_phrase, is_activeFrasa kata kunci spesifik untuk menyaring artikel berita ke node taksonomi tertentu saat tahap preprocessing crawler.
scraping_target_keywordsscraping_target_id, taxonomy_keyword_id (PK Komposit)Tabel relasi many-to-many untuk mengikat target scraping instansi dengan daftar kata kunci fokus investigasi.
social_keywordsid, keyword, article_id, taxonomy, level, taxonomy_node_id, is_activeDaftar kata kunci pantauan media sosial (X/Twitter, TikTok) yang terikat pada hierarki taksonomi nasional.

3. Modul Artikel Berita, Ekstraksi AI, & Kurasi Manusia

articles (Master Metadata Artikel)

Tabel pusat penampung artikel berita yang telah dibersihkan oleh worker D1 dan diperkaya dengan metadata inferensi AI:

KolomTipe DataKeterangan & Karakteristik
idUUID (PK)ID artikel unik.
codeTEXT (Unique)Kode hash dokumen (SHA-256 dari URL/konten) untuk mencegah duplikasi ingest (deduplication).
titleTEXTJudul artikel berita yang telah dinormalisasi.
urlTEXTTautan absolut artikel berita asli.
data_typeTEXTTipe media (news_article, press_release, dll.).
channelTEXTKanal pemberitaan (Nasional, Hukum, Bisnis, Metro).
source_nameTEXTNama portal penerbit berita (misal: Kompas.com, DetikNews).
summaryTEXTRingkasan eksekutif 2–3 kalimat hasil ekstraksi AI.
pillarTEXTPilar strategis utama hasil klasifikasi tertinggi (EKONOMI, POLITIK, dll.).
primary_labelJSONBSimpul taksonomi primer: {"id": "...", "label": "Inflasi Pangan", "confidence": 0.94}.
labelsJSONBArray seluruh label taksonomi pendukung beserta skor probabilitas relevansi.
sentimentTEXTValensi sentimen pemberitaan (positive, neutral, negative).
confidenceREALSkor kepastian model inferensi AI (skala 0.00 – 1.00).
severityINTEGERDerajat keparahan dampak isu (skala 1 = Rendah s.d. 5 = Kritis/Darurat).
flaggedBOOLEANPenanda khusus jika artikel mengandung anomali atau ancaman keamanan mendesak.
entitiesJSONBDaftar entitas named-entity recognition: Tokoh, Organisasi, Lokasi, Objek Vital.
location_provinceTEXTNama provinsi hasil resolusi geospasial teks berita.
location_cityTEXTNama kabupaten/kota hasil resolusi entitas lokasi.
location_lat / lngDOUBLE PRECISIONKoordinat titik lintang dan bujur lokasi peristiwa berita.
human_validation_statusENUMStatus validasi kurasi manusia: 'pending', 'approved', 'rejected'.
published_atTIMESTAMPTZWaktu artikel diterbitkan oleh portal sumber asli.
scraped_atTIMESTAMPTZWaktu crawler memanen artikel mentah.
processed_atTIMESTAMPTZWaktu artikel selesai diproses AI dan diindeks ke sistem.

article_spoks (Fakta Terstruktur Subjek-Predikat-Objek-Keterangan)

Disimpan untuk memungkinkan analisis jaringan peristiwa (Event Knowledge Graph) dan dihitung oleh nexa-aggregation untuk metrik structured_facts:

CREATE TABLE article_spoks (
    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    article_id TEXT NOT NULL REFERENCES articles(id::text) ON DELETE CASCADE,
    subjek JSONB NOT NULL DEFAULT '[]',     -- Contoh: ["KPK", "Penyidik"]
    predikat JSONB NOT NULL DEFAULT '[]',   -- Contoh: ["Menyita", "Menggeledah"]
    objek JSONB NOT NULL DEFAULT '[]',      -- Contoh: ["Aset Rumah Mewah", "Uang Tunai"]
    keterangan TEXT,                        -- Contoh: "di kawasan Menteng, Jakarta Pusat"
    confidence REAL DEFAULT 0.85,
    extracted_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_article_spoks_article ON article_spoks (article_id);

article_currations & validation_decisions (Human-in-the-Loop)

  • article_currations: Mencatat aksi persetujuan (approved) atau penolakan (rejected) artikel oleh kurator beserta catatan koreksi editorial (validation_note).
  • validation_decisions: Menyimpan keputusan audit mendalam jika kurator mengubah klasifikasi AI (misal membetulkan corrected_label dari kategori Politik ke Ekonomi).
  • gold_dataset_state: Melacak jumlah korpus artikel terverifikasi manusia yang siap dialokasikan untuk siklus fine-tuning model AI selanjutnya.

4. Modul Media Sosial & Phone Farm (Pipeline B3)

Pipeline B3 Phone Farm memanen tren dan postingan sosial media secara kontinu menggunakan armada ponsel fisik Android, mengontrol scraping 4 platform (X, Facebook, Instagram, TikTok).

-- Master topik tren percakapan X/Twitter yang dinormalisasi setiap 15 menit
CREATE TABLE social_trending_topics (
    id SERIAL PRIMARY KEY,
    topic_name VARCHAR(255) NOT NULL UNIQUE,
    normalized_name VARCHAR(255) NOT NULL,
    first_detected_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    last_detected_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    peak_rank INTEGER DEFAULT 1,
    total_snapshots INTEGER DEFAULT 1,
    primary_pillar VARCHAR(50),      -- Dipetakan ke 5 Pilar Taksonomi
    taxonomy_node_id UUID REFERENCES taxonomy_nodes(id),
    status VARCHAR(20) DEFAULT 'ACTIVE' -- ACTIVE | ARCHIVED
);

CREATE INDEX idx_social_topics_norm ON social_trending_topics (normalized_name);
CREATE INDEX idx_social_topics_pillar ON social_trending_topics (primary_pillar);

5. Modul Pengadaan Barang & Jasa Pemerintah (LPSE / SIRUP)

Mendokumentasikan seluruh rencana dan realisasi pengadaan negara (Inaproc / LKPP) serta mendeteksi indikasi kecurangan lelang atau inefisiensi anggaran.

-- 1. Master Paket Pengadaan Nasional (SIRUP & Tender Inaproc)
CREATE TABLE fact_procurement (
    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    rup_id TEXT NOT NULL UNIQUE,                  -- Kode RUP dari portal LKPP
    package_name TEXT NOT NULL,                   -- Nama paket kegiatan pengadaan
    package_url TEXT,
    pagu NUMERIC(20, 2),                          -- Nilai pagu anggaran (Rupiah)
    procurement_type TEXT,                        -- Barang, Pekerjaan Konstruksi, Jasa Konsultansi
    procurement_scheme TEXT,                      -- Penyedia vs Swakelola
    method TEXT,                                  -- Tender, Pengadaan Langsung, E-Purchasing
    selection_period TEXT,
    domesticProduct BOOLEAN,                      -- Produk Dalam Negeri (PDN)
    small_business BOOLEAN,                       -- Alokasi UMKM/Koperasi
    klpd TEXT,                                    -- Nama Kementerian / Lembaga / Pemda
    work_unit TEXT,                               -- Satuan Kerja (Satker) pelaksana
    location TEXT,
    fiscal_year INTEGER,                          -- Tahun Anggaran (misal: 2026)
    source_org_node_id INTEGER REFERENCES organization_nodes(id),
    sector_id INTEGER REFERENCES master_sectors(id),
    region_id INTEGER REFERENCES master_regions(id),
    payload JSONB NOT NULL DEFAULT '{}',          -- Rincian spesifikasi lelang lengkap
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- 2. Wilayah Jangkauan Paket Multi-Kabupaten
CREATE TABLE fact_procurement_regions (
    procurement_id BIGINT NOT NULL REFERENCES fact_procurement(id) ON DELETE CASCADE,
    region_id INTEGER NOT NULL REFERENCES master_regions(id),
    source TEXT NOT NULL,                         -- manual | parsed_text
    created_at TIMESTAMPTZ DEFAULT NOW(),
    PRIMARY KEY (procurement_id, region_id)
);

-- 3. Evaluasi Anomali & Rekomendasi AI per Paket
CREATE TABLE fact_procurement_ai (
    procurement_id BIGINT PRIMARY KEY REFERENCES fact_procurement(id) ON DELETE CASCADE,
    classification TEXT NOT NULL,                 -- WAJAR | ANOMALI_TENDER | POTENSI_PEMBOROSAN
    reason TEXT,                                  -- Argumen penalaran logis dari model AI
    confidence NUMERIC(5, 4),                     -- Skor probabilitas (0.0000 s/d 1.0000)
    waste_amount NUMERIC(20, 2),                  -- Estimasi nilai pemborosan anggaran (Rp)
    model TEXT,                                   -- Nama model (misal: gpt-4o / claude-3-5-sonnet)
    prompt_version TEXT,
    evaluated_at TIMESTAMPTZ DEFAULT NOW(),
    payload JSONB NOT NULL DEFAULT '{}'
);

6. Modul Data Sektoral Pangan, Pendidikan, & Static Datasets

Menyimpan data statistik sektoral riil yang diunggah secara batch (oleh worker B2) sebagai kalibrasi silang terhadap isu pemberitaan.

Nama TabelStruktur KunciFungsi & Pola Akses
master_commoditiesid, commodity_name (UNIQUE), category, unit, aliases TEXT[]Katalog komoditas pangan nasional (Beras Medium, Cabai Rawit Merah, Minyak Goreng, Daging Sapi). Kolom aliases digunakan untuk resolusi teks saat artikel membahas pangan.
fact_indicatorid, indicator_type, region_id, product_id, period_date, value NUMERIC(18,4), unitDeret waktu numerik harga pangan harian/mingguan dari Badan Pangan Nasional/Kemendag. Memiliki indeks unik gabungan (grain index) untuk idempotensi UPSERT mingguan.
master_schoolsid, npsn (UNIQUE), school_name, school_level, accreditation, latitude, longitude, region_idRegistri sekolah Dapodik se-Indonesia lengkap dengan koordinat geospasial untuk deteksi insiden keamanan di sekitar fasilitas pendidikan.
static_datasetsid (UUID), file_sha256, file_path_minio, dataset_kind, status, rows_loadedRegistri berkas tabular besar yang diunggah ke Object Storage (MinIO) sebelum diekstraksi ke PostgreSQL via PostgreSQL COPY.
static_dataset_recordsid, dataset_id, row_hash, raw_payload JSONB, business_keyPenyimpanan baris data mentah dari file tabular yang diunggah untuk audit kelengkapan data.

7. Modul Keamanan, Observabilitas, & Registry

users & audit_log

  • users: Mengelola akun pengguna platform dengan kolom id (UUID), name, email (UNIQUE), password (Argon2/Bcrypt hash), role (admin, intel_analyst, executive_viewer), status (active, suspended), dan last_login_at.
  • audit_log: Mencatat setiap aktivitas manipulasi data oleh pengguna: actor_name, action (EXPORT_REPORT, UPDATE_TAXONOMY, VALIDATE_ARTICLE), target, dan created_at.

module_registry (Konfigurasi Dinamis Sidebar Dashboard)

Menyimpan konfigurasi modul frontend tanpa perlu deploy ulang kode aplikasi:

  • key (PK): ID rute modul (misal: national-overview, provinces, procurement).
  • name: Label menu antarmuka.
  • group_key: Kelompok navigasi (strategic, tactical, operational).
  • state: Status tayang (active, beta, pending).
  • tier: Hak akses level pengguna.

kafka_topic_offset_samples (Monitoring Throughput Antrean)

Mencatat posisi End Offset setiap topik Kafka setiap menit dengan primary key komposit (topic, bucket_start):

  • Menghitung Throughput (pesan/detik) secara presisi:
    -- Komputasi Throughput Antrean Kafka per Menit
    SELECT 
        t2.topic,
        t2.bucket_start,
        (t2.end_offset - t1.end_offset) / 60.0 AS throughput_msg_per_sec
    FROM kafka_topic_offset_samples t2
    JOIN kafka_topic_offset_samples t1 
      ON t2.topic = t1.topic 
     AND t1.bucket_start = t2.bucket_start - INTERVAL '1 minute'
    ORDER BY t2.bucket_start DESC;

Definisi Schema Drizzle ORM (TypeScript)

Berikut adalah cuplikan kode implementasi Drizzle ORM pada src/db/schema.ts di backend:

import {
  pgTable, uuid, text, integer, boolean, real,
  numeric, jsonb, timestamp, doublePrecision, pgEnum, primaryKey
} from "drizzle-orm/pg-core";

export const humanValidationStatusEnum = pgEnum("human_validation_status", [
  "pending", "approved", "rejected"
]);

export const articles = pgTable("articles", {
  id: uuid("id").primaryKey(),
  code: text("code").notNull().unique(),
  title: text("title").notNull(),
  dataType: text("data_type").notNull(),
  channel: text("channel"),
  sourceName: text("source_name"),
  url: text("url"),
  summary: text("summary"),
  pillar: text("pillar").notNull(),
  primaryLabel: jsonb("primary_label").notNull(),
  labels: jsonb("labels").notNull(),
  sentiment: text("sentiment"),
  confidence: real("confidence"),
  severity: integer("severity"),
  flagged: boolean("flagged").notNull().default(false),
  entities: jsonb("entities"),
  locationProvince: text("location_province"),
  locationCity: text("location_city"),
  locationLat: doublePrecision("location_lat"),
  locationLng: doublePrecision("location_lng"),
  humanValidationStatus: humanValidationStatusEnum("human_validation_status")
    .notNull()
    .default("pending"),
  publishedAt: timestamp("published_at", { withTimezone: true }),
  processedAt: timestamp("processed_at", { withTimezone: true }),
});

Strategi Pengindeksan & Optimasi Performa

Untuk menjamin waktu respons query OLTP tetap di bawah 50 milidetik pada volume jutaan transaksi, PostgreSQL menerapkan strategi indeks khusus:

  1. B-Tree Composite Indexes:

    • CREATE INDEX idx_articles_pub_prov ON articles (published_at DESC, location_province);
      Mempercepat pemfilteran linimasa berita terkini per provinsi.
    • CREATE INDEX idx_procurement_rup ON fact_procurement (rup_id);
      Menjamin pencarian instan paket LPSE saat sinkronisasi ulang.
    • CREATE INDEX idx_snapshots_topic_time ON social_trending_snapshots (topic_id, snapshot_at DESC);
      Optimasi pembacaan kurva pergerakan ranking tren 15 menit.
  2. GIN (Generalized Inverted Index) pada Kolom JSONB:

    • CREATE INDEX idx_articles_primary_label ON articles USING GIN (primary_label);
    • CREATE INDEX idx_articles_labels ON articles USING GIN (labels);
    • CREATE INDEX idx_articles_entities ON articles USING GIN (entities);
      Memungkinkan pencarian operator JSON path (@>, ?, ?|) secara efisien tanpa full-table scan.
  3. GIN Index pada Array Native (TEXT[]):

    • CREATE INDEX idx_org_aliases ON organization_nodes USING GIN (aliases);
    • CREATE INDEX idx_commodity_aliases ON master_commodities USING GIN (aliases);
      Mendukung query pencocokan nama variasi (aliases && ARRAY['alias_dicari']) dalam mikrodetik.
  4. Idempotensi Operasi Tulis (UPSERT Pattern):

    • Seluruh worker ingestion menggunakan klausa ON CONFLICT (code) DO UPDATE ... atau ON CONFLICT (rup_id) DO UPDATE ... untuk mencegah kegagalan pipeline saat memproses ulang pesan yang sama dari antrean Kafka.

On this page