From 39fe810cba308b7b31b62e8028a8abeb95d133b3 Mon Sep 17 00:00:00 2001 From: rbsetiawan Date: Tue, 23 Jun 2026 17:00:43 +0700 Subject: [PATCH] docs: buat struktur docapi AI-Friendly untuk geonet-console - README.md, index.md, authentication.md, common-response.md, common-error.md, integration-guide.md - services/auth/README.md + login.md - services/service-tokens/README.md + create, show, list, revoke, regenerate, delete, by-service, active, expired - services/databases/README.md - services/ldap/README.md - services/project-search/README.md Dokumentasi mencakup: business rule, contoh request/response, sequence flow, audit log, error guide, retry policy, SDK cURL/Python/Laravel, dampak ke GeoNetAgent. --- .../geonet-console/docapi/README.md | 72 +++++++ .../geonet-console/docapi/authentication.md | 107 ++++++++++ .../geonet-console/docapi/common-error.md | 116 +++++++++++ .../geonet-console/docapi/common-response.md | 90 +++++++++ .../geonet-console/docapi/index.md | 79 ++++++++ .../docapi/integration-guide.md | 145 ++++++++++++++ .../docapi/services/auth/README.md | 48 +++++ .../docapi/services/auth/login.md | 188 ++++++++++++++++++ .../docapi/services/databases/README.md | 41 ++++ .../docapi/services/ldap/README.md | 49 +++++ .../docapi/services/project-search/README.md | 42 ++++ .../docapi/services/service-tokens/README.md | 119 +++++++++++ .../docapi/services/service-tokens/active.md | 48 +++++ .../services/service-tokens/by-service.md | 52 +++++ .../docapi/services/service-tokens/create.md | 178 +++++++++++++++++ .../docapi/services/service-tokens/delete.md | 58 ++++++ .../docapi/services/service-tokens/expired.md | 48 +++++ .../docapi/services/service-tokens/list.md | 57 ++++++ .../services/service-tokens/regenerate.md | 136 +++++++++++++ .../docapi/services/service-tokens/revoke.md | 90 +++++++++ .../docapi/services/service-tokens/show.md | 66 ++++++ 21 files changed, 1829 insertions(+) create mode 100644 server-connection/geonet-console/docapi/README.md create mode 100644 server-connection/geonet-console/docapi/authentication.md create mode 100644 server-connection/geonet-console/docapi/common-error.md create mode 100644 server-connection/geonet-console/docapi/common-response.md create mode 100644 server-connection/geonet-console/docapi/index.md create mode 100644 server-connection/geonet-console/docapi/integration-guide.md create mode 100644 server-connection/geonet-console/docapi/services/auth/README.md create mode 100644 server-connection/geonet-console/docapi/services/auth/login.md create mode 100644 server-connection/geonet-console/docapi/services/databases/README.md create mode 100644 server-connection/geonet-console/docapi/services/ldap/README.md create mode 100644 server-connection/geonet-console/docapi/services/project-search/README.md create mode 100644 server-connection/geonet-console/docapi/services/service-tokens/README.md create mode 100644 server-connection/geonet-console/docapi/services/service-tokens/active.md create mode 100644 server-connection/geonet-console/docapi/services/service-tokens/by-service.md create mode 100644 server-connection/geonet-console/docapi/services/service-tokens/create.md create mode 100644 server-connection/geonet-console/docapi/services/service-tokens/delete.md create mode 100644 server-connection/geonet-console/docapi/services/service-tokens/expired.md create mode 100644 server-connection/geonet-console/docapi/services/service-tokens/list.md create mode 100644 server-connection/geonet-console/docapi/services/service-tokens/regenerate.md create mode 100644 server-connection/geonet-console/docapi/services/service-tokens/revoke.md create mode 100644 server-connection/geonet-console/docapi/services/service-tokens/show.md diff --git a/server-connection/geonet-console/docapi/README.md b/server-connection/geonet-console/docapi/README.md new file mode 100644 index 0000000..e73ec84 --- /dev/null +++ b/server-connection/geonet-console/docapi/README.md @@ -0,0 +1,72 @@ +# docapi — API Documentation (geonet-console) + +Folder ini adalah **Single Source of Truth** untuk seluruh dokumentasi API geonet-console. + +AI Agent dan Developer **wajib** membaca folder ini sebelum menggunakan atau mengembangkan API. +Tidak perlu membuka source code, controller, atau database schema. + +--- + +## Aturan + +- Dokumentasi API adalah bagian dari source code. +- Implementasi tanpa dokumentasi dianggap **belum selesai**. +- Setiap perubahan API **wajib** diikuti perubahan dokumentasi di folder ini. +- Markdown menjelaskan business rule. OpenAPI (`api-docs/openapi.json`) menjelaskan spesifikasi teknis. + +--- + +## Struktur + +``` +docapi/ + README.md ← file ini + index.md ← daftar semua endpoint + authentication.md ← panduan autentikasi + common-response.md ← format response standar + common-error.md ← kode error standar + pagination.md ← konvensi paginasi + versioning.md ← kebijakan versi API + integration-guide.md ← panduan integrasi antar service + + services/ + auth/ ← login, token guide + service-tokens/ ← CRUD service tokens (microservice Bearer) + databases/ ← database registry + ldap/ ← LDAP users & groups + project-search/ ← Ollama NAS project search +``` + +--- + +## Base URL + +| Environment | URL | +|-------------|-----| +| Production | `https://console.gisportal.id/api/v1` | + +## Autentikasi + +Lihat [`authentication.md`](./authentication.md) untuk panduan lengkap. + +Ringkasan: semua endpoint (kecuali `/auth/login`) memerlukan header: + +``` +Authorization: Bearer +``` + +Token diperoleh dari `POST /api/v1/auth/login` atau dari API Token yang diterbitkan di halaman `/api-clients`. + +--- + +## Checklist AI Sebelum Membuat Endpoint Baru + +- [ ] Endpoint dibuat di `routes/api.php` +- [ ] Controller method dibuat +- [ ] File markdown endpoint dibuat di `docapi/services/{service}/` +- [ ] `docapi/services/{service}/README.md` diperbarui +- [ ] `docapi/index.md` diperbarui +- [ ] Contoh request & response disertakan +- [ ] Error dijelaskan +- [ ] Business rule dijelaskan +- [ ] Audit log dicatat jika endpoint mengubah data diff --git a/server-connection/geonet-console/docapi/authentication.md b/server-connection/geonet-console/docapi/authentication.md new file mode 100644 index 0000000..169addc --- /dev/null +++ b/server-connection/geonet-console/docapi/authentication.md @@ -0,0 +1,107 @@ +# Authentication — geonet-console API + +geonet-console mendukung **3 metode autentikasi** untuk API. + +--- + +## 1. LDAP JWT (untuk pengguna manusia / AI Agent interaktif) + +Diperoleh dari `POST /api/v1/auth/login` menggunakan kredensial domain LDAP. + +``` +POST /api/v1/auth/login +Content-Type: application/json + +{ + "username": "john.doe", + "password": "password123" +} +``` + +Response: + +```json +{ + "data": { + "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", + "token_type": "Bearer", + "expires_in": 3600, + "auth_type": "ldap_jwt", + "user": { + "username": "john.doe", + "display_name": "John Doe", + "is_admin": true + } + } +} +``` + +Gunakan token pada setiap request: + +``` +Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... +``` + +**TTL:** Default 3600 detik (1 jam). Dikonfigurasi via `API_LDAP_JWT_TTL` di `.env`. + +**Scope:** JWT dari admin LDAP memiliki akses penuh. JWT dari non-admin hanya akses terbatas. + +--- + +## 2. API Token (untuk service-to-service, server-side automation) + +Diterbitkan di halaman `/api-clients` oleh admin. Token tidak expire kecuali dihapus manual. + +``` +Authorization: Bearer geonet_ +``` + +Setiap API Token memiliki **scope** yang menentukan akses: + +| Scope | Akses | +|-------|-------| +| `databases:read` | Baca daftar database | +| `databases:write` | Ubah status database | +| `ldap:read` | Baca user & group LDAP | +| `ldap:write` | Ubah user & group LDAP | +| `project-search:read` | Query project search | + +--- + +## 3. Service Token (untuk microservice Bearer token — GeoNetAgent, dll.) + +Diterbitkan di `/api-clients` → bagian **Service Tokens**. +Digunakan oleh microservice seperti GeoNetAgent untuk autentikasi ke collector. + +``` +Authorization: Bearer Col5FUFl34dVXgyBgTSA23KsYc5QhAh8s224OkR5GjQ +``` + +> **Catatan:** Service Token divalidasi oleh masing-masing microservice (bukan oleh geonet-console API). geonet-console hanya berfungsi sebagai registry dan management UI. Lihat [`services/service-tokens/README.md`](./services/service-tokens/README.md). + +--- + +## Urutan Prioritas Autentikasi + +``` +Request masuk + ↓ +Cek header: Authorization: Bearer + ↓ +Apakah JWT? (starts with eyJ) + → Ya → Validasi JWT LDAP + → Tidak → Cek API Token di database + → Valid → Lanjut dengan scope token + → Tidak valid → 401 Unauthorized +``` + +--- + +## Error Autentikasi + +| Kode | Kondisi | Solusi | +|------|---------|--------| +| `401` | Token tidak ada / tidak valid | Login ulang atau cek token | +| `401` | JWT expired | Login ulang ke `POST /auth/login` | +| `403` | Token valid tapi scope tidak cukup | Minta admin tambah scope | +| `429` | Rate limit login (10x/menit) | Tunggu 1 menit | diff --git a/server-connection/geonet-console/docapi/common-error.md b/server-connection/geonet-console/docapi/common-error.md new file mode 100644 index 0000000..f605603 --- /dev/null +++ b/server-connection/geonet-console/docapi/common-error.md @@ -0,0 +1,116 @@ +# Error Guide — geonet-console API + +Panduan lengkap untuk menangani error. AI Agent tidak boleh menebak — ikuti panduan ini. + +--- + +## 401 Unauthorized + +**Kondisi:** Token tidak ada, tidak valid, atau expired. + +**Solusi:** +- JWT expired → Login ulang ke `POST /api/v1/auth/login` +- API Token salah → Cek token di `/api-clients` +- Header tidak ada → Pastikan format `Authorization: Bearer ` + +**Contoh response:** +```json +{ + "error": { + "code": "UNAUTHENTICATED", + "message": "Unauthenticated." + } +} +``` + +**Retry:** Tidak boleh retry dengan token yang sama. Harus dapatkan token baru. + +--- + +## 403 Forbidden + +**Kondisi:** Token valid tapi tidak memiliki scope yang diperlukan. + +**Solusi:** Minta admin tambahkan scope yang diperlukan pada API Token di `/api-clients`. + +**Contoh response:** +```json +{ + "error": { + "code": "FORBIDDEN", + "message": "Insufficient scope. Required: ldap:write" + } +} +``` + +**Retry:** Tidak perlu retry. Masalah ada di permission, bukan token. + +--- + +## 404 Not Found + +**Kondisi:** Resource tidak ditemukan (ID salah, sudah dihapus). + +**Contoh response:** +```json +{ + "error": { + "code": "NOT_FOUND", + "message": "Service token not found" + } +} +``` + +**Retry:** Tidak perlu retry. Verifikasi ID yang digunakan. + +--- + +## 422 Unprocessable Entity + +**Kondisi:** Data request tidak lulus validasi. + +**Contoh response:** +```json +{ + "message": "The given data was invalid.", + "errors": { + "name": ["The name field is required."], + "expires_in_days": ["The expires in days must be at least 1."] + } +} +``` + +**Retry:** Tidak perlu retry. Perbaiki data request sesuai pesan error. + +--- + +## 429 Too Many Requests + +**Kondisi:** Melebihi rate limit. + +| Endpoint | Rate Limit | +|----------|------------| +| `POST /auth/login` | 10 request / menit | +| `POST /project-search/ask` | 20 request / menit | + +**Contoh response:** +```json +{ + "message": "Too Many Attempts." +} +``` + +**Retry:** Tunggu 60 detik sebelum retry. Cek header `Retry-After`. + +--- + +## 500 Internal Server Error + +**Kondisi:** Error di sisi server (bug, DB down, dll.). + +**Solusi:** +1. Cek Laravel log: `docker exec geonet-console tail -100 storage/logs/laravel.log` +2. Cek container: `docker logs geonet-console --tail 50` +3. Jangan retry lebih dari 3x dengan exponential backoff. + +**Retry policy:** Max 3x, backoff: 1s → 2s → 4s. diff --git a/server-connection/geonet-console/docapi/common-response.md b/server-connection/geonet-console/docapi/common-response.md new file mode 100644 index 0000000..d7c42aa --- /dev/null +++ b/server-connection/geonet-console/docapi/common-response.md @@ -0,0 +1,90 @@ +# Format Response Standar + +Semua response API geonet-console menggunakan format JSON konsisten. + +--- + +## Response Sukses — Single Resource + +```json +{ + "data": { + "id": "uuid", + "field": "value" + } +} +``` + +## Response Sukses — Collection + +```json +{ + "data": [ + { "id": "uuid-1", "field": "value" }, + { "id": "uuid-2", "field": "value" } + ] +} +``` + +## Response Sukses — Action (revoke, delete, dll.) + +```json +{ + "message": "Operasi berhasil." +} +``` + +## Response Sukses — Create (dengan token sekali tampil) + +```json +{ + "data": { + "id": "uuid", + "token": "plain_token_hanya_tampil_sekali", + "token_prefix": "Col5FUFl34dVXgyB" + }, + "message": "Token created. Save it now — it will not be shown again." +} +``` + +--- + +## Response Error + +```json +{ + "error": { + "code": "ERROR_CODE", + "message": "Deskripsi error yang dapat dibaca manusia." + } +} +``` + +## Response Error — Validation + +```json +{ + "message": "The given data was invalid.", + "errors": { + "name": ["The name field is required."], + "service": ["The service field is required."] + } +} +``` + +--- + +## HTTP Status Codes + +| Code | Kondisi | +|------|---------| +| `200` | OK — request berhasil | +| `201` | Created — resource baru dibuat | +| `204` | No Content — delete berhasil | +| `400` | Bad Request — request tidak valid | +| `401` | Unauthorized — tidak ada / token invalid | +| `403` | Forbidden — token valid tapi tidak punya akses | +| `404` | Not Found — resource tidak ditemukan | +| `422` | Unprocessable Entity — validasi gagal | +| `429` | Too Many Requests — rate limit | +| `500` | Internal Server Error — error server | diff --git a/server-connection/geonet-console/docapi/index.md b/server-connection/geonet-console/docapi/index.md new file mode 100644 index 0000000..bec1c72 --- /dev/null +++ b/server-connection/geonet-console/docapi/index.md @@ -0,0 +1,79 @@ +# API Endpoint Index — geonet-console + +Base URL: `https://console.gisportal.id/api/v1` + +--- + +## Auth + +| Method | Endpoint | Auth | Scope | Deskripsi | Dokumen | +|--------|----------|------|-------|-----------|---------| +| POST | `/auth/login` | — | — | Login LDAP, dapat JWT | [login.md](./services/auth/login.md) | +| GET | `/auth/token-guide` | — | — | Panduan penggunaan token | [token-guide.md](./services/auth/token-guide.md) | + +--- + +## Me + +| Method | Endpoint | Auth | Scope | Deskripsi | Dokumen | +|--------|----------|------|-------|-----------|---------| +| GET | `/me` | JWT / API Token | — | Info user yang sedang login | [me.md](./services/auth/me.md) | + +--- + +## Databases + +| Method | Endpoint | Auth | Scope | Deskripsi | Dokumen | +|--------|----------|------|-------|-----------|---------| +| GET | `/databases` | JWT / API Token | `databases:read` | List semua database | [index.md](./services/databases/list.md) | +| POST | `/databases/{database}/offline` | JWT / API Token | `databases:write` | Tandai database offline | [offline.md](./services/databases/offline.md) | + +--- + +## LDAP Users + +| Method | Endpoint | Auth | Scope | Deskripsi | Dokumen | +|--------|----------|------|-------|-----------|---------| +| GET | `/ldap/users` | JWT / API Token | `ldap:read` | List semua user LDAP | [list.md](./services/ldap/users-list.md) | +| GET | `/ldap/users/{username}` | JWT / API Token | `ldap:read` | Detail user LDAP | [show.md](./services/ldap/users-show.md) | +| PUT | `/ldap/users/{username}` | JWT / API Token | `ldap:write` | Update user LDAP | [update.md](./services/ldap/users-update.md) | +| POST | `/ldap/users/{username}/groups` | JWT / API Token | `ldap:write` | Tambah user ke group | [add-group.md](./services/ldap/users-add-group.md) | +| DELETE | `/ldap/users/{username}/groups/{group}` | JWT / API Token | `ldap:write` | Hapus user dari group | [remove-group.md](./services/ldap/users-remove-group.md) | + +--- + +## LDAP Groups + +| Method | Endpoint | Auth | Scope | Deskripsi | Dokumen | +|--------|----------|------|-------|-----------|---------| +| GET | `/ldap/groups` | JWT / API Token | `ldap:read` | List semua group | [list.md](./services/ldap/groups-list.md) | +| GET | `/ldap/groups/{group}` | JWT / API Token | `ldap:read` | Detail group | [show.md](./services/ldap/groups-show.md) | +| POST | `/ldap/groups` | JWT / API Token | `ldap:write` | Buat group baru | [create.md](./services/ldap/groups-create.md) | +| POST | `/ldap/groups/{group}/members` | JWT / API Token | `ldap:write` | Tambah member ke group | [add-member.md](./services/ldap/groups-add-member.md) | +| DELETE | `/ldap/groups/{group}/members/{username}` | JWT / API Token | `ldap:write` | Hapus member dari group | [remove-member.md](./services/ldap/groups-remove-member.md) | + +--- + +## Service Tokens + +| Method | Endpoint | Auth | Scope | Deskripsi | Dokumen | +|--------|----------|------|-------|-----------|---------| +| GET | `/service-tokens` | JWT / API Token | — | List semua service tokens | [list.md](./services/service-tokens/list.md) | +| POST | `/service-tokens` | JWT / API Token | — | Buat service token baru | [create.md](./services/service-tokens/create.md) | +| GET | `/service-tokens/{id}` | JWT / API Token | — | Detail service token | [show.md](./services/service-tokens/show.md) | +| POST | `/service-tokens/{id}/revoke` | JWT / API Token | — | Revoke service token | [revoke.md](./services/service-tokens/revoke.md) | +| POST | `/service-tokens/{id}/regenerate` | JWT / API Token | — | Regenerate service token | [regenerate.md](./services/service-tokens/regenerate.md) | +| DELETE | `/service-tokens/{id}` | JWT / API Token | — | Hapus service token | [delete.md](./services/service-tokens/delete.md) | +| GET | `/service-tokens/by-service/{service}` | JWT / API Token | — | Token by nama service | [by-service.md](./services/service-tokens/by-service.md) | +| GET | `/service-tokens/active` | JWT / API Token | — | Semua token aktif | [active.md](./services/service-tokens/active.md) | +| GET | `/service-tokens/expired` | JWT / API Token | — | Semua token expired | [expired.md](./services/service-tokens/expired.md) | + +--- + +## Project Search + +| Method | Endpoint | Auth | Scope | Deskripsi | Dokumen | +|--------|----------|------|-------|-----------|---------| +| GET | `/project-search/sources` | JWT / API Token | `project-search:read` | Daftar sumber data | [sources.md](./services/project-search/sources.md) | +| GET | `/project-search/index/status` | JWT / API Token | `project-search:read` | Status indeks per source | [index-status.md](./services/project-search/index-status.md) | +| POST | `/project-search/ask` | JWT / API Token | `project-search:read` | Query natural language | [ask.md](./services/project-search/ask.md) | diff --git a/server-connection/geonet-console/docapi/integration-guide.md b/server-connection/geonet-console/docapi/integration-guide.md new file mode 100644 index 0000000..fdeb163 --- /dev/null +++ b/server-connection/geonet-console/docapi/integration-guide.md @@ -0,0 +1,145 @@ +# Integration Guide — geonet-console API + +Panduan integrasi untuk AI Agent dan microservice yang menggunakan geonet-console API. + +--- + +## Alur Integrasi untuk AI Agent (JWT) + +``` +Langkah 1: Login +POST /api/v1/auth/login + ↓ +Langkah 2: Simpan access_token + ↓ +Langkah 3: Gunakan token pada setiap request +Authorization: Bearer + ↓ +Langkah 4: Jika response 401 → Login ulang + ↓ +Langkah 5: Jika response 403 → Token tidak punya scope yang cukup +``` + +--- + +## Alur Integrasi untuk Microservice (API Token / Service Token) + +``` +Langkah 1: Admin buat API Token atau Service Token di /api-clients + ↓ +Langkah 2: Simpan token di .env atau config microservice + ↓ +Langkah 3: Gunakan pada setiap request +Authorization: Bearer + ↓ +Langkah 4: Token tidak expire kecuali dihapus/direvoke manual +``` + +--- + +## Dependency Antar Service + +``` +geonet-console + ↓ membaca +LDAP (Active Directory) — 10.100.1.40 + ↓ membaca/menulis +PostgreSQL App DB (databaselist_app) — 10.100.1.24 (Docker) + ↓ menulis audit +PostgreSQL Audit DB (databaselist_audit) — 10.100.1.24 (Docker) + ↓ sinkronisasi service tokens +PostgreSQL GeoNetAgent DB (geonetagent_dev) — 10.100.1.25 + ↓ query project search +PostgreSQL Project Search DB (geonet_project_search) — 10.100.1.25 + ↓ inference +Ollama (VM aiopr) — 10.100.1.26 +``` + +--- + +## GeoNetAgent Integration + +GeoNetAgent menggunakan **Service Token** untuk autentikasi ke collector. + +Token dikelola di geonet-console `/api-clients` → **Service Tokens**. +Saat token dibuat/regenerate di UI, token otomatis disinkronkan ke `geonetagent_dev.agent_tokens`. + +``` +Admin buat Service Token di geonet-console + ↓ sinkron otomatis +geonetagent_dev.agent_tokens (via AgentTokenSyncService) + ↓ +GeoNetAgent Agent (PowerShell) baca config.json + ↓ +POST https://agent.gisportal.id/api/v1/agent/report +Authorization: Bearer + ↓ +Collector (FastAPI) validasi token dari agent_tokens + ↓ +200 OK / 401 Unauthorized +``` + +**File config agent:** `GeoNetAgent/agent/config.json` +```json +{ + "collector_url": "https://agent.gisportal.id/api/v1/agent/report", + "agent_token": "" +} +``` + +--- + +## Contoh SDK + +### cURL (wajib) + +```bash +# Login +curl -s -X POST https://console.gisportal.id/api/v1/auth/login \ + -H "Content-Type: application/json" \ + -d '{"username":"john.doe","password":"password123"}' + +# List databases (dengan JWT) +curl -s https://console.gisportal.id/api/v1/databases \ + -H "Authorization: Bearer " + +# List service tokens (dengan API Token) +curl -s https://console.gisportal.id/api/v1/service-tokens \ + -H "Authorization: Bearer " +``` + +### Python + +```python +import requests + +BASE_URL = "https://console.gisportal.id/api/v1" + +# Login +resp = requests.post(f"{BASE_URL}/auth/login", json={ + "username": "john.doe", + "password": "password123" +}) +token = resp.json()["data"]["access_token"] + +# Gunakan token +headers = {"Authorization": f"Bearer {token}"} +databases = requests.get(f"{BASE_URL}/databases", headers=headers).json() +``` + +### Laravel (PHP) + +```php +use Illuminate\Support\Facades\Http; + +$response = Http::post('https://console.gisportal.id/api/v1/auth/login', [ + 'username' => 'john.doe', + 'password' => 'password123', +]); + +$token = $response->json('data.access_token'); + +$databases = Http::withToken($token) + ->get('https://console.gisportal.id/api/v1/databases') + ->json(); +``` diff --git a/server-connection/geonet-console/docapi/services/auth/README.md b/server-connection/geonet-console/docapi/services/auth/README.md new file mode 100644 index 0000000..8b90eb1 --- /dev/null +++ b/server-connection/geonet-console/docapi/services/auth/README.md @@ -0,0 +1,48 @@ +# Auth Service + +## Deskripsi + +Menyediakan autentikasi berbasis LDAP dengan JWT token untuk akses API geonet-console. + +## Tanggung Jawab + +- Login via kredensial LDAP domain (Active Directory) +- Menerbitkan JWT token dengan TTL terkonfigurasi +- Menyediakan panduan penggunaan token + +## Dependency + +- Active Directory LDAP: `10.100.1.40:389` +- `LdapAuthService` — validasi kredensial +- `LdapJwtService` — penerbitan dan validasi JWT + +## URL Service + +`https://console.gisportal.id/api/v1/auth` + +## Authentication + +Endpoint login dan token-guide **tidak memerlukan autentikasi**. + +## Endpoint + +| Method | Path | Deskripsi | Dokumen | +|--------|------|-----------|---------| +| POST | `/auth/login` | Login LDAP, dapat JWT | [login.md](./login.md) | +| GET | `/auth/token-guide` | Panduan token | [token-guide.md](./token-guide.md) | +| GET | `/me` | Info user aktif | [me.md](./me.md) | + +## Database + +- Tidak menulis ke database (autentikasi murni via LDAP) +- Audit log ditulis ke `databaselist_audit` via `AuditLogService` + +## Rate Limit + +- `POST /auth/login`: 10 request/menit per IP + +## Service yang Memanggil + +- Browser UI (form login) +- AI Agent (automation login) +- Microservice yang butuh JWT untuk API call diff --git a/server-connection/geonet-console/docapi/services/auth/login.md b/server-connection/geonet-console/docapi/services/auth/login.md new file mode 100644 index 0000000..365fdf8 --- /dev/null +++ b/server-connection/geonet-console/docapi/services/auth/login.md @@ -0,0 +1,188 @@ +# Login + +## Tujuan + +Autentikasi pengguna via LDAP dan mendapatkan JWT Bearer token untuk mengakses API. + +## Business Rule + +- Username dan password divalidasi ke Active Directory (`10.100.1.40`) +- Hanya user yang terdaftar di group `Domain Admins`, `Administrators`, atau `Enterprise Admins` yang mendapat `is_admin: true` +- JWT diterbitkan dengan TTL dari `API_LDAP_JWT_TTL` (default: 3600 detik) +- Setiap percobaan login (berhasil maupun gagal) dicatat di audit log +- Maksimum 10 percobaan login per menit per IP + +## URL + +`POST https://console.gisportal.id/api/v1/auth/login` + +## HTTP Method + +`POST` + +## Authentication + +Tidak diperlukan. + +## Request Header + +``` +Content-Type: application/json +``` + +## Request Body + +```json +{ + "username": "john.doe", + "password": "Password123!" +} +``` + +## Validation + +| Field | Aturan | +|-------|--------| +| `username` | required, string, max 100 karakter | +| `password` | required, string, max 255 karakter | + +## Response Success + +**HTTP 200** + +```json +{ + "data": { + "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huLmRvZSIsImlzX2FkbWluIjp0cnVlLCJleHAiOjE3MTk1MDAwMDB9.signature", + "token_type": "Bearer", + "expires_in": 3600, + "auth_type": "ldap_jwt", + "user": { + "username": "john.doe", + "display_name": "John Doe", + "is_admin": true + } + } +} +``` + +## Response Error + +**HTTP 401 — Kredensial salah:** +```json +{ + "error": { + "code": "invalid_credentials", + "message": "Invalid LDAP credentials." + } +} +``` + +**HTTP 422 — Validasi gagal:** +```json +{ + "message": "The given data was invalid.", + "errors": { + "username": ["The username field is required."] + } +} +``` + +**HTTP 429 — Rate limit:** +```json +{ + "message": "Too Many Attempts." +} +``` + +## Status Code + +| Code | Kondisi | +|------|---------| +| 200 | Login berhasil | +| 401 | Kredensial LDAP salah | +| 422 | Validasi request gagal | +| 429 | Rate limit (10x/menit) | + +## Contoh Request + +```bash +curl -s -X POST https://console.gisportal.id/api/v1/auth/login \ + -H "Content-Type: application/json" \ + -d '{"username":"john.doe","password":"Password123!"}' +``` + +## Contoh Response + +```json +{ + "data": { + "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", + "token_type": "Bearer", + "expires_in": 3600, + "auth_type": "ldap_jwt", + "user": { + "username": "john.doe", + "display_name": "John Doe", + "is_admin": true + } + } +} +``` + +## Sequence Flow + +```mermaid +sequenceDiagram + Client->>API: POST /auth/login {username, password} + API->>LDAP: bind(username, password) + LDAP-->>API: success / failed + alt Login berhasil + API->>LDAP: lookup user groups + LDAP-->>API: group list + API->>API: issue JWT + API->>AuditLog: log api.v1.auth.login + API-->>Client: 200 {access_token, user} + else Login gagal + API->>AuditLog: log api.v1.auth.login.failed + API-->>Client: 401 invalid_credentials + end +``` + +## Database yang Diakses + +- LDAP (`10.100.1.40`) — read only untuk validasi +- `databaselist_audit` — write untuk audit log + +## Audit Log + +| Event | Kondisi | +|-------|---------| +| `api.v1.auth.login` | Login berhasil | +| `api.v1.auth.login.failed` | Login gagal | + +## Rate Limit + +10 request / menit per IP. Dikonfigurasi via Laravel throttle middleware `throttle:10,1`. + +## Idempotent + +Tidak — setiap request login menghasilkan JWT baru. + +## Retry Policy + +- Jika `401`: jangan retry otomatis. Minta user input ulang. +- Jika `429`: tunggu 60 detik. +- Jika `500`: retry max 2x dengan backoff 2s. + +## Security + +- Password tidak disimpan di geonet-console, divalidasi langsung ke LDAP +- JWT disign dengan `APP_KEY` Laravel +- Token dikirim hanya via HTTPS + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | Dokumentasi dibuat | diff --git a/server-connection/geonet-console/docapi/services/databases/README.md b/server-connection/geonet-console/docapi/services/databases/README.md new file mode 100644 index 0000000..dcb3bf8 --- /dev/null +++ b/server-connection/geonet-console/docapi/services/databases/README.md @@ -0,0 +1,41 @@ +# Databases Service + +## Deskripsi + +Registry dan monitoring database yang terdaftar di geonet-console (eks. databaselist). + +## Endpoint + +| Method | Path | Scope | Deskripsi | +|--------|------|-------|-----------| +| GET | `/databases` | `databases:read` | List semua database | +| POST | `/databases/{database}/offline` | `databases:write` | Tandai database offline | + +## Authentication + +``` +Authorization: Bearer +``` + +## Contoh Request + +```bash +# List databases +curl -s https://console.gisportal.id/api/v1/databases \ + -H "Authorization: Bearer " + +# Tandai offline +curl -s -X POST \ + https://console.gisportal.id/api/v1/databases/my-database/offline \ + -H "Authorization: Bearer " +``` + +## Database yang Digunakan + +- `databaselist_app` — tabel databases + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | README dibuat | diff --git a/server-connection/geonet-console/docapi/services/ldap/README.md b/server-connection/geonet-console/docapi/services/ldap/README.md new file mode 100644 index 0000000..ec6f9bb --- /dev/null +++ b/server-connection/geonet-console/docapi/services/ldap/README.md @@ -0,0 +1,49 @@ +# LDAP Service + +## Deskripsi + +Manajemen user dan group Active Directory via LDAP. Read dan write ke domain `gisportal.id`. + +## Dependency + +- LDAP Server: `10.100.1.40:389` +- Domain: `DC=gisportal,DC=id` +- Service account: `Administrator@gisportal.id` + +## Endpoint Users + +| Method | Path | Scope | Deskripsi | +|--------|------|-------|-----------| +| GET | `/ldap/users` | `ldap:read` | List semua user | +| GET | `/ldap/users/{username}` | `ldap:read` | Detail user | +| PUT | `/ldap/users/{username}` | `ldap:write` | Update user | +| POST | `/ldap/users/{username}/groups` | `ldap:write` | Tambah ke group | +| DELETE | `/ldap/users/{username}/groups/{group}` | `ldap:write` | Hapus dari group | + +## Endpoint Groups + +| Method | Path | Scope | Deskripsi | +|--------|------|-------|-----------| +| GET | `/ldap/groups` | `ldap:read` | List semua group | +| GET | `/ldap/groups/{group}` | `ldap:read` | Detail group | +| POST | `/ldap/groups` | `ldap:write` | Buat group baru | +| POST | `/ldap/groups/{group}/members` | `ldap:write` | Tambah member | +| DELETE | `/ldap/groups/{group}/members/{username}` | `ldap:write` | Hapus member | + +## Contoh Request + +```bash +# List users +curl -s https://console.gisportal.id/api/v1/ldap/users \ + -H "Authorization: Bearer " + +# List groups +curl -s https://console.gisportal.id/api/v1/ldap/groups \ + -H "Authorization: Bearer " +``` + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | README dibuat | diff --git a/server-connection/geonet-console/docapi/services/project-search/README.md b/server-connection/geonet-console/docapi/services/project-search/README.md new file mode 100644 index 0000000..13188ea --- /dev/null +++ b/server-connection/geonet-console/docapi/services/project-search/README.md @@ -0,0 +1,42 @@ +# Project Search Service + +## Deskripsi + +Natural language search untuk file project di NAS via Ollama (LLM) dan PostgreSQL vector index. + +**Status:** Diimplementasi sebagian. Endpoint tersedia tapi index NAS belum aktif di production. + +## Dependency + +- Ollama: `http://10.100.1.26:11434` (VM aiopr) +- Model chat: `qwen2.5:7b` +- Model embed: `nomic-embed-text` +- PostgreSQL Project Search: `geonet_project_search` (10.100.1.25) + +## Endpoint + +| Method | Path | Scope | Deskripsi | +|--------|------|-------|-----------| +| GET | `/project-search/sources` | `project-search:read` | Daftar sumber data | +| GET | `/project-search/index/status` | `project-search:read` | Status indeks per source | +| POST | `/project-search/ask` | `project-search:read` | Query natural language | + +## Rate Limit + +`POST /project-search/ask`: 20 request / menit + +## Contoh Request + +```bash +# Query +curl -s -X POST https://console.gisportal.id/api/v1/project-search/ask \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{"query": "Laporan survey jalan tol 2025", "sources": ["project"]}' +``` + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | README dibuat | diff --git a/server-connection/geonet-console/docapi/services/service-tokens/README.md b/server-connection/geonet-console/docapi/services/service-tokens/README.md new file mode 100644 index 0000000..b64728a --- /dev/null +++ b/server-connection/geonet-console/docapi/services/service-tokens/README.md @@ -0,0 +1,119 @@ +# Service Tokens + +## Deskripsi + +Centralized management untuk Bearer token yang digunakan oleh microservice (GeoNetAgent, dll.). + +Service Tokens adalah token sederhana berbasis SHA256 hash yang dikelola di geonet-console +sebagai single point of control, dengan sinkronisasi otomatis ke database microservice terkait. + +## Tanggung Jawab + +- Menerbitkan Bearer token baru untuk microservice +- Menyimpan hash token (plain text tidak pernah disimpan) +- Menyinkronkan token ke `geonetagent_dev.agent_tokens` via `AgentTokenSyncService` +- Revoke dan hapus token dengan sinkronisasi ke database microservice +- Mencatat seluruh aksi ke audit log + +## Dependency + +- `ServiceTokenService` — logika CRUD + audit +- `AgentTokenSyncService` — push ke `geonetagent_dev.agent_tokens` +- `AuditLogService` — audit trail +- PostgreSQL `databaselist_app` — tabel `service_tokens` +- PostgreSQL `geonetagent_dev` (10.100.1.25) — tabel `agent_tokens` (sync target) + +## URL Service + +`https://console.gisportal.id/api/v1/service-tokens` + +## Authentication + +Semua endpoint memerlukan autentikasi: +``` +Authorization: Bearer +``` + +## Endpoint + +| Method | Path | Deskripsi | Dokumen | +|--------|------|-----------|---------| +| GET | `/service-tokens` | List semua token | [list.md](./list.md) | +| POST | `/service-tokens` | Buat token baru | [create.md](./create.md) | +| GET | `/service-tokens/{id}` | Detail token | [show.md](./show.md) | +| POST | `/service-tokens/{id}/revoke` | Revoke token | [revoke.md](./revoke.md) | +| POST | `/service-tokens/{id}/regenerate` | Regenerate token | [regenerate.md](./regenerate.md) | +| DELETE | `/service-tokens/{id}` | Hapus permanen | [delete.md](./delete.md) | +| GET | `/service-tokens/by-service/{service}` | Filter by service | [by-service.md](./by-service.md) | +| GET | `/service-tokens/active` | Hanya token aktif | [active.md](./active.md) | +| GET | `/service-tokens/expired` | Hanya token expired | [expired.md](./expired.md) | + +## Database yang Digunakan + +### `service_tokens` (databaselist_app) + +| Kolom | Tipe | Keterangan | +|-------|------|------------| +| `id` | UUID | Primary key | +| `name` | varchar(100) | Nama token (e.g. "GeoNetAgent-Production") | +| `service` | varchar(50) | Nama service (e.g. "GeoNetAgent") | +| `token_prefix` | varchar(20) | 16 char pertama token (display only) | +| `token_hash` | varchar(64) | SHA256 hash token lengkap | +| `is_active` | boolean | Status aktif | +| `expires_at` | timestamptz | Waktu expiry (null = tidak pernah expire) | +| `created_by` | varchar(100) | Username yang membuat | +| `created_at` | timestamptz | Waktu dibuat | +| `last_used_at` | timestamptz | Terakhir digunakan (nullable) | + +### `agent_tokens` (geonetagent_dev — sync target) + +| Kolom | Tipe | Keterangan | +|-------|------|------------| +| `id` | UUID | Primary key | +| `name` | varchar(100) | Nama token | +| `token_hash` | varchar(128) | SHA256 hash | +| `is_active` | boolean | Status aktif | +| `last_used_at` | timestamptz | Terakhir digunakan | +| `created_at` | timestamptz | Waktu dibuat | + +## Sinkronisasi ke GeoNetAgent + +Saat token dibuat, direvoke, atau dihapus di geonet-console: + +``` +geonet-console (ServiceTokenService) + ↓ via AgentTokenSyncService + ↓ DB connection: geonetagent (config/database.php) + ↓ user: geonet_portal (INSERT, SELECT, UPDATE, DELETE) +geonetagent_dev.agent_tokens + ↓ +GeoNetAgent Collector (FastAPI) — validasi token incoming +``` + +**Fallback:** Jika `GEONETAGENT_DB_USERNAME` kosong di `.env`, sync di-skip dengan warning log. geonet-console tetap berjalan normal. + +## Token Security + +- Token plain text **hanya ditampilkan sekali** saat dibuat atau di-regenerate +- Database hanya menyimpan SHA256 hash — tidak reversible +- `token_prefix` (16 char pertama) digunakan untuk identifikasi di UI +- Jika token hilang → gunakan **Regenerate** + +## Audit Log + +| Event | Kondisi | +|-------|---------| +| `service_token_created` | Token baru dibuat | +| `service_token_revoked` | Token direvoke | +| `service_token_regenerated` | Token di-regenerate | +| `service_token_deleted` | Token dihapus permanen | + +## Service yang Memanggil + +- Admin via UI `/api-clients` +- AI Agent via API `POST /api/v1/service-tokens` + +## Service yang Dipanggil + +- `geonetagent_dev` PostgreSQL (sinkronisasi) +- `databaselist_audit` PostgreSQL (audit log) diff --git a/server-connection/geonet-console/docapi/services/service-tokens/active.md b/server-connection/geonet-console/docapi/services/service-tokens/active.md new file mode 100644 index 0000000..1e6537c --- /dev/null +++ b/server-connection/geonet-console/docapi/services/service-tokens/active.md @@ -0,0 +1,48 @@ +# Get Active Tokens + +## Tujuan + +Mendapatkan semua service token yang aktif dan belum expired. + +## URL + +`GET https://console.gisportal.id/api/v1/service-tokens/active` + +## HTTP Method + +`GET` + +## Response Success + +**HTTP 200** + +```json +{ + "data": [ + { + "id": "065eb796-ecb5-4d95-b4cd-9ca6244cf13f", + "name": "GeoNetAgent-Production", + "service": "GeoNetAgent", + "token_prefix": "Col5FUFl34dVXgyB", + "is_active": true, + "expires_at": null, + "created_by": "admin", + "created_at": "2026-06-23T08:54:04+07:00", + "last_used_at": null + } + ] +} +``` + +## Contoh Request + +```bash +curl -s https://console.gisportal.id/api/v1/service-tokens/active \ + -H "Authorization: Bearer " +``` + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | Endpoint dibuat | diff --git a/server-connection/geonet-console/docapi/services/service-tokens/by-service.md b/server-connection/geonet-console/docapi/services/service-tokens/by-service.md new file mode 100644 index 0000000..6fa8da9 --- /dev/null +++ b/server-connection/geonet-console/docapi/services/service-tokens/by-service.md @@ -0,0 +1,52 @@ +# Get Tokens by Service + +## Tujuan + +Filter semua token berdasarkan nama service. + +## URL + +`GET https://console.gisportal.id/api/v1/service-tokens/by-service/{service}` + +## Request Parameter + +| Parameter | Tipe | Keterangan | +|-----------|------|------------| +| `service` | string | Nama service (case-sensitive, e.g. "GeoNetAgent") | + +## Response Success + +**HTTP 200** + +```json +{ + "data": [ + { + "id": "065eb796-ecb5-4d95-b4cd-9ca6244cf13f", + "name": "GeoNetAgent-Production", + "service": "GeoNetAgent", + "token_prefix": "Col5FUFl34dVXgyB", + "is_active": true, + "expires_at": null, + "created_by": "admin", + "created_at": "2026-06-23T08:54:04+07:00", + "last_used_at": null, + "is_expired": false + } + ] +} +``` + +## Contoh Request + +```bash +curl -s \ + "https://console.gisportal.id/api/v1/service-tokens/by-service/GeoNetAgent" \ + -H "Authorization: Bearer " +``` + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | Endpoint dibuat | diff --git a/server-connection/geonet-console/docapi/services/service-tokens/create.md b/server-connection/geonet-console/docapi/services/service-tokens/create.md new file mode 100644 index 0000000..9cc233e --- /dev/null +++ b/server-connection/geonet-console/docapi/services/service-tokens/create.md @@ -0,0 +1,178 @@ +# Create Service Token + +## Tujuan + +Membuat Bearer token baru untuk microservice. Token plain text ditampilkan **sekali** — harus disimpan saat itu juga. + +## Business Rule + +- Token dihasilkan secara acak (cryptographically secure random) +- 16 karakter pertama disimpan sebagai `token_prefix` untuk identifikasi UI +- SHA256 hash dari token lengkap disimpan di database (plain text tidak pernah disimpan) +- Token otomatis disinkronkan ke `geonetagent_dev.agent_tokens` jika `GEONETAGENT_DB_USERNAME` di-set +- Setelah endpoint ini mengembalikan response, token plain text tidak bisa diambil lagi +- Jika token hilang → gunakan endpoint Regenerate + +## URL + +`POST https://console.gisportal.id/api/v1/service-tokens` + +## HTTP Method + +`POST` + +## Authentication + +``` +Authorization: Bearer +``` + +## Request Header + +``` +Content-Type: application/json +Authorization: Bearer +``` + +## Request Body + +```json +{ + "name": "GeoNetAgent-Production", + "service": "GeoNetAgent", + "expires_in_days": null +} +``` + +## Validation + +| Field | Aturan | +|-------|--------| +| `name` | required, string, max 100 karakter | +| `service` | required, string, max 50 karakter | +| `expires_in_days` | nullable, integer, min 1 | + +## Response Success + +**HTTP 201** + +```json +{ + "data": { + "id": "065eb796-ecb5-4d95-b4cd-9ca6244cf13f", + "name": "GeoNetAgent-Production", + "service": "GeoNetAgent", + "token_prefix": "Col5FUFl34dVXgyB", + "token": "Col5FUFl34dVXgyBgTSA23KsYc5QhAh8s224OkR5GjQ", + "is_active": true, + "expires_at": null, + "created_by": "admin", + "created_at": "2026-06-23T08:54:04+07:00" + }, + "message": "Service token created successfully. Save the token securely as it will not be shown again." +} +``` + +> **PENTING:** Field `token` hanya ada di response ini. Setelah request ini selesai, token tidak bisa diambil lagi. + +## Response Error + +**HTTP 422 — Validasi gagal:** +```json +{ + "message": "The given data was invalid.", + "errors": { + "name": ["The name field is required."], + "service": ["The service field is required."] + } +} +``` + +**HTTP 401 — Tidak terautentikasi:** +```json +{ + "error": { + "code": "UNAUTHENTICATED", + "message": "Unauthenticated." + } +} +``` + +## Status Code + +| Code | Kondisi | +|------|---------| +| 201 | Token berhasil dibuat | +| 401 | Tidak terautentikasi | +| 422 | Validasi request gagal | + +## Contoh Request + +```bash +curl -s -X POST https://console.gisportal.id/api/v1/service-tokens \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "name": "GeoNetAgent-Production", + "service": "GeoNetAgent", + "expires_in_days": null + }' +``` + +## Sequence Flow + +```mermaid +sequenceDiagram + Client->>API: POST /service-tokens {name, service} + API->>API: Generate random token + API->>API: Hash token (SHA256) + API->>DB(databaselist_app): INSERT service_tokens + API->>DB(geonetagent_dev): INSERT agent_tokens (sync) + API->>AuditLog: log service_token_created + API-->>Client: 201 {token (plain, sekali tampil), prefix, id} +``` + +## Database yang Diakses + +- `databaselist_app.service_tokens` — INSERT +- `geonetagent_dev.agent_tokens` — INSERT (sync, opsional) +- `databaselist_audit` — INSERT audit log + +## Audit Log + +Event: `service_token_created` +```json +{ + "action": "service_token_created", + "entity_type": "ServiceToken", + "entity_id": "065eb796-ecb5-4d95-b4cd-9ca6244cf13f", + "details": { + "name": "GeoNetAgent-Production", + "service": "GeoNetAgent", + "token_prefix": "Col5FUFl34dVXgyB", + "expires_at": null, + "agent_token_synced": true + } +} +``` + +## Security + +- Token hanya ditampilkan sekali — simpan segera +- Gunakan HTTPS — token tidak boleh dikirim via plain HTTP +- Simpan token di `.env` atau secret manager, bukan di source code + +## Idempotent + +Tidak — setiap request menghasilkan token baru yang berbeda. + +## Retry Policy + +- Jika `201` sudah diterima tapi token tidak sempat disimpan → jangan retry, gunakan Regenerate +- Jika `500`: retry max 1x. Cek apakah token sudah terbuat di database sebelum retry + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | Endpoint dibuat, sync ke geonetagent_dev diimplementasi | diff --git a/server-connection/geonet-console/docapi/services/service-tokens/delete.md b/server-connection/geonet-console/docapi/services/service-tokens/delete.md new file mode 100644 index 0000000..498863d --- /dev/null +++ b/server-connection/geonet-console/docapi/services/service-tokens/delete.md @@ -0,0 +1,58 @@ +# Delete Service Token + +## Tujuan + +Menghapus service token secara permanen dari database. Tidak bisa di-undo. + +## Business Rule + +- Record dihapus dari `service_tokens` (hard delete) +- Record dihapus dari `geonetagent_dev.agent_tokens` (sync) +- Gunakan **Revoke** jika ingin menonaktifkan tapi tetap menyimpan audit trail +- Gunakan **Delete** hanya jika token sudah tidak relevan sama sekali + +## URL + +`DELETE https://console.gisportal.id/api/v1/service-tokens/{id}` + +## HTTP Method + +`DELETE` + +## Request Parameter + +| Parameter | Tipe | Keterangan | +|-----------|------|------------| +| `id` | UUID | ID service token | + +## Response Success + +**HTTP 200** + +```json +{ + "message": "Service token deleted successfully" +} +``` + +## Contoh Request + +```bash +curl -s -X DELETE \ + https://console.gisportal.id/api/v1/service-tokens/065eb796-ecb5-4d95-b4cd-9ca6244cf13f \ + -H "Authorization: Bearer " +``` + +## Audit Log + +Event: `service_token_deleted` + +## Idempotent + +Tidak — menghapus ID yang tidak ada mengembalikan 404. + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | Endpoint dibuat | diff --git a/server-connection/geonet-console/docapi/services/service-tokens/expired.md b/server-connection/geonet-console/docapi/services/service-tokens/expired.md new file mode 100644 index 0000000..15c6ea0 --- /dev/null +++ b/server-connection/geonet-console/docapi/services/service-tokens/expired.md @@ -0,0 +1,48 @@ +# Get Expired Tokens + +## Tujuan + +Mendapatkan semua service token yang sudah melewati `expires_at`. + +## URL + +`GET https://console.gisportal.id/api/v1/service-tokens/expired` + +## HTTP Method + +`GET` + +## Response Success + +**HTTP 200** + +```json +{ + "data": [ + { + "id": "aabbccdd-1234-5678-abcd-ef1234567890", + "name": "OldToken-Staging", + "service": "GeoNetAgent", + "token_prefix": "AbCdEfGh12345678", + "is_active": false, + "expires_at": "2026-01-01T00:00:00+07:00", + "created_by": "admin", + "created_at": "2025-12-01T09:00:00+07:00", + "last_used_at": "2025-12-31T23:59:00+07:00" + } + ] +} +``` + +## Contoh Request + +```bash +curl -s https://console.gisportal.id/api/v1/service-tokens/expired \ + -H "Authorization: Bearer " +``` + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | Endpoint dibuat | diff --git a/server-connection/geonet-console/docapi/services/service-tokens/list.md b/server-connection/geonet-console/docapi/services/service-tokens/list.md new file mode 100644 index 0000000..c8d3e12 --- /dev/null +++ b/server-connection/geonet-console/docapi/services/service-tokens/list.md @@ -0,0 +1,57 @@ +# List Service Tokens + +## Tujuan + +Mendapatkan daftar semua service tokens (aktif, revoked, dan expired). + +## URL + +`GET https://console.gisportal.id/api/v1/service-tokens` + +## HTTP Method + +`GET` + +## Authentication + +``` +Authorization: Bearer +``` + +## Response Success + +**HTTP 200** + +```json +{ + "data": [ + { + "id": "065eb796-ecb5-4d95-b4cd-9ca6244cf13f", + "name": "GeoNetAgent-Production", + "service": "GeoNetAgent", + "token_prefix": "Col5FUFl34dVXgyB", + "is_active": true, + "expires_at": null, + "created_by": "admin", + "created_at": "2026-06-23T08:54:04+07:00", + "last_used_at": null, + "is_expired": false + } + ] +} +``` + +> **Catatan:** Field `token` (plain text) **tidak tersedia** di endpoint ini. Token plain hanya tersedia saat create/regenerate. + +## Contoh Request + +```bash +curl -s https://console.gisportal.id/api/v1/service-tokens \ + -H "Authorization: Bearer " +``` + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | Endpoint dibuat | diff --git a/server-connection/geonet-console/docapi/services/service-tokens/regenerate.md b/server-connection/geonet-console/docapi/services/service-tokens/regenerate.md new file mode 100644 index 0000000..22f17db --- /dev/null +++ b/server-connection/geonet-console/docapi/services/service-tokens/regenerate.md @@ -0,0 +1,136 @@ +# Regenerate Service Token + +## Tujuan + +Membuat token baru untuk service token yang sudah ada. Token lama langsung direvoke. Digunakan saat token hilang, bocor, atau perlu dirotasi. + +## Business Rule + +- Token lama direvoke terlebih dahulu (is_active = false) +- Token baru dibuat dengan name dan service yang sama +- Token baru disinkronkan ke `geonetagent_dev.agent_tokens` +- Token lama di-revoke di `geonetagent_dev.agent_tokens` +- **Downtime window:** antara revoke token lama dan distribusi token baru ke microservice +- Token plain text ditampilkan **sekali** — harus disimpan saat itu juga + +## URL + +`POST https://console.gisportal.id/api/v1/service-tokens/{id}/regenerate` + +## HTTP Method + +`POST` + +## Authentication + +``` +Authorization: Bearer +``` + +## Request Parameter + +| Parameter | Tipe | Keterangan | +|-----------|------|------------| +| `id` | UUID | ID service token yang akan di-regenerate | + +## Request Body (opsional) + +```json +{ + "expires_in_days": 90 +} +``` + +Jika tidak disertakan, token baru tidak expire (null). + +## Response Success + +**HTTP 200** + +```json +{ + "data": { + "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "name": "GeoNetAgent-Production", + "service": "GeoNetAgent", + "token_prefix": "Xk9mPqR2nLvWsJhY", + "token": "Xk9mPqR2nLvWsJhYaB7cDeFgHiJkLmNoPqRsTuVwXyZ", + "is_active": true, + "expires_at": null, + "created_by": "admin", + "created_at": "2026-06-23T10:00:00+07:00" + }, + "message": "Service token regenerated successfully. Save the new token securely as it will not be shown again." +} +``` + +## Response Error + +**HTTP 404:** +```json +{ + "error": { + "code": "NOT_FOUND", + "message": "Service token not found" + } +} +``` + +## Status Code + +| Code | Kondisi | +|------|---------| +| 200 | Token berhasil di-regenerate | +| 401 | Tidak terautentikasi | +| 404 | Token ID tidak ditemukan | + +## Contoh Request + +```bash +curl -s -X POST \ + https://console.gisportal.id/api/v1/service-tokens/065eb796-ecb5-4d95-b4cd-9ca6244cf13f/regenerate \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" +``` + +## Sequence Flow + +```mermaid +sequenceDiagram + Client->>API: POST /service-tokens/{id}/regenerate + API->>DB(databaselist_app): Ambil token lama + API->>DB(databaselist_app): Revoke token lama (is_active=false) + API->>DB(geonetagent_dev): Revoke di agent_tokens (sync) + API->>API: Generate token baru + API->>DB(databaselist_app): INSERT service_tokens baru + API->>DB(geonetagent_dev): INSERT agent_tokens baru (sync) + API->>AuditLog: log service_token_regenerated + API-->>Client: 200 {token_baru (sekali tampil)} +``` + +## Dampak ke Microservice GeoNetAgent + +Setelah regenerate, agent yang masih menggunakan token lama akan mendapat **401** dari collector. + +**Langkah yang diperlukan:** +1. Copy token baru dari response +2. Update `config.json` di semua PC client agent: + ```json + { "agent_token": "" } + ``` +3. Distribusikan via GPO atau manual +4. Agent akan menggunakan token baru pada posting berikutnya + +## Audit Log + +Event: `service_token_regenerated` + +## Idempotent + +Tidak — setiap regenerate menghasilkan token baru. + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | Endpoint dibuat | diff --git a/server-connection/geonet-console/docapi/services/service-tokens/revoke.md b/server-connection/geonet-console/docapi/services/service-tokens/revoke.md new file mode 100644 index 0000000..98694a3 --- /dev/null +++ b/server-connection/geonet-console/docapi/services/service-tokens/revoke.md @@ -0,0 +1,90 @@ +# Revoke Service Token + +## Tujuan + +Menonaktifkan service token tanpa menghapusnya. Token yang direvoke tetap tercatat di database untuk audit trail. + +## Business Rule + +- `is_active` diset ke `false` +- Token yang direvoke tidak bisa digunakan oleh microservice +- Sinkronisasi ke `geonetagent_dev.agent_tokens` — `is_active = false` +- Token masih dapat dilihat di daftar (dengan status "Revoked") +- Untuk menghapus permanen gunakan endpoint Delete + +## URL + +`POST https://console.gisportal.id/api/v1/service-tokens/{id}/revoke` + +## HTTP Method + +`POST` + +## Authentication + +``` +Authorization: Bearer +``` + +## Request Parameter + +| Parameter | Tipe | Keterangan | +|-----------|------|------------| +| `id` | UUID | ID service token | + +## Response Success + +**HTTP 200** + +```json +{ + "message": "Service token revoked successfully" +} +``` + +## Response Error + +**HTTP 404:** +```json +{ + "error": { + "code": "NOT_FOUND", + "message": "Service token not found" + } +} +``` + +## Status Code + +| Code | Kondisi | +|------|---------| +| 200 | Token berhasil direvoke | +| 401 | Tidak terautentikasi | +| 404 | Token ID tidak ditemukan | + +## Contoh Request + +```bash +curl -s -X POST \ + https://console.gisportal.id/api/v1/service-tokens/065eb796-ecb5-4d95-b4cd-9ca6244cf13f/revoke \ + -H "Authorization: Bearer " +``` + +## Dampak Langsung + +- GeoNetAgent yang menggunakan token ini akan mendapat **401** dari collector pada posting berikutnya +- Tidak ada cara undo revoke — gunakan Regenerate untuk buat token baru + +## Audit Log + +Event: `service_token_revoked` + +## Idempotent + +Ya — merevoke token yang sudah direvoke tidak menghasilkan error. + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | Endpoint dibuat | diff --git a/server-connection/geonet-console/docapi/services/service-tokens/show.md b/server-connection/geonet-console/docapi/services/service-tokens/show.md new file mode 100644 index 0000000..36feb3b --- /dev/null +++ b/server-connection/geonet-console/docapi/services/service-tokens/show.md @@ -0,0 +1,66 @@ +# Get Service Token Detail + +## Tujuan + +Mendapatkan detail satu service token berdasarkan ID. + +## URL + +`GET https://console.gisportal.id/api/v1/service-tokens/{id}` + +## HTTP Method + +`GET` + +## Request Parameter + +| Parameter | Tipe | Keterangan | +|-----------|------|------------| +| `id` | UUID | ID service token | + +## Response Success + +**HTTP 200** + +```json +{ + "data": { + "id": "065eb796-ecb5-4d95-b4cd-9ca6244cf13f", + "name": "GeoNetAgent-Production", + "service": "GeoNetAgent", + "token_prefix": "Col5FUFl34dVXgyB", + "is_active": true, + "expires_at": null, + "created_by": "admin", + "created_at": "2026-06-23T08:54:04+07:00", + "last_used_at": null, + "is_expired": false + } +} +``` + +## Response Error + +**HTTP 404:** +```json +{ + "error": { + "code": "NOT_FOUND", + "message": "Service token not found" + } +} +``` + +## Contoh Request + +```bash +curl -s \ + https://console.gisportal.id/api/v1/service-tokens/065eb796-ecb5-4d95-b4cd-9ca6244cf13f \ + -H "Authorization: Bearer " +``` + +## Changelog + +| Tanggal | Perubahan | +|---------|-----------| +| 2026-06-23 | Endpoint dibuat |