# AIR SDA - Spesifikasi REST API

Base URL: `http://localhost:3000/api`
Autentikasi: Bearer JWT (kecuali endpoint /auth/login dan /health).

## Authentication

POST /auth/login dengan body { username, password } mengembalikan accessToken (JWT, masa aktif 8 jam) dan refreshToken (random 96 karakter, masa aktif 30 hari). Pakai accessToken sebagai header Authorization: Bearer untuk semua endpoint terproteksi.

POST /auth/refresh dengan body { refreshToken } mengembalikan accessToken baru tanpa perlu login ulang.

POST /auth/logout merevoke refreshToken aktif. Memerlukan header Authorization.

GET /auth/me mengembalikan info pengguna login termasuk permissions yang dimiliki, untuk frontend menentukan menu/tombol apa yang ditampilkan.

## Bangunan

GET /bangunan menerima query: search (substring nama/kode), jenis_id, kondisi, di_id, kategori (BANGUNAN/SALURAN/PETAK), bbox (minX,minY,maxX,maxY untuk filter viewport peta), limit, offset. Response berisi array data dengan field GeoJSON geom, lat/lng dari centroid, dan total_count untuk pagination.

GET /bangunan/:id mengembalikan detail lengkap satu bangunan beserta semua riwayat inspeksi dan daftar foto terkait.

POST /bangunan menerima body JSON dengan kode, nama, jenis_id, geom (GeoJSON Geometry: Point/LineString/Polygon), kondisi_saat_ini, dan field opsional lainnya. Validasi via Joi. Otomatis menyimpan organisasi_id dan created_by dari user login.

PUT /bangunan/:id update full record. Body sama dengan POST.

DELETE /bangunan/:id soft delete (set deleted_at). Data tetap ada untuk audit tapi tidak muncul di list.

GET /bangunan/statistik/dashboard mengembalikan agregat: total, baik, rusak_ringan, rusak_sedang, rusak_berat, perlu_inspeksi (yang lebih dari 6 bulan tidak diinspeksi).

GET /bangunan/nearby/search?lat=&lng=&radius_km= mengembalikan bangunan dalam radius dari koordinat, diurutkan dari yang terdekat. Berguna untuk fitur "bangunan di sekitar saya" pada Mode Lapangan.

## Inspeksi

GET /inspeksi?bangunan_id=&status= list inspeksi dengan filter opsional.

POST /inspeksi membuat catatan inspeksi baru berstatus DRAFT. Field penting: bangunan_id, tanggal_inspeksi, kondisi, persentase_kerusakan, catatan, rekomendasi, prioritas (RENDAH/SEDANG/TINGGI/URGENT), lokasi_inspeksi (GeoJSON Point dari GPS petugas).

POST /inspeksi/:id/approve mengubah status menjadi APPROVED dan trigger PostgreSQL otomatis memperbarui kondisi terkini bangunan. Memerlukan permission inspeksi.approve.

POST /inspeksi/:id/reject menolak inspeksi dengan alasan.

## Foto

POST /foto menerima multipart/form-data dengan field file (gambar JPEG/PNG/WEBP/HEIC max 20MB) dan metadata bangunan_id atau inspeksi_id, caption, taken_at, lat, lng, gps_accuracy_m, device_info. File disimpan ke disk lokal atau S3 (tergantung konfigurasi), URL publik dikembalikan untuk preview.

DELETE /foto/:id menghapus record DB dan file fisik.

## Layer GIS

GET /layer-gis mengembalikan semua layer milik organisasi plus layer publik.

POST /layer-gis multipart untuk upload .zip (shapefile) atau .tif (GeoTIFF), atau JSON untuk register URL tile XYZ/WMS/WMTS/LTS. Field: nama, tipe (SHAPEFILE/GEOTIFF/XYZ_TILE/WMS/WMTS/LTS), url (jika tile service), file (jika upload), opacity, warna, is_public.

DELETE /layer-gis/:id menghapus layer dan file fisik jika ada.

## Daerah Irigasi

GET /daerah-irigasi list DI di organisasi pengguna login dengan geom_area sebagai GeoJSON.

POST /daerah-irigasi membuat DI baru. Memerlukan permission di.manage. Body: kode_di, nama, kewenangan, luas_potensial_ha, luas_fungsional_ha, sumber_air, geom_area (GeoJSON MultiPolygon).

## Wilayah

GET /wilayah?tingkat=&parent_id=&search= mengambil hirarki wilayah administratif. Tingkat: PROVINSI/KABUPATEN/KECAMATAN/DESA. Untuk dropdown bertingkat, gunakan parent_id untuk filter anak dari satu parent.

## Master Data

GET /master/kategori daftar 3 kategori (BANGUNAN, SALURAN, PETAK) beserta warna default.

GET /master/jenis daftar semua jenis bangunan dengan info kategori induknya. Untuk populate dropdown jenis di form.

GET /master/role daftar role untuk admin yang menambah user baru.

## Pengguna

GET /pengguna list user di organisasi pengguna login. Memerlukan permission user.manage.

POST /pengguna tambah user baru. Body: username, email, password, nama_lengkap, nip, jabatan, role_id. Password otomatis di-hash bcrypt.

## Organisasi

GET /organisasi list semua organisasi (untuk SUPERADMIN).

GET /organisasi/me info organisasi pengguna login.

POST /organisasi (SUPERADMIN only) tambah organisasi baru.

## Laporan

GET /laporan/rekap-kondisi agregat bangunan per DI per kondisi. Untuk export ke Excel/PDF.

GET /laporan/rekap-jenis agregat bangunan per jenis dan kategori.

GET /laporan/inspeksi-tertunda list bangunan yang belum diinspeksi lebih dari 6 bulan, diurutkan dari yang paling lama tidak diinspeksi.

## Format Error

Semua error mengembalikan JSON: { error: "TipeError", message: "Pesan untuk user" } dengan HTTP status sesuai (400 BadRequest, 401 Unauthorized, 403 Forbidden, 404 NotFound, 409 Conflict, 500 InternalServerError).

## Pagination

Endpoint list yang mengembalikan banyak data menggunakan query limit dan offset. Default limit 100, offset 0. Response menyertakan field total untuk total record yang match filter (sebelum pagination) sehingga frontend dapat menampilkan total halaman.
