Memahami Setiap Layanan Eksternal

EUDR Forest Analyzer tidak menghasilkan data satelit sendiri. Sistem ini bergantung pada beberapa layanan eksternal untuk mengambil citra, mendeteksi deforestasi, mengklasifikasikan tutupan lahan, dan menyimpan hasil geospasial. Tutorial ini memperkenalkan setiap layanan tersebut.

Langkah 1

Google Earth Engine

GEE adalah platform cloud dengan petabyte data satelit. Alih-alih mengunduh citra ke server Anda sendiri, Anda mengirim permintaan komputasi ke infrastruktur Google dan hanya menerima hasil yang dibutuhkan.

Aplikasi ini menggunakan empat dataset dari GEE:

UMD/hansen/global_forest_change_2023_v1_11 Hansen Global Forest Change — resolusi 30 m, cakupan global. Band lossyear menunjukkan tahun berapa pohon hilang (nilai 1–23 untuk 2001–2023).
projects/radar-wur/raddalert/v1 Peringatan RADD — Radar Sentinel-1, resolusi 10 m, wilayah tropis. Bekerja menembus awan karena radar tidak bergantung pada cahaya optik.
ESA/WorldCover/v200 ESA WorldCover — Klasifikasi tutupan lahan pada 10 m. Menunjukkan apakah suatu piksel berupa tutupan pohon, lahan pertanian, air, area terbangun, dan sebagainya.
COPERNICUS/S2_SR_HARMONIZED Sentinel-2 L2A — Citra optik untuk visualisasi warna asli dan analisis NDVI.

Autentikasi dilakukan melalui file kunci service account. Backend memanggil ee.Initialize(credentials) saat startup, dan setiap panggilan GEE berikutnya menggunakan kembali sesi tersebut.

Langkah 2

PostgreSQL + PostGIS

PostGIS mengubah database PostgreSQL biasa menjadi database spasial. Batas-batas plot disimpan sebagai kolom geometry, sehingga Anda dapat menjalankan kueri seperti “apakah poligon ini tumpang tindih dengan kawasan lindung?”

Aplikasi ini menggunakan connection pooling untuk menghindari biaya membuka koneksi baru setiap request:

Python
_connection_pool = pool.ThreadedConnectionPool(
    minconn=pool_size,
    maxconn=pool_size + max_overflow,
    host=os.getenv("DB_HOST", "localhost"),
    database=os.getenv("DB_NAME", "eudr_forest_analyzer"),
    cursor_factory=RealDictCursor
)
Bahasa Indonesia
Buat pool koneksi database yang sudah terbuka. Siapkan pool_size (default 5) koneksi setiap saat. Izinkan hingga pool_size + max_overflow (default 15) saat lalu lintas tinggi.
host / database — Dibaca dari variabel lingkungan, menggunakan localhost dan nama database default sebagai cadangan.
RealDictCursor — Mengembalikan baris kueri sebagai dictionary Python, bukan tuple, sehingga Anda dapat menulis row["plot_id"] alih-alih row[0].
Langkah 3

Abstraksi Provider

Codebase mendukung beberapa backend data satelit. Sebuah factory pattern di providers/factory.py menentukan mana yang digunakan berdasarkan satu variabel lingkungan:

Python — providers/factory.py
def get_provider() -> DataProvider:
    provider_type = os.getenv("DATA_PROVIDER", "gee")
    if provider_type == "gee":
        return GEEProvider()
    elif provider_type == "planetary":
        return PlanetaryComputerProvider()
    elif provider_type == "cdse":
        return CDSEProvider()
Bahasa Indonesia
Baca DATA_PROVIDER dari environment. Default-nya adalah "gee" (Google Earth Engine).
Kembalikan kelas provider yang sesuai. Setiap kelas mengimplementasikan antarmuka yang sama (DataProvider), sehingga sisa aplikasi tidak perlu tahu backend mana yang diajak berkomunikasi.
Tiga opsi saat ini: GEE (terimplementasi penuh), Copernicus CDSE (terimplementasi penuh, saat ini aktif di produksi), dan Microsoft Planetary Computer (parsial — citra satelit berfungsi, kehilangan hutan belum diimplementasi).

Semua layanan analisis memanggil get_provider() dan menggunakan objek yang dikembalikan. Mereka tidak pernah mengimpor GEEProvider secara langsung.

Langkah 3a

Provider GEE: Cara Kerjanya di Balik Layar

Provider GEE (providers/gee_provider.py, 392 baris) adalah lapisan delegasi — ia tidak memproses data satelit secara langsung, melainkan mendelegasikan ke layanan-layanan khusus yang sudah ada di codebase.

hansen_tile_service Peringatan Kehilangan Hutan — Mengkueri dataset Hansen GFC untuk mendeteksi kehilangan tutupan pohon berdasarkan band lossyear.
radd_alert_service Peringatan Radar / RADD — Mengambil peringatan deforestasi berbasis radar dari koleksi RADD Sentinel-1.
land_cover_service Tutupan Lahan — Mengambil klasifikasi tutupan lahan dari ESA WorldCover dan menghitung statistik per kelas.
sentinel_imagery_service Citra Satelit & NDVI — Mengambil citra Sentinel-2 untuk visualisasi warna asli dan analisis perubahan NDVI.

Autentikasi dilakukan melalui service account key file. Saat startup, provider memanggil ee.Initialize(credentials) menggunakan kredensial dari variabel lingkungan GEE_SERVICE_ACCOUNT_KEY_FILE.

💡
Arsitektur Tipis

Dengan hanya 392 baris, provider GEE sengaja dibuat tipis. Seluruh kompleksitas pemrosesan data satelit berada di layanan-layanan khusus (glad_alert_service, radd_alert_service, land_cover_service, sentinel_imagery_service). Provider hanya berfungsi sebagai jembatan antara antarmuka DataProvider dan layanan-layanan tersebut.

Langkah 3b

Provider CDSE: Sistem Produksi yang Aktif

Provider CDSE (providers/cdse_provider.py, 1.920 baris) adalah provider paling komprehensif dan merupakan yang digunakan saat ini di produksi (DATA_PROVIDER=cdse).

File ini berisi tiga kelas helper utama:

GFWDataAPI Wrapper Global Forest Watch Data API — Mengkueri data kehilangan hutan dan peringatan deforestasi melalui data-api.globalforestwatch.org.
ESAWorldCoverSTAC Pemrosesan Tutupan Lahan — Mengambil data ESA WorldCover dengan mekanisme fallback: pertama mencoba WMS (services.terrascope.be/wms), lalu STAC (services.terrascope.be/stac) jika WMS gagal.
CDSEProvider Kelas Utama — Menangani autentikasi OAuth2 melalui identity.dataspace.copernicus.eu dan mengambil citra satelit melalui SentinelHub Process API (sh.dataspace.copernicus.eu).

Provider ini berkomunikasi dengan lima endpoint API eksternal:

data-api.globalforestwatch.org Data kehilangan hutan dan peringatan deforestasi
identity.dataspace.copernicus.eu Autentikasi OAuth2 untuk mendapatkan access token
sh.dataspace.copernicus.eu SentinelHub Process API untuk citra satelit dan NDVI
services.terrascope.be/wms WMS untuk tutupan lahan ESA WorldCover (primer)
services.terrascope.be/stac STAC untuk tutupan lahan ESA WorldCover (fallback)
Ketahanan: Fallback Data Simulasi

Saat GFW API tidak tersedia (timeout, error, atau tidak ada koneksi), provider CDSE tidak gagal total. Sebagai gantinya, ia menghasilkan data simulasi deterministik menggunakan hash MD5 dari geometri sebagai seed. Ini berarti geometri yang sama selalu menghasilkan data simulasi yang sama — konsisten untuk pengujian dan demonstrasi.

Langkah 4

Layanan Email SMTP

Sistem mengirim email pada momen-momen penting: aktivasi akun, notifikasi analisis selesai, ringkasan batch dengan lampiran PDF, dan peringatan kegagalan. Layanan email menggunakan SMTP (biasanya Gmail) dengan template HTML yang disesuaikan dengan branding aplikasi.

Metode utama meliputi send_activation_email(), send_analysis_complete_email(), send_batch_complete_email(), dan send_analysis_failed_email(). Pengguna tier Enterprise menerima lampiran PDF yang ditingkatkan dengan citra satelit dan analisis NDVI, sementara pengguna tier gratis mendapat laporan ringkasan yang lebih sederhana.

Bekerja dengan Layanan Eksternal

Cara mengganti provider data satelit

  1. Buka file .env Anda (atau buat dari .env.example).
  2. Ubah variabel DATA_PROVIDER. Pilihan: gee, planetary, atau cdse.
    DATA_PROVIDER=planetary
  3. Jika beralih ke Planetary Computer, tambahkan PLANETARY_COMPUTER_API_KEY dan instal paket tambahan:
    pip install planetary-computer pystac-client stackstac rioxarray
  4. Restart server backend. Semua kode analisis menggunakan antarmuka DataProvider yang sama, jadi tidak ada hal lain yang perlu diubah.

Cara menambahkan provider data baru

  1. Buat file baru di backend/providers/, misalnya my_provider.py.
  2. Definisikan kelas yang meng-extend DataProvider (dari providers/base.py).
  3. Implementasikan metode yang diperlukan: initialize(), get_forest_loss_alerts(), get_radar_alerts(), get_land_cover(), get_satellite_imagery(), dan get_ndvi_analysis().
  4. Setiap metode harus mengembalikan dataclass yang benar dari providers/base.py (AlertResult, LandCoverResult, ImageryResult, atau NDVIResult).
  5. Daftarkan di providers/factory.py dengan menambahkan cabang elif di get_provider().
  6. Atur DATA_PROVIDER=my_provider di .env dan restart.

Cara mengonfigurasi autentikasi GEE

  1. Buat service account di Google Cloud Console dengan akses Earth Engine.
  2. Unduh file kunci JSON untuk service account tersebut.
  3. Atur berikut ini di file .env Anda:
    GEE_SERVICE_ACCOUNT=true GEE_PROJECT_ID=your-project-id GEE_SERVICE_ACCOUNT_EMAIL=sa@your-project.iam.gserviceaccount.com GEE_SERVICE_ACCOUNT_KEY_FILE=/path/to/keyfile.json
  4. Restart backend. Provider GEE memanggil ee.Initialize(credentials) saat startup menggunakan nilai-nilai ini.

Cara mengubah pengaturan koneksi database

  1. Buka file .env Anda.
  2. Atur kombinasi variabel berikut:
    DB_HOST=localhost DB_PORT=5432 DB_NAME=eudr_forest_analyzer DB_USER=postgres DB_PASSWORD=secret DB_POOL_SIZE=5 DB_MAX_OVERFLOW=10
  3. Restart backend. Connection pool akan dibuat ulang dengan pengaturan baru.
  4. Untuk memverifikasi koneksi, periksa log startup untuk pesan “Database connection pool created” (tanpa error).

Mengapa Pilihan Desain Ini?

Pola Provider

Adaptor Listrik Universal

Bayangkan abstraksi provider seperti adaptor listrik universal. Saat Anda bepergian ke negara lain, Anda mencolokkan adaptor yang berbeda, tetapi laptop Anda bekerja dengan cara yang sama. Factory pattern di factory.py memilih adaptor; sisa aplikasi tinggal mencolokkan.

GEE, Microsoft Planetary Computer, dan Copernicus Data Space semuanya menawarkan data satelit serupa — citra Sentinel-2, peta tutupan lahan, indikator kehilangan hutan — tetapi dengan API dan skema autentikasi yang sama sekali berbeda. Abstraksi provider menormalisasi semuanya ke dalam sekumpulan dataclass bersama: AlertResult, LandCoverResult, ImageryResult, dan NDVIResult.

Artinya, provider baru dapat ditambahkan (misalnya, vendor satelit komersial) tanpa menyentuh logika bisnis apa pun. Anda hanya perlu menulis lapisan translasi antara API mereka dan dataclass standar.

Mengapa Connection Pooling?

Tanpa connection pooling, setiap request HTTP akan membuka koneksi TCP baru ke PostgreSQL. Itu berarti TCP handshake, negosiasi SSL, autentikasi, dan setup koneksi — semuanya sebelum satu kueri pun dijalankan. Saat beban tinggi, ini bisa menambah ratusan milidetik per request dan menghabiskan batas koneksi database.

Dengan pooling, sekumpulan koneksi dibuat sekali saat startup dan dijaga tetap hidup. Saat sebuah request membutuhkan database, ia meminjam koneksi dari pool, menjalankan kuerinya, dan mengembalikannya. Pool juga menangani koneksi basi: ia dapat menguji setiap koneksi dengan SELECT 1 ringan sebelum menyerahkannya. Jika pengujian gagal (koneksi terputus, gangguan jaringan), pool secara diam-diam membuat koneksi baru.

Konfigurasi memiliki dua pengatur: pool_size (koneksi minimum yang selalu siap, default 5) dan max_overflow (berapa banyak koneksi tambahan yang dapat dibuat saat lonjakan lalu lintas, default 10). Ini menjaga penggunaan memori tetap terprediksi sambil tetap menangani lonjakan.

Jebakan GEE

ImageCollection vs. Image — kesalahan GEE #1

Peringatan RADD (projects/radar-wur/raddalert/v1) dan ESA WorldCover (ESA/WorldCover/v200) keduanya adalah ImageCollection, bukan Image tunggal. Memuatnya dengan ee.Image("...") menyebabkan error: “Image.load: Asset is not an Image.”

Solusinya: gunakan ee.ImageCollection("...").first() untuk WorldCover (karena berisi satu mosaik global) atau filter berdasarkan rentang tanggal dan reduksi dengan .max() untuk RADD.

Jebakan umum lainnya: ImageCollection RADD berisi tipe citra campuran — beberapa memiliki band peringatan, yang lain memiliki band baseline. Memanggil .max() pada seluruh koleksi memicu error “Expected a homogeneous image collection.” Solusinya: .select('Alert') sebelum .max() agar semua citra memiliki struktur band yang sama.

GEE vs CDSE: Kapan Menggunakan Yang Mana

Kedua provider terimplementasi penuh, tetapi memiliki kekuatan dan arsitektur yang berbeda. Tabel berikut merangkum perbedaan utama:

Aspek GEE CDSE
Arsitektur Lapisan delegasi tipis (392 baris) — mendelegasikan ke layanan khusus Mandiri dan komprehensif (1.920 baris) — semua logika dalam satu file
Kehilangan Hutan Hansen GFC via GEE API (lossyear band) Global Forest Watch Data API (data-api.globalforestwatch.org)
Peringatan Radar RADD via GEE ImageCollection Global Forest Watch Data API (endpoint peringatan RADD)
Tutupan Lahan ESA WorldCover via GEE ESA WorldCover via Terrascope WMS/STAC (dengan mekanisme fallback)
Citra Satelit Sentinel-2 via GEE Sentinel-2 via SentinelHub Process API
Autentikasi Service account key file + ee.Initialize() OAuth2 client credentials (CDSE_CLIENT_ID / CDSE_CLIENT_SECRET)
Fallback Offline Tidak ada — memerlukan koneksi GEE Data simulasi deterministik (hash MD5 geometri sebagai seed)
Terbaik Untuk Lingkungan riset, akses ke petabyte data historis GEE Deployment produksi, ketahanan tinggi, independen dari Google
Catatan Produksi

Deployment produksi saat ini menggunakan CDSE (DATA_PROVIDER=cdse). Provider GEE tetap tersedia sebagai alternatif untuk lingkungan pengembangan dan riset.

Referensi Layanan Eksternal

Dataset Satelit

Dataset ID Resolusi Cakupan Band yang Digunakan
Hansen GFC UMD/hansen/global_forest_change_2023_v1_11 30 m Global (2001+) lossyear
RADD projects/radar-wur/raddalert/v1 10 m Tropis (2019+) Alert
ESA WorldCover ESA/WorldCover/v200 10 m Global (2021) Map
Sentinel-2 L2A COPERNICUS/S2_SR_HARMONIZED 10 m Global B2-B4, B8 (RGB+NIR)

Metode Antarmuka Provider

Metode Mengembalikan Deskripsi
initialize() bool Terhubung ke sumber data dan melakukan autentikasi
get_forest_loss_alerts(geometry, start, end) AlertResult Peringatan kehilangan hutan (berbasis optik/Landsat)
get_radar_alerts(geometry, start, end) AlertResult Peringatan deforestasi berbasis radar (Sentinel-1)
get_land_cover(geometry, year) LandCoverResult Klasifikasi tutupan lahan (pohon, pertanian, air, dll.)
get_satellite_imagery(geometry, date) ImageryResult Citra satelit warna asli untuk tanggal tertentu
get_ndvi_analysis(geometry, baseline, current) NDVIResult Perbandingan indeks vegetasi antara dua tahun

Variabel Lingkungan

Variabel Default Deskripsi
DATA_PROVIDER gee Provider satelit mana yang digunakan (gee, planetary, cdse)
GEE_SERVICE_ACCOUNT false Gunakan autentikasi service account untuk GEE
GEE_PROJECT_ID ID proyek Google Earth Engine
DB_HOST localhost Host database PostgreSQL
DB_POOL_SIZE 5 Koneksi minimum yang dijaga di connection pool
SMTP_HOST smtp.gmail.com Hostname server email SMTP

Endpoint API Provider CDSE

Layanan URL Metode Tujuan
GFW Data API data-api.globalforestwatch.org GET / POST Kueri data kehilangan hutan dan peringatan deforestasi
CDSE Identity identity.dataspace.copernicus.eu/auth/realms/CDSE/protocol/openid-connect/token POST Autentikasi OAuth2 untuk mendapatkan access token
SentinelHub Process sh.dataspace.copernicus.eu/api/v1/process POST Mengambil citra satelit Sentinel-2 dan menghitung NDVI
Terrascope WMS services.terrascope.be/wms GET Mengambil peta tutupan lahan ESA WorldCover (primer)
Terrascope STAC services.terrascope.be/stac GET Mengambil tile tutupan lahan ESA WorldCover (fallback)
GFW RADD data-api.globalforestwatch.org/dataset/gfw_radd_deforestation_alerts GET / POST Kueri peringatan deforestasi berbasis radar RADD

Perbandingan Implementasi Provider

Fitur GEE CDSE Planetary
Kehilangan Hutan Terimplementasi (Hansen GFC) Terimplementasi (GFW Data API) Belum diimplementasi
Peringatan Radar Terimplementasi (RADD via GEE) Terimplementasi (RADD via GFW) Belum diimplementasi
Tutupan Lahan Terimplementasi (ESA WorldCover via GEE) Terimplementasi (Terrascope WMS/STAC) Belum diimplementasi
Citra Satelit Terimplementasi (Sentinel-2 via GEE) Terimplementasi (SentinelHub Process API) Terimplementasi (Sentinel-2 via STAC)
Analisis NDVI Terimplementasi Terimplementasi Belum diimplementasi
Fallback Offline Tidak ada Data simulasi deterministik (MD5) Tidak ada
Status Produksi Tersedia (alternatif) Aktif di produksi Parsial

Variabel Lingkungan CDSE

Variabel Default Deskripsi
DATA_PROVIDER gee Atur ke cdse untuk menggunakan provider Copernicus Data Space
CDSE_CLIENT_ID OAuth2 client ID dari Copernicus Data Space (didaftarkan di dataspace.copernicus.eu)
CDSE_CLIENT_SECRET OAuth2 client secret yang dipasangkan dengan CDSE_CLIENT_ID
GFW_API_KEY API key untuk Global Forest Watch Data API (opsional, meningkatkan rate limit)