Browse Source
- 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.master
21 changed files with 1829 additions and 0 deletions
@ -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> |
||||||
|
``` |
||||||
|
|
||||||
|
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 |
||||||
@ -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_<token_string> |
||||||
|
``` |
||||||
|
|
||||||
|
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 <token> |
||||||
|
↓ |
||||||
|
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 | |
||||||
@ -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 <token>` |
||||||
|
|
||||||
|
**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. |
||||||
@ -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 | |
||||||
@ -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) | |
||||||
@ -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 <access_token> |
||||||
|
↓ |
||||||
|
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 <token> |
||||||
|
↓ |
||||||
|
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 <service_token> |
||||||
|
↓ |
||||||
|
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": "<service_token_lengkap>" |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 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 <jwt_token>" |
||||||
|
|
||||||
|
# List service tokens (dengan API Token) |
||||||
|
curl -s https://console.gisportal.id/api/v1/service-tokens \ |
||||||
|
-H "Authorization: Bearer <api_token>" |
||||||
|
``` |
||||||
|
|
||||||
|
### 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(); |
||||||
|
``` |
||||||
@ -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 |
||||||
@ -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 | |
||||||
@ -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 <jwt_atau_api_token_dengan_scope_databases:read> |
||||||
|
``` |
||||||
|
|
||||||
|
## Contoh Request |
||||||
|
|
||||||
|
```bash |
||||||
|
# List databases |
||||||
|
curl -s https://console.gisportal.id/api/v1/databases \ |
||||||
|
-H "Authorization: Bearer <token>" |
||||||
|
|
||||||
|
# Tandai offline |
||||||
|
curl -s -X POST \ |
||||||
|
https://console.gisportal.id/api/v1/databases/my-database/offline \ |
||||||
|
-H "Authorization: Bearer <token>" |
||||||
|
``` |
||||||
|
|
||||||
|
## Database yang Digunakan |
||||||
|
|
||||||
|
- `databaselist_app` — tabel databases |
||||||
|
|
||||||
|
## Changelog |
||||||
|
|
||||||
|
| Tanggal | Perubahan | |
||||||
|
|---------|-----------| |
||||||
|
| 2026-06-23 | README dibuat | |
||||||
@ -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 <token_dengan_scope_ldap:read>" |
||||||
|
|
||||||
|
# List groups |
||||||
|
curl -s https://console.gisportal.id/api/v1/ldap/groups \ |
||||||
|
-H "Authorization: Bearer <token>" |
||||||
|
``` |
||||||
|
|
||||||
|
## Changelog |
||||||
|
|
||||||
|
| Tanggal | Perubahan | |
||||||
|
|---------|-----------| |
||||||
|
| 2026-06-23 | README dibuat | |
||||||
@ -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 <token_dengan_scope_project-search:read>" \ |
||||||
|
-H "Content-Type: application/json" \ |
||||||
|
-d '{"query": "Laporan survey jalan tol 2025", "sources": ["project"]}' |
||||||
|
``` |
||||||
|
|
||||||
|
## Changelog |
||||||
|
|
||||||
|
| Tanggal | Perubahan | |
||||||
|
|---------|-----------| |
||||||
|
| 2026-06-23 | README dibuat | |
||||||
@ -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 <jwt_token_atau_api_token> |
||||||
|
``` |
||||||
|
|
||||||
|
## 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) |
||||||
@ -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 <jwt_token>" |
||||||
|
``` |
||||||
|
|
||||||
|
## Changelog |
||||||
|
|
||||||
|
| Tanggal | Perubahan | |
||||||
|
|---------|-----------| |
||||||
|
| 2026-06-23 | Endpoint dibuat | |
||||||
@ -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 <jwt_token>" |
||||||
|
``` |
||||||
|
|
||||||
|
## Changelog |
||||||
|
|
||||||
|
| Tanggal | Perubahan | |
||||||
|
|---------|-----------| |
||||||
|
| 2026-06-23 | Endpoint dibuat | |
||||||
@ -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 <jwt_token_atau_api_token> |
||||||
|
``` |
||||||
|
|
||||||
|
## Request Header |
||||||
|
|
||||||
|
``` |
||||||
|
Content-Type: application/json |
||||||
|
Authorization: Bearer <token> |
||||||
|
``` |
||||||
|
|
||||||
|
## 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 <jwt_token>" \ |
||||||
|
-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 | |
||||||
@ -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 <jwt_token>" |
||||||
|
``` |
||||||
|
|
||||||
|
## Audit Log |
||||||
|
|
||||||
|
Event: `service_token_deleted` |
||||||
|
|
||||||
|
## Idempotent |
||||||
|
|
||||||
|
Tidak — menghapus ID yang tidak ada mengembalikan 404. |
||||||
|
|
||||||
|
## Changelog |
||||||
|
|
||||||
|
| Tanggal | Perubahan | |
||||||
|
|---------|-----------| |
||||||
|
| 2026-06-23 | Endpoint dibuat | |
||||||
@ -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 <jwt_token>" |
||||||
|
``` |
||||||
|
|
||||||
|
## Changelog |
||||||
|
|
||||||
|
| Tanggal | Perubahan | |
||||||
|
|---------|-----------| |
||||||
|
| 2026-06-23 | Endpoint dibuat | |
||||||
@ -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 <jwt_token_atau_api_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 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
> **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 <jwt_token>" |
||||||
|
``` |
||||||
|
|
||||||
|
## Changelog |
||||||
|
|
||||||
|
| Tanggal | Perubahan | |
||||||
|
|---------|-----------| |
||||||
|
| 2026-06-23 | Endpoint dibuat | |
||||||
@ -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 <jwt_token_atau_api_token> |
||||||
|
``` |
||||||
|
|
||||||
|
## 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 <jwt_token>" \ |
||||||
|
-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": "<token_baru>" } |
||||||
|
``` |
||||||
|
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 | |
||||||
@ -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 <jwt_token_atau_api_token> |
||||||
|
``` |
||||||
|
|
||||||
|
## 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 <jwt_token>" |
||||||
|
``` |
||||||
|
|
||||||
|
## 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 | |
||||||
@ -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 <jwt_token>" |
||||||
|
``` |
||||||
|
|
||||||
|
## Changelog |
||||||
|
|
||||||
|
| Tanggal | Perubahan | |
||||||
|
|---------|-----------| |
||||||
|
| 2026-06-23 | Endpoint dibuat | |
||||||
Loading…
Reference in new issue