# Frontend API Contract Dokumen ini merangkum endpoint Orchestration Agent Service yang dipakai oleh frontend. Fokus flow: 1. User login dan menyimpan token. 2. User menyiapkan knowledge source: upload/proses file, connect database, ingest schema, dan rebuild data catalog. 3. Setelah knowledge siap, user membuat `new analysis` dengan judul, objective, business question, dan data source binding. 4. Frontend mengirim pertanyaan ke AI Agent Service terpisah. 5. Service ini hanya merekam riwayat tanya jawab ke `analyses_messages`. Base URL lokal contoh: `http://localhost:8080` ## Konvensi Semua endpoint protected wajib memakai: ```http Authorization: Bearer ``` Endpoint public: - `GET /health` - `POST /api/login` - `POST /api/refresh` Sebagian besar response memakai envelope: ```json { "status": "success", "message": "human-readable message", "data": {} } ``` Error response: ```json { "status": "error", "message": "error message", "data": { "code": "OPTIONAL_ERROR_CODE" } } ``` Catatan ownership: beberapa endpoint masih menerima `user_id` di body, path, atau query untuk kompatibilitas. Nilainya wajib sama dengan user dari Bearer token. ## Flow Frontend ### 1. Login Frontend memanggil `POST /api/login`, lalu simpan: - `data.user.id` sebagai `user_id` - `data.access_token` untuk header Bearer - `data.refresh_token` untuk refresh token rotation `access_token` berlaku 1 jam. `refresh_token` berlaku 7 hari dan akan diganti setiap kali refresh sukses. ### 2. Refresh Token Jika request protected menerima `401` karena token expired, panggil `POST /api/refresh` menggunakan refresh token terakhir. Setelah sukses, ganti access token dan refresh token lama dengan token baru dari response. Refresh token lama tidak boleh dipakai lagi setelah refresh sukses. ### 3. Menyiapkan Knowledge Source Frontend dapat menyediakan knowledge source dari dokumen dan/atau database. Untuk dokumen: 1. Ambil tipe file yang didukung: `GET /api/v1/documents/doctypes` 2. Upload file: `POST /api/v1/document/upload` 3. Proses dokumen: `POST /api/v1/document/process` 4. Pantau status dokumen: `GET /api/v1/documents/{user_id}` Untuk database: 1. Ambil tipe database dan schema form: `GET /api/v1/database-clients/dbtypes` 2. Simpan koneksi database: `POST /api/v1/database-clients` 3. Ingest schema database: `POST /api/v1/database-clients/{client_id}/ingest?user_id={user_id}` 4. Pantau koneksi: `GET /api/v1/database-clients/{user_id}` Setelah dokumen/database siap, frontend dapat rebuild dan membaca user data catalog: 1. `POST /api/v1/data-catalog/rebuild` 2. `GET /api/v1/data-catalog/{user_id}` ### 4. Membuat New Analysis Frontend menampilkan form: - `analysis_title` - `objective` - `business_questions` - `data_bind` `POST /api/v1/analyses` wajib menerima `analysis_title`, `objective`, `business_questions`, dan `data_bind`. `business_questions` berbentuk array string karena satu analysis dapat membawa lebih dari satu pertanyaan bisnis awal. Flow yang direkomendasikan: 1. `POST /api/v1/analyses` dengan title, objective, business_questions, dan data_bind. 2. Ambil `data.id` dari response sebagai `analysis_id`. 3. Frontend memanggil AI Agent Service terpisah memakai context analysis, business_questions, dan catalog. 4. Saat user mulai bertanya ke AI Agent Service, rekam pertanyaan dengan `role=user` ke endpoint messages. 5. Setelah AI Agent Service menjawab, simpan jawaban dengan `role=ai` ke endpoint messages. ### 5. Conversation Recording Endpoint message di service ini tidak memanggil AI agent, tidak melakukan reasoning, dan tidak membuat balasan otomatis. Frontend bertanggung jawab melakukan dua write terpisah: 1. Rekam pertanyaan user: ```json { "role": "user", "content": "Apa penyebab revenue turun di Q3?" } ``` 2. Setelah AI Agent Service menjawab, rekam jawaban agent: ```json { "role": "ai", "content": "Revenue Q3 turun terutama karena penurunan volume transaksi di segmen enterprise..." } ``` ## Endpoint Ringkas | Method | Path | Kegunaan | | --- | --- | --- | | `GET` | `/health` | Health check service | | `POST` | `/api/login` | Login dan issue token pair | | `POST` | `/api/refresh` | Rotate refresh token dan issue token pair baru | | `GET` | `/api/v1/documents/doctypes` | List tipe dokumen yang didukung | | `POST` | `/api/v1/document/upload` | Upload dokumen ke Azure Blob Storage | | `POST` | `/api/v1/document/upload-local` | Upload dokumen ke local filesystem untuk benchmark | | `POST` | `/api/v1/document/process` | Proses dokumen async | | `GET` | `/api/v1/documents/{user_id}` | List dokumen milik user | | `DELETE` | `/api/v1/document/delete` | Hapus dokumen | | `GET` | `/api/v1/database-clients/dbtypes` | List tipe database dan schema credential form | | `POST` | `/api/v1/database-clients` | Buat koneksi database | | `GET` | `/api/v1/database-clients/{user_id}` | List koneksi database user | | `GET` | `/api/v1/database-clients/{user_id}/{client_id}` | Detail koneksi database | | `PUT` | `/api/v1/database-clients/{client_id}` | Update koneksi database | | `DELETE` | `/api/v1/database-clients/{client_id}` | Hapus koneksi database | | `POST` | `/api/v1/database-clients/{client_id}/ingest` | Introspect schema database ke catalog | | `POST` | `/api/v1/data-catalog/rebuild` | Rebuild user data catalog | | `GET` | `/api/v1/data-catalog/{user_id}` | Ambil user data catalog index | | `POST` | `/api/v1/analyses` | Buat analysis baru | | `GET` | `/api/v1/analyses` | List analysis user | | `GET` | `/api/v1/analyses/{id}` | Detail analysis | | `PATCH` | `/api/v1/analyses/{id}` | Update metadata/status analysis | | `DELETE` | `/api/v1/analyses/{id}` | Hapus analysis | | `PUT` | `/api/v1/analyses/{id}/data-bind` | Update data source binding analysis | | `GET` | `/api/v1/analyses/{id}/data-catalog` | Ambil catalog yang scoped ke analysis | | `POST` | `/api/v1/analyses/{id}/data-catalog/rebuild` | Rebuild catalog scoped ke analysis dari data_bind | | `GET` | `/api/v1/analyses/{id}/messages` | Ambil riwayat pesan analysis | | `POST` | `/api/v1/analyses/{id}/messages` | Rekam satu pesan conversation | ## Auth ### `POST /api/login` Login user dengan email dan password. Request: ```json { "email": "user@example.com", "password": "password" } ``` Success `200`: ```json { "status": "success", "message": "login successful", "data": { "user": { "id": "user-id", "email": "user@example.com", "fullname": "User Name", "role": "user", "status": "active" }, "access_token": "jwt-access-token", "refresh_token": "opaque-refresh-token", "token_type": "Bearer", "expires_in": 3600, "refresh_expires_in": 604800 } } ``` Errors: `400`, `401`, `403`, `404`, `500`. ### `POST /api/refresh` Menukar refresh token aktif dengan token pair baru. Request: ```json { "refresh_token": "opaque-refresh-token" } ``` Success `200` mengembalikan bentuk `data` yang sama dengan login, berisi user, access token baru, refresh token baru, `token_type`, `expires_in`, dan `refresh_expires_in`. Errors: `400`, `401`, `403`, `500`. ## Documents ### Document Model ```json { "id": "document-id", "user_id": "user-id", "filename": "sales.csv", "blob_name": "user-id/document-id/sales.csv", "file_size": 2048, "file_type": "csv", "status": "uploaded", "chunks_count": 0, "processed_at": "2026-06-30T08:00:00Z", "error_message": null, "created_at": "2026-06-30T08:00:00Z" } ``` Status umum: `uploaded`, `processing`, `processed`, `failed`. ### `GET /api/v1/documents/doctypes` Mengambil tipe dokumen yang didukung. Success `200`: ```json { "status": "success", "message": "supported document types", "data": [ { "type": "pdf", "max_size_mb": 10, "status": "active", "message": null } ] } ``` ### `POST /api/v1/document/upload` Upload dokumen ke Azure Blob Storage. Maksimum 10 MB. Mendukung `pdf`, `docx`, `txt`, `csv`, dan `xlsx`. Content-Type: `multipart/form-data` Form fields: | Field | Required | Keterangan | | --- | --- | --- | | `user_id` | Yes | Harus sama dengan user dari token | | `file` | Yes | File dokumen | Success `201`: `data` berisi Document Model. Errors: `400`, `401`, `403`, `429`, `500`. ### `POST /api/v1/document/upload-local` Upload file ke filesystem lokal untuk benchmarking. Kontrak form sama dengan upload Azure. Success `201`: ```json { "status": "success", "message": "file saved locally", "data": { "path": "files/user-id/sales.csv" } } ``` ### `POST /api/v1/document/process` Memulai proses dokumen secara async. Untuk dokumen unstructured, service melakukan extract text dan embedding jika tersedia. Untuk dokumen tabular, service membuat parquet/catalog source. Request: ```json { "document_id": "document-id", "user_id": "user-id" } ``` Success `202`: ```json { "status": "success", "message": "document processing started", "data": { "document_id": "document-id", "file_type": "csv", "status": "processing" } } ``` Pantau hasilnya lewat `GET /api/v1/documents/{user_id}`. Errors: `400`, `401`, `403`, `404`, `500`. ### `GET /api/v1/documents/{user_id}` List dokumen milik user. Success `200`: ```json { "status": "success", "message": "documents", "data": [] } ``` Errors: `401`, `403`, `500`. ### `DELETE /api/v1/document/delete` Menghapus dokumen dari storage, embedding/parquet terkait, dan record database. Request: ```json { "document_id": "document-id", "user_id": "user-id" } ``` Success `200`: ```json { "status": "success", "message": "document deleted" } ``` Errors: `400`, `401`, `403`, `404`, `500`. ## Database Clients ### DB Client Model ```json { "id": "client-id", "user_id": "user-id", "name": "Analytics Warehouse", "db_type": "postgres", "status": "active", "created_at": "2026-06-30T08:00:00Z", "updated_at": "2026-06-30T08:00:00Z" } ``` ### `GET /api/v1/database-clients/dbtypes` Mengambil tipe database dan daftar field credential untuk render form dinamis. Saat ini `postgres` aktif; tipe lain dapat muncul sebagai `inactive`. ### `POST /api/v1/database-clients` Menyimpan koneksi database. Credentials disimpan terenkripsi. Jika koneksi dengan identity yang sama sudah ada, response `200` mengembalikan client existing. Request: ```json { "user_id": "user-id", "name": "Analytics Warehouse", "db_type": "postgres", "credentials": { "host": "db.example.com", "port": 5432, "database": "analytics", "username": "db_user", "password": "db_password", "ssl_mode": "require" } } ``` Success: - `201`: database client created - `200`: database client already exists Errors: `400`, `401`, `403`, `429`, `500`. ### `GET /api/v1/database-clients/{user_id}` List koneksi database milik user. Success `200`: ```json { "status": "success", "message": "database clients", "data": [] } ``` Errors: `401`, `403`, `500`. ### `GET /api/v1/database-clients/{user_id}/{client_id}` Ambil detail satu koneksi database. Success `200` dengan `data` berisi DB Client Model. Errors: `401`, `403`, `404`, `500`. ### `PUT /api/v1/database-clients/{client_id}?user_id={user_id}` Update nama, credentials, atau status koneksi. Semua field body optional, tetapi body harus JSON valid. Request: ```json { "name": "Updated Warehouse", "credentials": { "host": "db.example.com", "port": 5432, "database": "analytics", "username": "db_user", "password": "new_password", "ssl_mode": "require" }, "status": "active" } ``` Success `200`: `data` berisi DB Client Model. Errors: `400`, `401`, `403`, `404`, `500`. ### `DELETE /api/v1/database-clients/{client_id}?user_id={user_id}` Menghapus koneksi database dan memicu pembersihan catalog. Success `200`: ```json { "status": "success", "message": "database client deleted" } ``` Errors: `400`, `401`, `403`, `404`, `500`. ### `POST /api/v1/database-clients/{client_id}/ingest?user_id={user_id}` Melakukan introspection schema database dan menyimpan hasilnya ke catalog. Tidak membutuhkan request body. Success `200`: ```json { "status": "success", "message": "schema ingested", "data": { "tables": [] } } ``` Errors: `400`, `401`, `403`, `404`, `409`, `429`, `500`. ## Data Catalog ### `POST /api/v1/data-catalog/rebuild` Rebuild seluruh catalog user dari dokumen tabular dan database client aktif. Request: ```json { "user_id": "user-id" } ``` Success `200`: ```json { "status": "success", "message": "catalog rebuilt", "data": { "user_id": "user-id", "schema_version": "1.0", "generated_at": "2026-06-30T08:00:00Z", "sources": [] } } ``` Errors: `400`, `401`, `403`, `429`, `500`. ### `GET /api/v1/data-catalog/{user_id}` Mengambil index catalog user. Response `sources` berisi ringkasan source, tanpa detail table penuh. Success `200`: ```json { "status": "success", "message": "data catalog", "data": { "user_id": "user-id", "schema_version": "1.0", "generated_at": "2026-06-30T08:00:00Z", "sources": [ { "source_id": "document-or-client-id", "source_type": "tabular", "name": "sales.csv", "location_ref": "blob/path/or/db-ref", "table_count": 1, "updated_at": "2026-06-30T08:00:00Z" } ] } } ``` Errors: `401`, `403`, `500`. ### `POST /api/v1/analyses/{id}/data-catalog/rebuild` Membangun ulang catalog khusus analysis berdasarkan `data_bind` terbaru milik analysis tersebut. Endpoint ini hanya memakai source yang ter-bind ke analysis, bukan semua knowledge source user. Gunakan endpoint ini setelah perubahan binding jika frontend ingin memicu rebuild secara eksplisit. `PUT /api/v1/analyses/{id}/data-bind` juga melakukan rebuild analysis catalog sebagai bagian dari update binding. Tidak membutuhkan request body. Success `200`: ```json { "status": "success", "message": "analysis catalog rebuilt", "data": { "user_id": "user-id", "schema_version": "1.0", "generated_at": "2026-06-30T08:00:00Z", "sources": [] } } ``` Errors: `400`, `401`, `404`, `500`. ### `GET /api/v1/analyses/{id}/data-catalog` Mengambil catalog yang scoped ke analysis dan mengikuti `data_bind` analysis, bukan seluruh catalog user. Success `200`: ```json { "status": "success", "message": "analysis data catalog", "data": { "user_id": "user-id", "schema_version": "1.0", "generated_at": "2026-06-30T08:00:00Z", "sources": [] } } ``` Errors: `401`, `404`. ## Analyses ### Data Bind Item `data_bind` adalah daftar source yang dipilih user untuk analysis. ```json { "id": "source-id", "name": "sales.csv", "group_type": "document", "type": "csv" } ``` Field: | Field | Required | Keterangan | | --- | --- | --- | | `id` | Yes | `document.id` atau `database_client.id` | | `name` | Yes | Nama yang ditampilkan di UI | | `group_type` | Yes | `document` atau `database` | | `type` | Yes | File type (`csv`, `pdf`, `xlsx`) atau database type (`postgres`) | Rules: - `data_bind` wajib berisi minimal satu source. - Semua source harus milik user yang sedang login. - Duplicate source dalam satu `data_bind` ditolak. ### Analysis Model ```json { "id": "analysis-id", "user_id": "user-id", "analysis_title": "Q3 Revenue Analysis", "objective": "Find revenue movement and root cause", "business_questions": [ "Why did revenue drop in Q3?", "Which customer segment contributed the most to the change?" ], "status": "active", "data_bind": [ { "id": "document-id", "name": "sales.csv", "group_type": "document", "type": "csv" } ], "data_bind_version": 1, "report_collection": [], "created_at": "2026-06-30T08:00:00Z", "updated_at": "2026-06-30T08:00:00Z" } ``` ### `POST /api/v1/analyses` Membuat analysis aktif dengan source binding awal. Request: ```json { "analysis_title": "Q3 Revenue Analysis", "objective": "Find revenue movement and root cause", "business_questions": [ "Why did revenue drop in Q3?", "Which customer segment contributed the most to the change?" ], "data_bind": [ { "id": "document-id", "name": "sales.csv", "group_type": "document", "type": "csv" }, { "id": "database-client-id", "name": "Analytics Warehouse", "group_type": "database", "type": "postgres" } ] } ``` Success `201`: `data` berisi Analysis Model. Validation: - `business_questions` wajib berisi minimal satu string non-empty. - `data_bind` wajib berisi minimal satu source. Errors: `400`, `401`, `409`. ### `GET /api/v1/analyses` List analysis milik user. Query: | Query | Default | Keterangan | | --- | --- | --- | | `status` | `active` | `active` atau `inactive` | | `page` | `1` | Nomor halaman | | `limit` | `20` | Maksimum `100` | Success `200`: ```json { "status": "success", "message": "Analyses retrieved", "data": { "analyses": [], "pagination": { "page": 1, "limit": 20 } } } ``` Errors: `401`, `500`. ### `GET /api/v1/analyses/{id}` Ambil detail analysis milik user. Success `200` dengan `data` berisi Analysis Model. Errors: `400`, `401`, `404`. ### `PATCH /api/v1/analyses/{id}` Update metadata analysis. Field optional. Request: ```json { "analysis_title": "Updated title", "objective": "Updated objective", "status": "inactive" } ``` `status` hanya `active` atau `inactive`. Success `200`: `data` berisi Analysis Model. Errors: `400`, `401`, `404`. ### `DELETE /api/v1/analyses/{id}` Hapus analysis milik user. Success `204` tanpa response body. Errors: `400`, `401`, `404`. ### `PUT /api/v1/analyses/{id}/data-bind` Mengganti daftar source yang ter-bind ke analysis secara atomic dengan optimistic version check. Jika update berhasil, service juga rebuild catalog scope analysis dari `data_bind` terbaru. Jika rebuild catalog gagal, perubahan binding ditolak/rollback. Request: ```json { "expected_version": 1, "data_bind": [ { "id": "new-document-id", "name": "updated-sales.csv", "group_type": "document", "type": "csv" } ] } ``` Success `200`: `data` berisi Analysis Model dengan `data_bind_version` yang sudah naik. Errors: - `400`: payload invalid, empty binding, source invalid - `401`: token invalid/missing - `409`: stale `expected_version`, inactive analysis, atau limit violation ## Analysis Messages ### Message Model ```json { "id": "message-id", "analysis_id": "analysis-id", "user_id": "user-id", "role": "user", "content": "Apa penyebab revenue turun di Q3?", "created_at": "2026-06-30T08:00:00Z" } ``` `role` hanya: - `user`: pertanyaan atau instruksi dari user - `ai`: jawaban dari AI Agent Service ### `POST /api/v1/analyses/{id}/messages` Merekam tepat satu pesan conversation ke `analyses_messages`. Request untuk pertanyaan user: ```json { "role": "user", "content": "Apa penyebab revenue turun di Q3?" } ``` Request untuk jawaban AI: ```json { "role": "ai", "content": "Revenue turun karena penurunan transaksi enterprise dan kenaikan churn di wilayah barat." } ``` Success `201`: ```json { "status": "success", "message": "Message created", "data": { "message": { "id": "message-id", "analysis_id": "analysis-id", "user_id": "user-id", "role": "user", "content": "Apa penyebab revenue turun di Q3?", "created_at": "2026-06-30T08:00:00Z" } } } ``` Errors: - `400`: invalid role/content, invalid analysis ID - `401`: token invalid/missing - `409`: inactive analysis atau message limit tercapai ### `GET /api/v1/analyses/{id}/messages` Mengambil riwayat conversation analysis. Query: | Query | Default | Keterangan | | --- | --- | --- | | `limit` | `100` | Maksimum `100` | Success `200`: ```json { "status": "success", "message": "Messages retrieved", "data": { "messages": [] } } ``` Errors: `400`, `401`, `404`. ## Suggested Frontend Integration Sequence ### Login ```text POST /api/login store access_token, refresh_token, user.id ``` ### Upload and Process File ```text GET /api/v1/documents/doctypes POST /api/v1/document/upload POST /api/v1/document/process GET /api/v1/documents/{user_id} ``` ### Connect Database ```text GET /api/v1/database-clients/dbtypes POST /api/v1/database-clients POST /api/v1/database-clients/{client_id}/ingest?user_id={user_id} GET /api/v1/database-clients/{user_id} ``` ### Generate Knowledge Catalog ```text POST /api/v1/data-catalog/rebuild GET /api/v1/data-catalog/{user_id} ``` ### Create Analysis and Start Conversation ```text POST /api/v1/analyses with business_questions call AI Agent Service outside this service POST /api/v1/analyses/{analysis_id}/messages with role=user and content=user_question POST /api/v1/analyses/{analysis_id}/messages with role=ai and content=agent_answer GET /api/v1/analyses/{analysis_id}/messages ``` ## Important Frontend Notes - Jangan mengirim pesan user ke `POST /api/v1/analyses/{id}/messages` dengan ekspektasi service ini akan menjawab. Endpoint ini hanya persistence. - AI Agent Service adalah service terpisah. Service ini menyimpan metadata analysis, knowledge catalog, data binding, dan history conversation. - User-level catalog berisi seluruh knowledge source user; analysis-level catalog hanya berisi source yang ada di `data_bind` analysis. - Perubahan `data_bind` akan rebuild analysis-level catalog. Frontend juga dapat memanggil endpoint rebuild analysis catalog secara eksplisit jika diperlukan. - Setelah refresh token sukses, selalu replace refresh token lama dengan refresh token baru. - Untuk endpoint yang membutuhkan `user_id`, gunakan `data.user.id` dari login dan pastikan sama dengan token aktif. - Untuk binding analysis, pakai source yang sudah berhasil diupload/diproses atau database client yang sudah diingest.