Anggota workspace
Sebuah workspace dibagikan kepada admin lain melalui baris keanggotaan. Setiap anggota memegang tepat satu role, dan role itu menentukan apa yang boleh dilakukan setiap rute workspace. Rute ini membaca daftar anggota dan mengubahnya.
Semua rute memerlukan header API key yang dikonfigurasi dan header principal tepercaya (X-User-Subject, plus klaim role/unit/level opsional) seperti rute lain yang membawa principal; lihat Percakapan dan memori. Pemanggil yang bukan anggota workspace mendapat 404 di setiap rute di bawah, jawaban yang sama dengan id workspace yang tidak dikenal.
Role workspace
owner, partner, dan viewer adalah role workspace — kedudukan seseorang di dalam satu workspace. Ini bukan hal yang sama dengan partner, yaitu organisasi pengintegrasi yang mengunggah dokumen lewat Kafka. Admin yang sama bisa menjadi owner di satu workspace dan viewer di workspace lain, dan keanggotaan dalam organisasi pengintegrasi tidak dengan sendirinya memberikan role workspace.
Rute menegakkan role dengan satu pemeriksaan bersama, WorkspaceAccess.require(...) di src/aceh_rag/api/workspaces.py:327, yang menjawab 403 dengan {"detail": "This action requires one of: <roles>"}. Izin di bawah dibaca dari pemanggilan tersebut, bukan dari niat produk.
| Kemampuan | owner | partner | viewer | Pemeriksaan kode |
|---|---|---|---|---|
| Membaca workspace, sources, dokumen, artifact, dan daftar anggota | Ya | Ya | Ya | Hanya _access(), tanpa require: sources GET workspaces.py:584, dokumen :922, artifact :977, konten artifact :1004, anggota :1094 |
| Mengunggah dokumen, mengganti dokumen | Ya | Ya | Tidak | access.require(OWNER, PARTNER): unggah :850, ganti :884 |
| Menyimpan kumpulan sumber, memilih atau membatalkan satu dokumen | Ya | Ya | Tidak | access.require(OWNER, PARTNER): simpan :625, pilih :683, batal pilih :717 |
| Menghapus unggahan workspace | Ya | Ya | Tidak | access.require(OWNER, PARTNER): :756 |
| Menghapus artifact | Semua | Hanya buatannya sendiri | Tidak | :1063, plus pemeriksaan artifact milik sendiri di :1064 |
| Mengganti nama atau menghapus workspace | Ya | Tidak | Tidak | access.require(OWNER): :501, :528 |
| Mengundang anggota, mengubah role anggota | Ya | Tidak | Tidak | access.require(OWNER): :1122 |
| Mengeluarkan anggota lain | Ya | Tidak | Tidak | access.require(OWNER): :1169 |
| Keluar dari workspace (keluarkan diri sendiri) | Serahkan kepemilikan dahulu | Ya | Ya | :1168 — pengeluaran diri sendiri melewati pemeriksaan owner; pemeriksaan owner terakhir di :1174 mengembalikan 422 |
| Menyerahkan kepemilikan | Ya | Tidak | Tidak | access.require(OWNER): :1208 |
Viewer boleh membaca dan mengeluarkan dirinya sendiri. Penulisan lain memerlukan owner atau partner dan menjawab 403 dengan This action requires one of: owner, partner bila ditolak; penulisan administratif memerlukan owner dan menjawab 403 dengan This action requires one of: owner. Partner hanya boleh menghapus artifact buatannya sendiri. Owner harus menyerahkan kepemilikan sebelum keluar.
Sebuah workspace selalu punya tepat satu owner. Repository menolak owner kedua (WorkspaceOwnerExistsError) dan menolak workspace tanpa owner (LastWorkspaceOwnerError); keduanya muncul sebagai 422 di bawah.
Objek anggota
GET /workspaces/{workspace_id}/members dan dua rute yang mengembalikan anggota memakai satu bentuk yang sama:
| Field | Tipe | Makna |
|---|---|---|
admin_id | string (UUID) | Subject admin anggota tersebut, sebagaimana dikirim di X-User-Subject. |
role | string | owner, partner, atau viewer. |
invited_by | string atau null | Subject admin yang menambahkannya; null bila baris itu tidak menyimpan pencatat undangan. |
GET /workspaces/{workspace_id}/members
Mengembalikan semua anggota, owner lebih dulu, lalu menurut urutan undangan. Semua anggota, termasuk viewer, boleh memanggilnya: viewer sudah dapat melihat setiap jawaban dan dokumen di workspace, jadi menyembunyikan daftar anggota tidak melindungi apa pun.
{
"members": [
{"admin_id": "0f2b0000-0000-4000-8000-000000000001", "role": "owner", "invited_by": null},
{"admin_id": "0f2b0000-0000-4000-8000-000000000002", "role": "partner", "invited_by": "0f2b0000-0000-4000-8000-000000000001"}
]
}
| Status | Detail | Kapan |
|---|---|---|
200 | Daftar anggota | Pemanggil adalah anggota. |
401 | {"detail": "Invalid or missing API key"} | Header API key tidak ada atau salah. |
401 | {"detail": "Authenticated principal required"} | Penegakan principal aktif dan identitas tidak ada. |
401 | {"detail": "Invalid authenticated principal"} | Penegakan principal aktif dan resolusi identitas gagal, atau subject principal yang dihasilkan bukan UUID, terlepas dari pengaturan penegakan principal. |
404 | {"detail": "Workspace not found"} | Id workspace tidak dikenal, atau pemanggil bukan anggota. Keduanya sengaja tidak dibedakan. |
422 | Array validasi (detail) dengan msg: "Value error, workspace_id must be a valid UUID" | workspace_id bukan UUID. |
POST /workspaces/{workspace_id}/members
Mengundang admin, atau mengubah role anggota yang sudah ada — panggilan yang sama. Mengundang orang yang sudah hadir adalah perubahan role, bukan error, sehingga klien tidak perlu tahu verb mana yang berlaku sebelum pengguna bertindak. Hanya owner.
{"admin_id": "0f2b0000-0000-4000-8000-000000000002", "role": "partner"}
Field extra ditolak dengan 422. admin_id harus UUID dan role harus salah satu dari tiga nilai enum.
| Status | Detail | Kapan |
|---|---|---|
200 | Objek anggota | Undangan atau perubahan role diterapkan. |
401 | {"detail": "Invalid or missing API key"} | Header API key tidak ada atau salah. |
401 | {"detail": "Authenticated principal required"} | Penegakan principal aktif dan identitas tidak ada. |
401 | {"detail": "Invalid authenticated principal"} | Penegakan principal aktif dan resolusi identitas gagal, atau subject principal yang dihasilkan bukan UUID, terlepas dari pengaturan penegakan principal. |
403 | {"detail": "This action requires one of: owner"} | Pemanggil adalah partner atau viewer. Tidak ada yang berubah. |
404 | {"detail": "Workspace not found"} | Id workspace tidak dikenal, atau pemanggil bukan anggota. |
422 | Array validasi | workspace_id atau admin_id bukan UUID, admin_id atau role tidak ada, role tidak dikenal, atau ada field tambahan terlarang. |
422 | {"detail": "This workspace already has an owner. Transfer ownership instead of inviting a second one."} | Request mencoba menjadikan orang lain owner. Gunakan PUT …/owner. |
422 | {"detail": "A workspace must always have an owner."} | Request menurunkan satu-satunya owner. |
Mengubah role bukan cara menyerahkan workspace: slot owner hanya berpindah melalui rute transfer.
DELETE /workspaces/{workspace_id}/members/{admin_id}
Mengeluarkan anggota. Owner boleh mengeluarkan siapa pun; setiap anggota boleh mengeluarkan dirinya sendiri, sehingga viewer yang tidak lagi ingin workspace itu ada di daftarnya tidak perlu meminta owner. Sukses mengembalikan 204 tanpa body.
| Status | Detail | Kapan |
|---|---|---|
204 | Body kosong | Baris anggota dihapus. |
401 | {"detail": "Invalid or missing API key"} | Header API key tidak ada atau salah. |
401 | {"detail": "Authenticated principal required"} | Penegakan principal aktif dan identitas tidak ada. |
401 | {"detail": "Invalid authenticated principal"} | Penegakan principal aktif dan resolusi identitas gagal, atau subject principal yang dihasilkan bukan UUID, terlepas dari pengaturan penegakan principal. |
403 | {"detail": "This action requires one of: owner"} | Pemanggil bukan owner dan admin_id bukan subject pemanggil sendiri. Tidak ada yang berubah. |
404 | {"detail": "Workspace not found"} | Id workspace tidak dikenal, atau pemanggil bukan anggota. |
404 | {"detail": "Member not found"} | Pemanggil boleh mengeluarkan id tersebut, tetapi tidak ada anggota seperti itu di sini. Tidak ada yang berubah. |
422 | Array validasi | workspace_id atau admin_id bukan UUID. |
422 | {"detail": "A workspace must always have an owner. Transfer ownership before leaving."} | Owner mencoba mengeluarkan dirinya sendiri saat ia satu-satunya owner. |
PUT /workspaces/{workspace_id}/owner
Menyerahkan workspace kepada admin lain secara atomik. PUT pada sub-resource tunggal, karena sebuah workspace punya tepat satu owner dan panggilan ini menyebut siapa orangnya. Hanya owner.
{"admin_id": "0f2b0000-0000-4000-8000-000000000002"}
Owner lama menjadi partner: ia tetap bekerja di workspace yang ia jalankan dan hanya kehilangan administrasi. Target menjadi owner; bila target belum menjadi anggota, barisnya dibuat, sehingga transfer juga bisa menjadi undangan pertama. Pemanggil tetap memiliki akses sebagai partner. Field extra ditolak dengan 422, dan admin_id harus UUID.
| Status | Detail | Kapan |
|---|---|---|
200 | Objek anggota | Owner baru, dengan role: "owner". |
401 | {"detail": "Invalid or missing API key"} | Header API key tidak ada atau salah. |
401 | {"detail": "Authenticated principal required"} | Penegakan principal aktif dan identitas tidak ada. |
401 | {"detail": "Invalid authenticated principal"} | Penegakan principal aktif dan resolusi identitas gagal, atau subject principal yang dihasilkan bukan UUID, terlepas dari pengaturan penegakan principal. |
403 | {"detail": "This action requires one of: owner"} | Pemanggil adalah partner atau viewer. Tidak ada yang berubah. |
404 | {"detail": "Workspace not found"} | Id workspace tidak dikenal, atau pemanggil bukan anggota. |
422 | Array validasi | workspace_id atau admin_id bukan UUID, admin_id tidak ada, atau ada field tambahan terlarang. |
Menyerahkan kepada owner saat ini tidak mengubah apa pun dan mengembalikan barisnya. Kepemilikan tidak pernah dikosongkan: transfer menurunkan owner lama, bukan meninggalkan workspace tanpa owner.