{"openapi":"3.0.0","info":{"title":"Kamus Digital Sambas-Indonesia API","version":"1.0.0"},"components":{"schemas":{},"parameters":{}},"paths":{"/api/v1/ping":{"get":{"tags":["Misc"],"summary":"Canary CI/CD - verifikasi deploy (tanpa auth, tanpa DB)","responses":{"200":{"description":"Pong + info runtime yang melayani","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"pong":{"type":"boolean"},"time":{"type":"string"},"env":{"type":"string"},"runtime":{"type":"string","enum":["node","cloudflare-workers"]},"host":{"type":"string"}},"required":["pong","time","env","runtime","host"]}},"required":["success","data"]}}}}}}},"/api/v1/auth/register":{"post":{"tags":["Auth"],"summary":"Registrasi user baru (role default: contributor)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"email":{"type":"string","format":"email"},"phone":{"type":"string","maxLength":20},"password":{"type":"string","minLength":8,"pattern":"[a-zA-Z]"},"confirm_password":{"type":"string"}},"required":["name","email","password","confirm_password"]}}}},"responses":{"201":{"description":"Registrasi berhasil","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"user_id":{"type":"string"},"username":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string","nullable":true},"verification_required":{"type":"boolean","enum":[true]}},"required":["user_id","username","email","phone","verification_required"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Nama/email/HP sudah dipakai","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/login":{"post":{"tags":["Auth"],"summary":"Login - dapatkan access token + refresh token (httpOnly cookie)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"password":{"type":"string","minLength":1},"client_type":{"type":"string","enum":["web","mobile"],"default":"web"}},"required":["email","password"]}}}},"responses":{"200":{"description":"Login berhasil","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"access_token":{"type":"string"},"expires_in":{"type":"integer"},"refresh_token":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"username":{"type":"string"},"role":{"type":"string"},"avatar_url":{"type":"string","nullable":true,"format":"uri"}},"required":["id","username","role","avatar_url"]}},"required":["access_token","expires_in","user"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Email atau password salah","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Email belum diverifikasi OTP","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/google":{"post":{"tags":["Auth"],"summary":"Masuk dengan Google (ID token)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"id_token":{"type":"string","minLength":1},"client_type":{"type":"string","enum":["web","mobile"],"default":"web"}},"required":["id_token"]}}}},"responses":{"200":{"description":"Login berhasil","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"access_token":{"type":"string"},"expires_in":{"type":"integer"},"refresh_token":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"username":{"type":"string"},"role":{"type":"string"},"avatar_url":{"type":"string","nullable":true,"format":"uri"}},"required":["id","username","role","avatar_url"]}},"required":["access_token","expires_in","user"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"ID token Google tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Email sudah terdaftar tanpa identitas Google","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak percobaan (5/15 menit per IP)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"503":{"description":"GOOGLE_CLIENT_ID belum di-set","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/facebook":{"post":{"tags":["Auth"],"summary":"Masuk dengan Facebook (access token Graph)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string","minLength":1},"client_type":{"type":"string","enum":["web","mobile"],"default":"web"}},"required":["access_token"]}}}},"responses":{"200":{"description":"Login berhasil","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"access_token":{"type":"string"},"expires_in":{"type":"integer"},"refresh_token":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"username":{"type":"string"},"role":{"type":"string"},"avatar_url":{"type":"string","nullable":true,"format":"uri"}},"required":["id","username","role","avatar_url"]}},"required":["access_token","expires_in","user"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Access token Facebook tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Email sudah terdaftar tanpa identitas Facebook","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak percobaan (5/15 menit per IP)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"503":{"description":"FACEBOOK_APP_ID / FACEBOOK_APP_SECRET belum di-set","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/verify-email":{"post":{"tags":["Auth"],"summary":"Verifikasi email dengan OTP 8 karakter 0-9A-Z, lalu terbitkan JWT seperti login","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"code":{"type":"string","minLength":6,"maxLength":16},"client_type":{"type":"string","enum":["web","mobile"],"default":"web"}},"required":["email","code"]}}}},"responses":{"200":{"description":"Email terverifikasi + token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"access_token":{"type":"string"},"expires_in":{"type":"integer"},"refresh_token":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"username":{"type":"string"},"role":{"type":"string"},"avatar_url":{"type":"string","nullable":true,"format":"uri"}},"required":["id","username","role","avatar_url"]}},"required":["access_token","expires_in","user"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"OTP salah atau kadaluarsa","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak percobaan (5/15 menit per IP)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/resend-otp":{"post":{"tags":["Auth"],"summary":"Kirim ulang OTP (email tak dikenal tetap 200; cooldown 2 menit)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]}}}},"responses":{"200":{"description":"Kode baru dikirim jika email belum diverifikasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Kirim ulang terlalu cepat (1/2 menit per IP, dan 2 menit per email)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/refresh":{"post":{"tags":["Auth"],"summary":"Rotasi refresh token + access token baru (web: cookie, mobile: body)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"refresh_token":{"type":"string","minLength":1}},"default":{}}}}},"responses":{"200":{"description":"Access token baru","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"access_token":{"type":"string"},"expires_in":{"type":"integer"},"refresh_token":{"type":"string"}},"required":["access_token","expires_in"]}},"required":["success","data"]}}}},"401":{"description":"Refresh token tidak valid/kadaluarsa","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/logout":{"post":{"tags":["Auth"],"summary":"Logout - revoke refresh token perangkat ini (web: cookie, mobile: body)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"refresh_token":{"type":"string","minLength":1}},"default":{}}}}},"responses":{"200":{"description":"Logout berhasil","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}}}}},"/api/v1/auth/logout-all-devices":{"post":{"tags":["Auth"],"summary":"Logout semua perangkat - revoke semua refresh token user","responses":{"200":{"description":"Semua perangkat berhasil di-logout","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/forgot-password":{"post":{"tags":["Auth"],"summary":"Minta link reset password (response selalu sama, cegah enumeration)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]}}}},"responses":{"200":{"description":"Link reset dikirim jika email terdaftar","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/reset-password":{"post":{"tags":["Auth"],"summary":"Reset password pakai token dari email","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":1},"email":{"type":"string","format":"email"},"code":{"type":"string","minLength":1},"new_password":{"type":"string","minLength":8,"pattern":"[a-zA-Z]"}},"required":["new_password"]}}}},"responses":{"200":{"description":"Password berhasil direset","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token reset tidak valid/kadaluarsa","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/change-password":{"post":{"tags":["Auth"],"summary":"Ubah password sendiri (login) - semua session direvoke, wajib login ulang","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"old_password":{"type":"string","minLength":1},"new_password":{"type":"string","minLength":8,"pattern":"[a-zA-Z]"},"confirm_password":{"type":"string","minLength":1}},"required":["old_password","new_password","confirm_password"]}}}},"responses":{"200":{"description":"Password berhasil diubah","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid / akun OAuth-only / password baru sama dengan lama","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid atau password lama salah","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak percobaan (5/15 menit per user)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/providers":{"get":{"tags":["Auth"],"summary":"Daftar provider OAuth yang terhubung ke akun","responses":{"200":{"description":"Daftar provider","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"providers":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string"},"linked_at":{"type":"string"}},"required":["provider","linked_at"]}}},"required":["providers"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/google/link":{"post":{"tags":["Auth"],"summary":"Hubungkan akun Google ke user yang sedang login","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"id_token":{"type":"string","minLength":1}},"required":["id_token"]}}}},"responses":{"200":{"description":"Google terhubung","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"provider":{"type":"string","enum":["google"]},"linked_at":{"type":"string"}},"required":["provider","linked_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token sesi / ID token Google tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Google sudah terhubung ke akun lain","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"503":{"description":"GOOGLE_CLIENT_ID belum di-set","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"delete":{"tags":["Auth"],"summary":"Lepas tautan akun Google","responses":{"200":{"description":"Google dilepas","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Google belum terhubung","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Metode login terakhir - setel password dulu","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/account":{"delete":{"tags":["Auth"],"summary":"Hapus akun sendiri (soft delete + bersihkan data pribadi)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"confirmation":{"type":"string"},"password":{"type":"string"}},"required":["confirmation"]}}}},"responses":{"200":{"description":"Akun dihapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}},"required":["success","data"]}}}},"400":{"description":"Konfirmasi atau kata sandi tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Sesi tidak valid atau kata sandi salah","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/delete-account/request":{"post":{"tags":["Auth"],"summary":"Minta kode hapus akun lewat email (response selalu sama)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]}}}},"responses":{"200":{"description":"Kode dikirim jika email terdaftar","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/auth/delete-account/confirm":{"post":{"tags":["Auth"],"summary":"Hapus akun dengan kode email","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"code":{"type":"string","minLength":1},"confirmation":{"type":"string"}},"required":["email","code","confirmation"]}}}},"responses":{"200":{"description":"Akun dihapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Kode tidak valid atau kedaluwarsa","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words":{"get":{"tags":["Words","Admin"],"summary":"List kata panel admin - filter tayang (published true|false|all)","parameters":[{"schema":{"type":"string","maxLength":255,"default":""},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"required":false,"name":"word_type","in":"query"},{"schema":{"type":"boolean","nullable":true},"required":false,"name":"is_verified","in":"query"},{"schema":{"type":"boolean","nullable":true},"required":false,"name":"published","in":"query"}],"responses":{"200":{"description":"Daftar kata (cursor)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"language_id":{"type":"string"},"language_code":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"matched_translation":{"type":"string"},"matched_variant":{"type":"string"},"sense":{"type":"string","nullable":true}},"required":["id","lemma","language_id","language_code","word_type","status","is_verified"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"post":{"tags":["Words","Admin"],"summary":"Tambah kata baru lengkap dengan makna/terjemahan/contoh (transaksional)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"lemma":{"type":"string","minLength":1,"maxLength":255},"lemma_allows_comma":{"type":"boolean","default":false},"notes":{"type":"string"},"meanings":{"type":"array","items":{"type":"object","properties":{"word_class_id":{"type":"string","minLength":26,"maxLength":26},"definition":{"type":"string","minLength":1},"is_have_definition":{"type":"boolean","default":true},"is_have_translation":{"type":"boolean","default":true},"order_index":{"type":"integer","minimum":1,"default":1},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text"]},"default":[]},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]}},"required":["source_language_id","source_sentence"]}}},"required":["word_class_id","definition"]},"minItems":1},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"],"default":"word"},"usage_labels":{"type":"array","items":{"type":"string","enum":["kasar","tabu","informal","halus","seksual","diskriminatif"]},"default":[]},"category_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"default":[]},"related_words":{"type":"array","items":{"type":"object","properties":{"relation_type":{"type":"string","enum":["synonym","antonym","has_component","derived_from"]},"word_id":{"type":"string","minLength":26,"maxLength":26},"word":{"type":"object","properties":{"lemma":{"type":"string","minLength":1,"maxLength":255},"notes":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"],"default":"word"},"usage_labels":{"type":"array","items":{"type":"string","enum":["kasar","tabu","informal","halus","seksual","diskriminatif"]},"default":[]},"category_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"default":[]},"inherit_meanings":{"type":"boolean","default":true},"meaning_overrides":{"type":"array","items":{"type":"object","properties":{"meaning_index":{"type":"integer","nullable":true,"minimum":0},"definition":{"type":"string","minLength":1},"word_class_id":{"type":"string","minLength":26,"maxLength":26},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"}},"required":["language_id","translation_text"]}},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]}},"required":["source_language_id","source_sentence"]}}},"required":["meaning_index"]},"maxItems":20},"meanings":{"type":"array","items":{"type":"object","properties":{"word_class_id":{"type":"string","minLength":26,"maxLength":26},"definition":{"type":"string","minLength":1},"is_have_definition":{"type":"boolean","default":true},"is_have_translation":{"type":"boolean","default":true},"order_index":{"type":"integer","minimum":1,"default":1},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text"]},"default":[]},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]}},"required":["source_language_id","source_sentence"]}}},"required":["word_class_id","definition"]},"minItems":1},"variants":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string","minLength":1,"maxLength":255},"variant_type":{"type":"string","enum":["inflection","derivation","alternative","reduplication"],"default":"alternative"},"affix_type":{"type":"string","enum":["prefix","suffix","circumfix","reduplication"]},"affix_value":{"type":"string","maxLength":50},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"notes":{"type":"string","maxLength":1000}},"required":["form"]},"maxItems":20},"pronunciation":{"type":"object","properties":{"notation":{"type":"string","minLength":1,"default":"ipa"},"value":{"type":"string","minLength":1}},"required":["value"]},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1},"sha":{"type":"string","minLength":1,"maxLength":128},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean","default":false},"content_warnings":{"type":"array","items":{"type":"string","enum":["kekerasan"]},"default":[]}},"required":["url","provider_file_id"]},"maxItems":10},"status":{"type":"string","enum":["draft","published"]}},"required":["lemma"]}},"required":["relation_type"]},"default":[]},"variants":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string","minLength":1,"maxLength":255},"variant_type":{"type":"string","enum":["inflection","derivation","alternative","reduplication"],"default":"alternative"},"affix_type":{"type":"string","enum":["prefix","suffix","circumfix","reduplication"]},"affix_value":{"type":"string","maxLength":50},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"notes":{"type":"string","maxLength":1000}},"required":["form"]},"maxItems":20},"pronunciation":{"type":"object","properties":{"notation":{"type":"string","minLength":1,"default":"ipa"},"value":{"type":"string","minLength":1}},"required":["value"]},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1},"sha":{"type":"string","minLength":1,"maxLength":128},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean","default":false},"content_warnings":{"type":"array","items":{"type":"string","enum":["kekerasan"]},"default":[]}},"required":["url","provider_file_id"]},"maxItems":10},"search_miss_id":{"type":"string","minLength":26,"maxLength":26},"status":{"type":"string","enum":["draft","published"],"default":"draft"}},"required":["language_id","lemma","meanings"]}}}},"responses":{"201":{"description":"Kata tersimpan (status per role)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"created_at":{"type":"string"},"search_miss_id":{"type":"string","nullable":true},"warnings":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},"inline_created_words":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"relation_type":{"type":"string","enum":["synonym","antonym","has_component","derived_from"]},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"meanings_count":{"type":"integer"},"inherited_meanings_count":{"type":"integer"},"overridden_meanings_count":{"type":"integer"},"warnings":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["word_id","lemma","relation_type","word_type","status","is_verified","meanings_count","inherited_meanings_count","overridden_meanings_count"]}}},"required":["word_id","lemma","word_type","status","is_verified","created_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid / referensi id tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/import":{"post":{"tags":["Words","Admin"],"summary":"Impor kata dari CSV yang sudah dipratinjau (maksimal 5 kata)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["validate","commit"]},"items":{"type":"array","items":{"type":"object","properties":{"lemma":{"type":"string","minLength":1,"maxLength":255},"verify":{"type":"boolean","default":false},"verified":{"type":"boolean","default":false},"notes":{"type":"string","maxLength":2000},"meanings":{"type":"array","items":{"type":"object","properties":{"translation":{"type":"string","maxLength":500},"definition":{"type":"string","maxLength":2000},"example":{"type":"string","maxLength":500}}},"minItems":1,"maxItems":20}},"required":["lemma","meanings"]},"minItems":1,"maxItems":5}},"required":["mode","items"]}}}},"responses":{"200":{"description":"Hasil cek tanpa menulis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"lemma":{"type":"string"},"outcome":{"type":"string","enum":["created","meanings_added","skipped","invalid"]},"status":{"type":"string","enum":["draft","published"]},"is_verified":{"type":"boolean"},"meanings_added":{"type":"number"},"meanings_skipped":{"type":"number"},"message":{"type":"string"}},"required":["lemma","outcome","meanings_added","meanings_skipped"]}}},"required":["items"]}},"required":["success","data"]}}}},"201":{"description":"Kata atau makna tersimpan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"lemma":{"type":"string"},"outcome":{"type":"string","enum":["created","meanings_added","skipped","invalid"]},"status":{"type":"string","enum":["draft","published"]},"is_verified":{"type":"boolean"},"meanings_added":{"type":"number"},"meanings_skipped":{"type":"number"},"message":{"type":"string"}},"required":["lemma","outcome","meanings_added","meanings_skipped"]}}},"required":["items"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/import-sessions":{"post":{"tags":["Words","Admin"],"summary":"Simpan ringkasan sesi impor massal","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":26,"maxLength":26},"source_label":{"type":"string","nullable":true,"maxLength":500},"status":{"type":"string","enum":["running","completed","cancelled","failed"]},"total":{"type":"integer","minimum":0},"created_count":{"type":"integer","minimum":0},"duplicates_count":{"type":"integer","minimum":0},"meanings_added_count":{"type":"integer","minimum":0},"invalid_count":{"type":"integer","minimum":0},"items":{"type":"array","items":{"type":"object","properties":{"lemma":{"type":"string","minLength":1,"maxLength":255},"outcome":{"type":"string","enum":["created","meanings_added","skipped","invalid"]},"meanings_added":{"type":"integer","minimum":0},"message":{"type":"string","maxLength":2000}},"required":["lemma","outcome","meanings_added"]},"maxItems":5000}},"required":["id","status","total","created_count","duplicates_count","meanings_added_count","invalid_count","items"]}}}},"responses":{"201":{"description":"Sesi tersimpan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"triggered_by":{"type":"string"},"triggered_by_username":{"type":"string","nullable":true},"attributed_to":{"type":"string"},"attributed_to_username":{"type":"string","nullable":true},"source_label":{"type":"string","nullable":true},"status":{"type":"string","enum":["running","completed","cancelled","failed"]},"total":{"type":"number"},"created_count":{"type":"number"},"duplicates_count":{"type":"number"},"meanings_added_count":{"type":"number"},"invalid_count":{"type":"number"},"items":{"type":"array","items":{"type":"object","properties":{"lemma":{"type":"string","minLength":1,"maxLength":255},"outcome":{"type":"string","enum":["created","meanings_added","skipped","invalid"]},"meanings_added":{"type":"integer","minimum":0},"message":{"type":"string","maxLength":2000}},"required":["lemma","outcome","meanings_added"]}},"created_at":{"type":"string"},"finished_at":{"type":"string","nullable":true}},"required":["id","triggered_by","triggered_by_username","attributed_to","attributed_to_username","source_label","status","total","created_count","duplicates_count","meanings_added_count","invalid_count","items","created_at","finished_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"get":{"tags":["Words","Admin"],"summary":"Daftar riwayat impor massal","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar sesi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"triggered_by":{"type":"string"},"triggered_by_username":{"type":"string","nullable":true},"attributed_to":{"type":"string"},"attributed_to_username":{"type":"string","nullable":true},"source_label":{"type":"string","nullable":true},"status":{"type":"string","enum":["running","completed","cancelled","failed"]},"total":{"type":"number"},"created_count":{"type":"number"},"duplicates_count":{"type":"number"},"meanings_added_count":{"type":"number"},"invalid_count":{"type":"number"},"items":{"type":"array","items":{"type":"object","properties":{"lemma":{"type":"string","minLength":1,"maxLength":255},"outcome":{"type":"string","enum":["created","meanings_added","skipped","invalid"]},"meanings_added":{"type":"integer","minimum":0},"message":{"type":"string","maxLength":2000}},"required":["lemma","outcome","meanings_added"]}},"created_at":{"type":"string"},"finished_at":{"type":"string","nullable":true}},"required":["id","triggered_by","triggered_by_username","attributed_to","attributed_to_username","source_label","status","total","created_count","duplicates_count","meanings_added_count","invalid_count","items","created_at","finished_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"number"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/import-sessions/{id}":{"get":{"tags":["Words","Admin"],"summary":"Detail sesi impor massal","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail sesi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"triggered_by":{"type":"string"},"triggered_by_username":{"type":"string","nullable":true},"attributed_to":{"type":"string"},"attributed_to_username":{"type":"string","nullable":true},"source_label":{"type":"string","nullable":true},"status":{"type":"string","enum":["running","completed","cancelled","failed"]},"total":{"type":"number"},"created_count":{"type":"number"},"duplicates_count":{"type":"number"},"meanings_added_count":{"type":"number"},"invalid_count":{"type":"number"},"items":{"type":"array","items":{"type":"object","properties":{"lemma":{"type":"string","minLength":1,"maxLength":255},"outcome":{"type":"string","enum":["created","meanings_added","skipped","invalid"]},"meanings_added":{"type":"integer","minimum":0},"message":{"type":"string","maxLength":2000}},"required":["lemma","outcome","meanings_added"]}},"created_at":{"type":"string"},"finished_at":{"type":"string","nullable":true}},"required":["id","triggered_by","triggered_by_username","attributed_to","attributed_to_username","source_label","status","total","created_count","duplicates_count","meanings_added_count","invalid_count","items","created_at","finished_at"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/bulk":{"post":{"tags":["Words","Admin"],"summary":"Mass-action kata (delete | publish | unpublish). Partial success per-id; publish mengikuti merge lemma twin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["delete","publish","unpublish"]},"ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"minItems":1,"maxItems":50}},"required":["action","ids"]}}}},"responses":{"200":{"description":"Hasil per-id","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"action":{"type":"string","enum":["delete","publish","unpublish"]},"succeeded":{"type":"integer","minimum":0},"failed":{"type":"integer","minimum":0},"results":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"ok":{"type":"boolean","enum":[true]},"merged_into_word_id":{"type":"string","nullable":true}},"required":["id","ok","merged_into_word_id"]},{"type":"object","properties":{"id":{"type":"string"},"ok":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"}},"required":["id","ok","error_code","message"]}]}}},"required":["action","succeeded","failed","results"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid / batch kosong / terlalu besar","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan (publish/unpublish butuh verifikator)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/duplicates":{"get":{"tags":["Words","Admin"],"summary":"Kelompok lemma duplikat (tab Duplikasi)","responses":{"200":{"description":"Kelompok duplikat","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"total_groups":{"type":"integer"},"groups":{"type":"array","items":{"type":"object","properties":{"lemma":{"type":"string"},"language_id":{"type":"string"},"language_code":{"type":"string"},"default_keep_word_id":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"language_id":{"type":"string"},"language_code":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"meanings_count":{"type":"integer"},"created_at":{"type":"string"},"suggested_keep":{"type":"boolean"}},"required":["id","lemma","language_id","language_code","word_type","status","is_verified","meanings_count","created_at","suggested_keep"]}}},"required":["lemma","language_id","language_code","default_keep_word_id","items"]}}},"required":["total_groups","groups"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/duplicates/merge":{"post":{"tags":["Words","Admin"],"summary":"Gabungkan entri lemma duplikat ke satu entri yang dipilih","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"keep_word_id":{"type":"string","minLength":26,"maxLength":26},"merge_word_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"minItems":1}},"required":["keep_word_id","merge_word_ids"]}}}},"responses":{"200":{"description":"Gabungan berhasil","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"keep_word_id":{"type":"string"},"merged_word_ids":{"type":"array","items":{"type":"string"}}},"required":["keep_word_id","merged_word_ids"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid / lemma tidak cocok","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Entri tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/comma-splits":{"get":{"tags":["Words","Admin"],"summary":"Kandidat pecah koma (tab Pemisahan)","responses":{"200":{"description":"Kandidat lemma & terjemahan berkoma","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"total":{"type":"integer"},"lemmas":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"language_id":{"type":"string"},"language_code":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"meanings_count":{"type":"integer"},"suggested_parts":{"type":"array","items":{"type":"string"}},"meaning_preview":{"type":"array","items":{"type":"string"}},"copied_translation":{"type":"string"},"copied_definition":{"type":"string"}},"required":["word_id","lemma","language_id","language_code","word_type","status","is_verified","meanings_count","suggested_parts","meaning_preview","copied_translation","copied_definition"]}},"translations":{"type":"array","items":{"type":"object","properties":{"meaning_translation_id":{"type":"string"},"meaning_id":{"type":"string"},"word_id":{"type":"string"},"lemma":{"type":"string"},"translation_text":{"type":"string"},"language_id":{"type":"string"},"language_code":{"type":"string"},"suggested_parts":{"type":"array","items":{"type":"string"}},"definition":{"type":"string"},"word_class_id":{"type":"string","nullable":true}},"required":["meaning_translation_id","meaning_id","word_id","lemma","translation_text","language_id","language_code","suggested_parts","definition","word_class_id"]}}},"required":["total","lemmas","translations"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/comma-splits/apply":{"post":{"tags":["Words","Admin"],"summary":"Pisahkan lemma jadi beberapa kata, atau terjemahan jadi beberapa makna","requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["lemma"]},"word_id":{"type":"string","minLength":26,"maxLength":26},"parts":{"type":"array","items":{"type":"string","minLength":1},"minItems":2},"meaning_overrides":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","enum":["copy"]}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","enum":["replace"]},"translation_text":{"type":"string","minLength":1},"definition":{"type":"string"},"word_class_id":{"type":"string","nullable":true,"minLength":26,"maxLength":26},"meaning_source":{"type":"string","enum":["manual","kbbi"]}},"required":["mode","translation_text","meaning_source"]}]}}},"required":["kind","word_id","parts"]},{"type":"object","properties":{"kind":{"type":"string","enum":["translation"]},"meaning_translation_id":{"type":"string","minLength":26,"maxLength":26},"parts":{"type":"array","items":{"type":"string","minLength":1},"minItems":2}},"required":["kind","meaning_translation_id","parts"]}]}}}},"responses":{"200":{"description":"Pemisahan berhasil","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"kind":{"type":"string","enum":["lemma","translation"]},"word_id":{"type":"string"},"created_word_ids":{"type":"array","items":{"type":"string"}},"meaning_ids":{"type":"array","items":{"type":"string"}}},"required":["kind","word_id"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Entri tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/comma-splits/mark-literal":{"post":{"tags":["Words","Admin"],"summary":"Tandai koma sebagai literal (keluar antrean Pemisahan)","requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["lemma"]},"word_id":{"type":"string","minLength":26,"maxLength":26}},"required":["kind","word_id"]},{"type":"object","properties":{"kind":{"type":"string","enum":["translation"]},"meaning_translation_id":{"type":"string","minLength":26,"maxLength":26}},"required":["kind","meaning_translation_id"]}]}}}},"responses":{"200":{"description":"Ditandai literal","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"kind":{"type":"string","enum":["lemma","translation"]},"id":{"type":"string"}},"required":["kind","id"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Entri tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/:id":{"get":{"tags":["Words","Admin"],"summary":"Detail kata SEMUA status - prefill form edit (draft/pending/rejected terbuka)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail kata","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"lemma_allows_comma":{"type":"boolean","default":false},"language_id":{"type":"string"},"notes":{"type":"string","nullable":true},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"is_corrected":{"type":"boolean"},"self_verified":{"type":"boolean"},"created_by":{"type":"object","nullable":true,"properties":{"username":{"type":"string"},"role":{"type":"string"}},"required":["username","role"]},"verified_by":{"type":"object","nullable":true,"properties":{"username":{"type":"string"},"role":{"type":"string"}},"required":["username","role"]},"verified_at":{"type":"string","nullable":true},"meanings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"word_class":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"alias":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"parent_id":{"type":"string","nullable":true}},"required":["id","code","name","alias","description","parent_id"]},"inherited_from_meaning_id":{"type":"string","nullable":true},"definition":{"type":"string"},"is_have_definition":{"type":"boolean"},"is_have_translation":{"type":"boolean"},"order_index":{"type":"integer"},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string"},"translation_text":{"type":"string"},"translation_type":{"type":"string"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text","translation_type"]}},"examples":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"source_language_id":{"type":"string"},"source_sentence":{"type":"string"},"target_language_id":{"type":"string","nullable":true},"target_sentence":{"type":"string","nullable":true},"source_type":{"type":"string","nullable":true},"audios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"dialect_id":{"type":"string","nullable":true},"speaker_name":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true},"is_primary":{"type":"boolean"},"mime_type":{"type":"string"}},"required":["id","url","dialect_id","speaker_name","duration_ms","is_primary","mime_type"]}}},"required":["id","source_language_id","source_sentence","target_language_id","target_sentence","source_type","audios"]}}},"required":["id","word_class","inherited_from_meaning_id","definition","is_have_definition","is_have_translation","order_index","translations","examples"]}},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}},"pronunciations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"notation":{"type":"string"},"value":{"type":"string"},"dialect_id":{"type":"string","nullable":true}},"required":["id","notation","value","dialect_id"]}},"images":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"provider_file_id":{"type":"string"},"sha":{"type":"string","nullable":true},"alt_text":{"type":"string","nullable":true},"is_primary":{"type":"boolean"}},"required":["id","url","provider_file_id","alt_text","is_primary"]}},"audios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"dialect_id":{"type":"string","nullable":true},"speaker_name":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true},"is_primary":{"type":"boolean"},"mime_type":{"type":"string"}},"required":["id","url","dialect_id","speaker_name","duration_ms","is_primary","mime_type"]}},"related_words":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"relation_type":{"type":"string"}},"required":["word_id","lemma","relation_type"]}},"appears_in":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"relation_type":{"type":"string"}},"required":["word_id","lemma","relation_type"]}},"variants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"form":{"type":"string"},"variant_type":{"type":"string"},"affix_type":{"type":"string","nullable":true},"affix_value":{"type":"string","nullable":true},"dialect_id":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true}},"required":["id","form","variant_type","affix_type","affix_value","dialect_id","notes"]}},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true},"takedown_reason_code":{"type":"string","nullable":true},"takedown_note":{"type":"string","nullable":true},"taken_down_at":{"type":"string","nullable":true}},"required":["id","lemma","language_id","notes","word_type","status","is_verified","is_corrected","self_verified","created_by","verified_by","verified_at","meanings","categories","pronunciations","images","audios","related_words","appears_in","variants","created_at","updated_at","takedown_reason_code","takedown_note","taken_down_at"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"put":{"tags":["Words","Admin"],"summary":"Edit kata (full replace - kirim ulang seluruh form)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"lemma":{"type":"string","minLength":1,"maxLength":255},"lemma_allows_comma":{"type":"boolean","default":false},"notes":{"type":"string"},"meanings":{"type":"array","items":{"type":"object","properties":{"word_class_id":{"type":"string","minLength":26,"maxLength":26},"definition":{"type":"string","minLength":1},"is_have_definition":{"type":"boolean","default":true},"is_have_translation":{"type":"boolean","default":true},"order_index":{"type":"integer","minimum":1,"default":1},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text"]},"default":[]},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]}},"required":["source_language_id","source_sentence"]}}},"required":["word_class_id","definition"]},"minItems":1},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"],"default":"word"},"usage_labels":{"type":"array","items":{"type":"string","enum":["kasar","tabu","informal","halus","seksual","diskriminatif"]},"default":[]},"category_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"default":[]},"variants":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string","minLength":1,"maxLength":255},"variant_type":{"type":"string","enum":["inflection","derivation","alternative","reduplication"],"default":"alternative"},"affix_type":{"type":"string","enum":["prefix","suffix","circumfix","reduplication"]},"affix_value":{"type":"string","maxLength":50},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"notes":{"type":"string","maxLength":1000}},"required":["form"]},"maxItems":20},"pronunciation":{"type":"object","properties":{"notation":{"type":"string","minLength":1,"default":"ipa"},"value":{"type":"string","minLength":1}},"required":["value"]},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1},"sha":{"type":"string","minLength":1,"maxLength":128},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean","default":false},"content_warnings":{"type":"array","items":{"type":"string","enum":["kekerasan"]},"default":[]}},"required":["url","provider_file_id"]},"maxItems":10},"status":{"type":"string","enum":["draft","published"],"default":"draft"},"related_words":{"type":"array","items":{"type":"object","properties":{"relation_type":{"type":"string","enum":["synonym","antonym","has_component","derived_from"]},"word_id":{"type":"string","minLength":26,"maxLength":26},"word":{"nullable":true}},"required":["relation_type"]},"default":[]}},"required":["language_id","lemma","meanings"]}}}},"responses":{"200":{"description":"Kata ter-update (status per role)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"is_corrected":{"type":"boolean"},"updated_at":{"type":"string","nullable":true},"warnings":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["word_id","lemma","word_type","status","is_verified","is_corrected","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid / referensi id tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"delete":{"tags":["Words","Admin"],"summary":"Soft-delete kata (07-api-delete-kata.md) - hilang dari publik & admin, baris dipertahankan untuk audit/recovery","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Kata di-soft-delete","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan / sudah dihapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/:id/verify":{"post":{"tags":["Words","Admin"],"summary":"Verifikasi kata oleh verifikator (is_verified → true)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Kata terverifikasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator (admin/root/reviewer)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/:id/unverify":{"post":{"tags":["Words","Admin"],"summary":"Cabut verifikasi kata (is_verified → false)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Verifikasi dicabut","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/:id/publish":{"post":{"tags":["Words","Admin"],"summary":"Publikasikan kata (status → published, is_verified → true)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Kata ditayangkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator (admin/root/reviewer)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/:id/unpublish":{"post":{"tags":["Words","Admin"],"summary":"Tarik kata dari tayang (status → draft)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Kata ditarik dari tayang","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/:id/takedown":{"post":{"tags":["Words","Admin"],"summary":"Tarik entri yang tayang (status → taken_down). Bukan soft-delete.","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason_code":{"type":"string","enum":["not_sambas","inaccurate","duplicate","inappropriate","spam","other"]},"note":{"type":"string","maxLength":1000}},"required":["reason_code"]}}}},"responses":{"200":{"description":"Entri ditarik","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["taken_down","published"]}},"required":["id","status"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Bukan published","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/words/:id/restore":{"post":{"tags":["Words","Admin"],"summary":"Pulihkan entri taken_down ke published","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Entri dipulihkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["taken_down","published"]}},"required":["id","status"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Bukan taken_down","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/:wordId/pronunciations":{"post":{"tags":["Words"],"summary":"Kontribusi pelafalan pada kata existing (contributor → antrean review)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"wordId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"dialect_id":{"type":"string","minLength":26,"maxLength":26},"notation":{"type":"string","minLength":1,"default":"ipa"},"value":{"type":"string","minLength":1,"maxLength":500},"audio_url":{"type":"string","format":"uri"},"speaker_name":{"type":"string","maxLength":255},"notes":{"type":"string"}},"required":["value"]}}}},"responses":{"201":{"description":"Pelafalan tersimpan (status per role)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"dialect_id":{"type":"string","nullable":true},"notation":{"type":"string"},"value":{"type":"string"},"audio_url":{"type":"string","nullable":true},"speaker_name":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending_review","published","rejected"]},"is_verified":{"type":"boolean"},"is_corrected":{"type":"boolean"}},"required":["id","word_id","dialect_id","notation","value","audio_url","speaker_name","notes","status","is_verified","is_corrected"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid / duplikat","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/:wordId/pronunciations/audio":{"post":{"tags":["Words"],"summary":"Upload file audio pelafalan (multipart) - multi-take; opsional example_id","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"wordId","in":"path"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"audio":{"type":"string","format":"binary"},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"example_id":{"type":"string","minLength":26,"maxLength":26},"speaker_name":{"type":"string","maxLength":255},"duration_ms":{"type":"integer","nullable":true}}}}}},"responses":{"201":{"description":"Audio tersimpan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"example_id":{"type":"string","nullable":true},"dialect_id":{"type":"string","nullable":true},"url":{"type":"string"},"mime_type":{"type":"string"},"file_size":{"type":"integer"},"duration_ms":{"type":"integer","nullable":true},"speaker_name":{"type":"string","nullable":true},"is_primary":{"type":"boolean"},"status":{"type":"string","enum":["pending_review","published","rejected"]},"is_verified":{"type":"boolean"},"is_corrected":{"type":"boolean"}},"required":["id","word_id","example_id","dialect_id","url","mime_type","file_size","duration_ms","speaker_name","is_primary","status","is_verified","is_corrected"]}},"required":["success","data"]}}}},"400":{"description":"File/MIME tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata/contoh/dialek tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"503":{"description":"Storage belum dikonfigurasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/:wordId/pronunciations/audio/{audioId}":{"delete":{"tags":["Words"],"summary":"Soft-delete audio pelafalan (admin/editor/root)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"wordId","in":"path"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"audioId","in":"path"}],"responses":{"204":{"description":"Audio dihapus"},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata/audio tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/:wordId/images":{"post":{"tags":["Words"],"summary":"Kontribusi gambar contoh pada kata existing (hasil direct-upload)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"wordId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1},"sha":{"type":"string","minLength":1,"maxLength":128},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean","default":false},"content_warnings":{"type":"array","items":{"type":"string","enum":["kekerasan"]},"default":[]}},"required":["url","provider_file_id"]}}}},"responses":{"201":{"description":"Gambar tersimpan (status per role)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"url":{"type":"string"},"provider_file_id":{"type":"string"},"alt_text":{"type":"string","nullable":true},"is_primary":{"type":"boolean"},"status":{"type":"string","enum":["pending_review","published","rejected"]},"is_verified":{"type":"boolean"},"is_corrected":{"type":"boolean"}},"required":["id","word_id","url","provider_file_id","alt_text","is_primary","status","is_verified","is_corrected"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid / file sudah dipakai","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/:wordId/meanings":{"post":{"tags":["Words"],"summary":"Kontribusi definisi (makna) pada kata existing (contributor → antrean review)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"wordId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"word_class_id":{"type":"string","minLength":26,"maxLength":26},"definition":{"type":"string","minLength":1},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"}},"required":["language_id","translation_text"]},"minItems":1}},"required":["definition","translations"]}}}},"responses":{"201":{"description":"Makna tersimpan (status per role)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"word_class_id":{"type":"string","nullable":true},"definition":{"type":"string"},"order_index":{"type":"integer"},"status":{"type":"string","enum":["pending_review","published","rejected"]},"is_verified":{"type":"boolean"},"is_corrected":{"type":"boolean"}},"required":["id","word_id","word_class_id","definition","order_index","status","is_verified","is_corrected"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid / duplikat","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/:wordId/comments":{"get":{"tags":["Comments"],"summary":"Komentar pada sebuah kata (published/taken_down/deleted_by_author, + vote counts)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"wordId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar komentar","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"word_lemma":{"type":"string","nullable":true},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"status":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"created_at":{"type":"string"},"upvotes":{"type":"integer"},"downvotes":{"type":"integer"}},"required":["id","word_id","word_lemma","user_id","username","body","status","created_at","upvotes","downvotes"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"400":{"description":"Query tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak permintaan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"post":{"tags":["Comments"],"summary":"Tulis komentar pada lemma - langsung published (post-moderation + blocklist filter)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"wordId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":1000}},"required":["body"]}}}},"responses":{"201":{"description":"Komentar tersimpan dan tayang","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"word_lemma":{"type":"string","nullable":true},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"status":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"created_at":{"type":"string"}},"required":["id","word_id","word_lemma","user_id","username","body","status","created_at"]}},"required":["success","data"]}}}},"400":{"description":"Body kosong/kepanjangan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak komentar (30/menit per user)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/:id/reports":{"post":{"tags":["Words","Word Reports"],"summary":"Laporkan entri yang tayang (login). Kata tetap tayang sampai verifikator bertindak.","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason_code":{"type":"string","enum":["not_sambas","inaccurate","duplicate","inappropriate","spam","other","violent_image"]},"note":{"type":"string","maxLength":1000},"image_id":{"type":"string","minLength":26,"maxLength":26}},"required":["reason_code"]}}}},"responses":{"201":{"description":"Laporan tersimpan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"image_id":{"type":"string","nullable":true},"status":{"type":"string","enum":["open"]},"created_at":{"type":"string"}},"required":["id","word_id","status","created_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Bukan published atau laporan masih terbuka","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Rate limit","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words":{"get":{"tags":["Words"],"summary":"Daftar semua kata A-Z (browsing publik) - cursor komposit + filter q","parameters":[{"schema":{"type":"string","maxLength":255,"default":""},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","pattern":"^[A-Za-z]$"},"required":false,"name":"letter","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"required":false,"name":"word_type","in":"query"},{"schema":{"type":"boolean","nullable":true},"required":false,"name":"is_verified","in":"query"}],"responses":{"200":{"description":"Daftar kata urut lemma","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"language_id":{"type":"string"},"language_code":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"matched_translation":{"type":"string"},"matched_variant":{"type":"string"},"sense":{"type":"string","nullable":true}},"required":["id","lemma","language_id","language_code","word_type","status","is_verified"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"400":{"description":"Query tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/latest":{"get":{"tags":["Words"],"summary":"Feed kosakata terbaru yang sudah disetujui (cursor waktu persetujuan)","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":1},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Kata published urut persetujuan terbaru","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"language_id":{"type":"string"},"language_code":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"approved_at":{"type":"string"},"sense":{"type":"string","nullable":true}},"required":["id","lemma","language_id","language_code","word_type","status","is_verified","approved_at","sense"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"400":{"description":"Query tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/search":{"get":{"tags":["Words"],"summary":"Cari kata (dropdown sinonim/antonim form admin) - list + meta pagination","parameters":[{"schema":{"type":"string","maxLength":255,"default":""},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","enum":["lemma","translation"],"default":"lemma"},"required":false,"name":"search_in","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"translation_language_id","in":"query"},{"schema":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"required":false,"name":"word_type","in":"query"},{"schema":{"type":"boolean","nullable":true},"required":false,"name":"is_verified","in":"query"}],"responses":{"200":{"description":"Hasil pencarian","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"language_id":{"type":"string"},"language_code":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"matched_translation":{"type":"string"},"matched_variant":{"type":"string"},"sense":{"type":"string","nullable":true}},"required":["id","lemma","language_id","language_code","word_type","status","is_verified"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"400":{"description":"Query tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/today":{"get":{"tags":["Words"],"summary":"Kata hari ini - deterministik per tanggal WIB (korpus kosong = data null)","responses":{"200":{"description":"Detail kata + date + is_new_this_week, atau null","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"lemma":{"type":"string"},"lemma_allows_comma":{"type":"boolean","default":false},"language_id":{"type":"string"},"notes":{"type":"string","nullable":true},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"is_corrected":{"type":"boolean"},"self_verified":{"type":"boolean"},"created_by":{"type":"object","nullable":true,"properties":{"username":{"type":"string"},"role":{"type":"string"}},"required":["username","role"]},"verified_by":{"type":"object","nullable":true,"properties":{"username":{"type":"string"},"role":{"type":"string"}},"required":["username","role"]},"verified_at":{"type":"string","nullable":true},"meanings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"word_class":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"alias":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"parent_id":{"type":"string","nullable":true}},"required":["id","code","name","alias","description","parent_id"]},"inherited_from_meaning_id":{"type":"string","nullable":true},"definition":{"type":"string"},"is_have_definition":{"type":"boolean"},"is_have_translation":{"type":"boolean"},"order_index":{"type":"integer"},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string"},"translation_text":{"type":"string"},"translation_type":{"type":"string"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text","translation_type"]}},"examples":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"source_language_id":{"type":"string"},"source_sentence":{"type":"string"},"target_language_id":{"type":"string","nullable":true},"target_sentence":{"type":"string","nullable":true},"source_type":{"type":"string","nullable":true},"audios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"dialect_id":{"type":"string","nullable":true},"speaker_name":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true},"is_primary":{"type":"boolean"},"mime_type":{"type":"string"}},"required":["id","url","dialect_id","speaker_name","duration_ms","is_primary","mime_type"]}}},"required":["id","source_language_id","source_sentence","target_language_id","target_sentence","source_type","audios"]}}},"required":["id","word_class","inherited_from_meaning_id","definition","is_have_definition","is_have_translation","order_index","translations","examples"]}},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}},"pronunciations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"notation":{"type":"string"},"value":{"type":"string"},"dialect_id":{"type":"string","nullable":true}},"required":["id","notation","value","dialect_id"]}},"images":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"provider_file_id":{"type":"string"},"sha":{"type":"string","nullable":true},"alt_text":{"type":"string","nullable":true},"is_primary":{"type":"boolean"}},"required":["id","url","provider_file_id","alt_text","is_primary"]}},"audios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"dialect_id":{"type":"string","nullable":true},"speaker_name":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true},"is_primary":{"type":"boolean"},"mime_type":{"type":"string"}},"required":["id","url","dialect_id","speaker_name","duration_ms","is_primary","mime_type"]}},"related_words":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"relation_type":{"type":"string"}},"required":["word_id","lemma","relation_type"]}},"appears_in":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"relation_type":{"type":"string"}},"required":["word_id","lemma","relation_type"]}},"variants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"form":{"type":"string"},"variant_type":{"type":"string"},"affix_type":{"type":"string","nullable":true},"affix_value":{"type":"string","nullable":true},"dialect_id":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true}},"required":["id","form","variant_type","affix_type","affix_value","dialect_id","notes"]}},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"is_new_this_week":{"type":"boolean"}},"required":["id","lemma","language_id","notes","word_type","status","is_verified","is_corrected","self_verified","created_by","verified_by","verified_at","meanings","categories","pronunciations","images","audios","related_words","appears_in","variants","date","is_new_this_week"]}},"required":["success","data"]}}}}}}},"/api/v1/words/lemma/:lemma":{"get":{"tags":["Words"],"summary":"Detail kata published berdasarkan lemma (URL publik web)","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255},"required":true,"name":"lemma","in":"path"}],"responses":{"200":{"description":"Detail kata","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"lemma_allows_comma":{"type":"boolean","default":false},"language_id":{"type":"string"},"notes":{"type":"string","nullable":true},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"is_corrected":{"type":"boolean"},"self_verified":{"type":"boolean"},"created_by":{"type":"object","nullable":true,"properties":{"username":{"type":"string"},"role":{"type":"string"}},"required":["username","role"]},"verified_by":{"type":"object","nullable":true,"properties":{"username":{"type":"string"},"role":{"type":"string"}},"required":["username","role"]},"verified_at":{"type":"string","nullable":true},"meanings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"word_class":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"alias":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"parent_id":{"type":"string","nullable":true}},"required":["id","code","name","alias","description","parent_id"]},"inherited_from_meaning_id":{"type":"string","nullable":true},"definition":{"type":"string"},"is_have_definition":{"type":"boolean"},"is_have_translation":{"type":"boolean"},"order_index":{"type":"integer"},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string"},"translation_text":{"type":"string"},"translation_type":{"type":"string"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text","translation_type"]}},"examples":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"source_language_id":{"type":"string"},"source_sentence":{"type":"string"},"target_language_id":{"type":"string","nullable":true},"target_sentence":{"type":"string","nullable":true},"source_type":{"type":"string","nullable":true},"audios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"dialect_id":{"type":"string","nullable":true},"speaker_name":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true},"is_primary":{"type":"boolean"},"mime_type":{"type":"string"}},"required":["id","url","dialect_id","speaker_name","duration_ms","is_primary","mime_type"]}}},"required":["id","source_language_id","source_sentence","target_language_id","target_sentence","source_type","audios"]}}},"required":["id","word_class","inherited_from_meaning_id","definition","is_have_definition","is_have_translation","order_index","translations","examples"]}},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}},"pronunciations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"notation":{"type":"string"},"value":{"type":"string"},"dialect_id":{"type":"string","nullable":true}},"required":["id","notation","value","dialect_id"]}},"images":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"provider_file_id":{"type":"string"},"sha":{"type":"string","nullable":true},"alt_text":{"type":"string","nullable":true},"is_primary":{"type":"boolean"}},"required":["id","url","provider_file_id","alt_text","is_primary"]}},"audios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"dialect_id":{"type":"string","nullable":true},"speaker_name":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true},"is_primary":{"type":"boolean"},"mime_type":{"type":"string"}},"required":["id","url","dialect_id","speaker_name","duration_ms","is_primary","mime_type"]}},"related_words":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"relation_type":{"type":"string"}},"required":["word_id","lemma","relation_type"]}},"appears_in":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"relation_type":{"type":"string"}},"required":["word_id","lemma","relation_type"]}},"variants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"form":{"type":"string"},"variant_type":{"type":"string"},"affix_type":{"type":"string","nullable":true},"affix_value":{"type":"string","nullable":true},"dialect_id":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true}},"required":["id","form","variant_type","affix_type","affix_value","dialect_id","notes"]}}},"required":["id","lemma","language_id","notes","word_type","status","is_verified","is_corrected","self_verified","created_by","verified_by","verified_at","meanings","categories","pronunciations","images","audios","related_words","appears_in","variants"]}},"required":["success","data"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/:id":{"get":{"tags":["Words"],"summary":"Detail kata published (halaman publik)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail kata","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"lemma_allows_comma":{"type":"boolean","default":false},"language_id":{"type":"string"},"notes":{"type":"string","nullable":true},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"is_corrected":{"type":"boolean"},"self_verified":{"type":"boolean"},"created_by":{"type":"object","nullable":true,"properties":{"username":{"type":"string"},"role":{"type":"string"}},"required":["username","role"]},"verified_by":{"type":"object","nullable":true,"properties":{"username":{"type":"string"},"role":{"type":"string"}},"required":["username","role"]},"verified_at":{"type":"string","nullable":true},"meanings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"word_class":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"alias":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"parent_id":{"type":"string","nullable":true}},"required":["id","code","name","alias","description","parent_id"]},"inherited_from_meaning_id":{"type":"string","nullable":true},"definition":{"type":"string"},"is_have_definition":{"type":"boolean"},"is_have_translation":{"type":"boolean"},"order_index":{"type":"integer"},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string"},"translation_text":{"type":"string"},"translation_type":{"type":"string"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text","translation_type"]}},"examples":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"source_language_id":{"type":"string"},"source_sentence":{"type":"string"},"target_language_id":{"type":"string","nullable":true},"target_sentence":{"type":"string","nullable":true},"source_type":{"type":"string","nullable":true},"audios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"dialect_id":{"type":"string","nullable":true},"speaker_name":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true},"is_primary":{"type":"boolean"},"mime_type":{"type":"string"}},"required":["id","url","dialect_id","speaker_name","duration_ms","is_primary","mime_type"]}}},"required":["id","source_language_id","source_sentence","target_language_id","target_sentence","source_type","audios"]}}},"required":["id","word_class","inherited_from_meaning_id","definition","is_have_definition","is_have_translation","order_index","translations","examples"]}},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}},"pronunciations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"notation":{"type":"string"},"value":{"type":"string"},"dialect_id":{"type":"string","nullable":true}},"required":["id","notation","value","dialect_id"]}},"images":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"provider_file_id":{"type":"string"},"sha":{"type":"string","nullable":true},"alt_text":{"type":"string","nullable":true},"is_primary":{"type":"boolean"}},"required":["id","url","provider_file_id","alt_text","is_primary"]}},"audios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"dialect_id":{"type":"string","nullable":true},"speaker_name":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true},"is_primary":{"type":"boolean"},"mime_type":{"type":"string"}},"required":["id","url","dialect_id","speaker_name","duration_ms","is_primary","mime_type"]}},"related_words":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"relation_type":{"type":"string"}},"required":["word_id","lemma","relation_type"]}},"appears_in":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"relation_type":{"type":"string"}},"required":["word_id","lemma","relation_type"]}},"variants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"form":{"type":"string"},"variant_type":{"type":"string"},"affix_type":{"type":"string","nullable":true},"affix_value":{"type":"string","nullable":true},"dialect_id":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true}},"required":["id","form","variant_type","affix_type","affix_value","dialect_id","notes"]}}},"required":["id","lemma","language_id","notes","word_type","status","is_verified","is_corrected","self_verified","created_by","verified_by","verified_at","meanings","categories","pronunciations","images","audios","related_words","appears_in","variants"]}},"required":["success","data"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/:id/change-history":{"get":{"tags":["Words","Suggestions"],"summary":"Riwayat perubahan kata - timeline semua edit (langsung & dari suggestion)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"},{"schema":{"type":"number","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar riwayat perubahan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":26,"maxLength":26},"timestamp":{"type":"string"},"actor":{"type":"object","properties":{"user_id":{"type":"string"},"username":{"type":"string","nullable":true}},"required":["user_id","username"]},"type":{"type":"string","enum":["direct_edit","suggest_edit"]},"changes":{"type":"array","items":{"type":"object","properties":{"entity":{"type":"string"},"field":{"type":"string"},"old_value":{"nullable":true},"new_value":{"nullable":true},"display_old":{"type":"string"},"display_new":{"type":"string"}},"required":["entity","field","display_old","display_new"]}},"source":{"type":"object","nullable":true,"properties":{"suggestion_id":{"type":"string","minLength":26,"maxLength":26},"suggested_by":{"type":"object","properties":{"user_id":{"type":"string","minLength":26,"maxLength":26},"username":{"type":"string","nullable":true}},"required":["user_id","username"]},"reason":{"type":"string"},"reviewer":{"type":"object","nullable":true,"properties":{"user_id":{"type":"string","minLength":26,"maxLength":26},"username":{"type":"string","nullable":true}},"required":["user_id","username"]},"review_comment":{"type":"string","nullable":true}},"required":["suggestion_id","suggested_by","reason","reviewer","review_comment"]}},"required":["id","timestamp","actor","type","changes","source"]}},"meta":{"type":"object","properties":{"limit":{"type":"number"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/words/:id/suggest-edit":{"post":{"tags":["Words","Suggestions"],"summary":"Usulkan perubahan pada kata yang tayang","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"proposed_changes":{"type":"object","properties":{"lemma":{"type":"string","minLength":1,"maxLength":255},"notes":{"type":"string","maxLength":2000},"meanings":{"type":"array","items":{"type":"object","properties":{"meaning_id":{"type":"string","minLength":26,"maxLength":26},"action":{"type":"string","enum":["update","add","delete"]},"word_class_id":{"type":"string","minLength":26,"maxLength":26},"definition":{"type":"string","maxLength":5000},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1,"maxLength":500},"translation_type":{"type":"string","maxLength":50}},"required":["language_id","translation_text"]}},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","maxLength":2000},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string","maxLength":2000},"source_type":{"type":"string","maxLength":100}},"required":["source_language_id","source_sentence"]}}},"required":["action"]},"maxItems":10},"category_ids_to_add":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26}},"category_ids_to_remove":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26}},"relations":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string","enum":["add","remove"]},"relation_type":{"type":"string","enum":["synonym","antonym","has_component","derived_from"]},"word_id":{"type":"string","minLength":26,"maxLength":26}},"required":["action","relation_type","word_id"]},"maxItems":10},"variants":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string","enum":["add","remove"]},"form":{"type":"string","minLength":1,"maxLength":255},"variant_type":{"type":"string","enum":["alternative","inflection","derivation","reduplication"],"default":"alternative"},"dialect_id":{"type":"string","nullable":true,"minLength":26,"maxLength":26}},"required":["action","form"]},"maxItems":10},"images":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string","enum":["add","remove","set_primary"]},"image_id":{"type":"string","minLength":26,"maxLength":26},"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1,"maxLength":255},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean"}},"required":["action"]},"maxItems":5}}},"reason_code":{"type":"string","enum":["typo","inaccurate_definition","missing_example","missing_relation","image_issue","other"]},"reason_text":{"type":"string","maxLength":500},"reason":{"type":"string","minLength":1,"maxLength":500}},"required":["proposed_changes"]}}}},"responses":{"201":{"description":"Usulan berhasil dibuat","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"suggestion_id":{"type":"string","minLength":26,"maxLength":26},"word_id":{"type":"string","minLength":26,"maxLength":26},"word_lemma":{"type":"string"},"status":{"type":"string","enum":["pending"]},"created_at":{"type":"string"},"message":{"type":"string"}},"required":["suggestion_id","word_id","word_lemma","status","created_at","message"]}},"required":["success","data"]}}}},"400":{"description":"Bad request / invalid changes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-suggestions":{"get":{"tags":["Admin","Suggestions"],"summary":"List usulan perubahan kata (admin)","parameters":[{"schema":{"type":"string","enum":["pending","approved","rejected","corrected"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"number","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar usulan (cursor)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":26,"maxLength":26},"word_id":{"type":"string","minLength":26,"maxLength":26},"word_lemma":{"type":"string"},"contributor_id":{"type":"string","minLength":26,"maxLength":26},"contributor_username":{"type":"string","nullable":true},"reason":{"type":"string"},"reason_code":{"type":"string","enum":["typo","inaccurate_definition","missing_example","missing_relation","image_issue","other"]},"status":{"type":"string","enum":["pending","approved","rejected","corrected"]},"created_at":{"type":"string"},"summary_changes":{"type":"object","properties":{"lemma":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"meanings_count":{"type":"number"},"categories_added":{"type":"number"},"categories_removed":{"type":"number"},"relations_count":{"type":"number"},"variants_count":{"type":"number"},"images_count":{"type":"number"}},"required":["lemma","notes","meanings_count","categories_added","categories_removed","relations_count","variants_count","images_count"]}},"required":["id","word_id","word_lemma","contributor_id","contributor_username","reason","reason_code","status","created_at","summary_changes"]}},"meta":{"type":"object","properties":{"limit":{"type":"number"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-suggestions/:id":{"get":{"tags":["Admin","Suggestions"],"summary":"Detail usulan + diff (current vs proposed)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail usulan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"suggestion":{"type":"object","properties":{"id":{"type":"string","minLength":26,"maxLength":26},"word_id":{"type":"string","minLength":26,"maxLength":26},"word_lemma":{"type":"string"},"contributor_id":{"type":"string","minLength":26,"maxLength":26},"contributor_username":{"type":"string","nullable":true},"reason":{"type":"string"},"reason_code":{"type":"string","enum":["typo","inaccurate_definition","missing_example","missing_relation","image_issue","other"]},"proposed_changes":{"nullable":true},"status":{"type":"string","enum":["pending","approved","rejected","corrected"]},"created_at":{"type":"string"}},"required":["id","word_id","word_lemma","contributor_id","contributor_username","reason","reason_code","status","created_at"]},"current_word":{"type":"object","properties":{"lemma":{"type":"string"},"notes":{"type":"string","nullable":true},"meanings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":26,"maxLength":26},"word_class":{"type":"object","nullable":true,"properties":{"code":{"type":"string"},"name":{"type":"string"}},"required":["code","name"]},"definition":{"type":"string"},"translations":{"type":"array","items":{"type":"object","properties":{"translation_text":{"type":"string"}},"required":["translation_text"]}}},"required":["id","word_class","definition","translations"]}},"category_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26}},"relations":{"type":"array","items":{"type":"object","properties":{"relation_type":{"type":"string"},"word_id":{"type":"string","minLength":26,"maxLength":26},"lemma":{"type":"string"}},"required":["relation_type","word_id","lemma"]}},"variants":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string"},"variant_type":{"type":"string"},"dialect_id":{"type":"string","nullable":true}},"required":["form","variant_type","dialect_id"]}},"images":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":26,"maxLength":26},"url":{"type":"string"},"is_primary":{"type":"boolean"},"alt_text":{"type":"string","nullable":true}},"required":["id","url","is_primary","alt_text"]}}},"required":["lemma","notes","meanings","category_ids","relations","variants","images"]},"diff":{"type":"object","properties":{"lemma":{"type":"object","properties":{"current":{"type":"string","nullable":true},"proposed":{"type":"string","nullable":true},"changed":{"type":"boolean"}},"required":["current","proposed","changed"]},"notes":{"type":"object","properties":{"current":{"type":"string","nullable":true},"proposed":{"type":"string","nullable":true},"changed":{"type":"boolean"}},"required":["current","proposed","changed"]},"meanings":{"type":"array","items":{"type":"object","properties":{"meaning_id":{"type":"string","nullable":true,"minLength":26,"maxLength":26},"changes":{"type":"array","items":{"type":"object","properties":{"current":{"type":"string","nullable":true},"proposed":{"type":"string","nullable":true},"changed":{"type":"boolean"}},"required":["current","proposed","changed"]}}},"required":["meaning_id","changes"]}},"categories":{"type":"object","properties":{"added":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26}},"removed":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26}}},"required":["added","removed"]},"relations":{"type":"object","properties":{"added":{"type":"array","items":{"type":"object","properties":{"relation_type":{"type":"string"},"word_id":{"type":"string","minLength":26,"maxLength":26},"lemma":{"type":"string"}},"required":["relation_type","word_id"]}},"removed":{"type":"array","items":{"type":"object","properties":{"relation_type":{"type":"string"},"word_id":{"type":"string","minLength":26,"maxLength":26},"lemma":{"type":"string"}},"required":["relation_type","word_id"]}}},"required":["added","removed"]},"variants":{"type":"object","properties":{"added":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string"},"variant_type":{"type":"string"}},"required":["form","variant_type"]}},"removed":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string"},"variant_type":{"type":"string"}},"required":["form","variant_type"]}}},"required":["added","removed"]},"images":{"type":"object","properties":{"added":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"is_primary":{"type":"boolean"},"provider":{"type":"string","nullable":true},"provider_file_id":{"type":"string","nullable":true}},"required":["url","is_primary"]}},"removed":{"type":"array","items":{"type":"object","properties":{"image_id":{"type":"string","minLength":26,"maxLength":26}},"required":["image_id"]}},"set_primary":{"type":"array","items":{"type":"object","properties":{"image_id":{"type":"string","minLength":26,"maxLength":26}},"required":["image_id"]}}},"required":["added","removed","set_primary"]}},"required":["lemma","notes","meanings","categories","relations","variants","images"]}},"required":["suggestion","current_word","diff"]}},"required":["success","data"]}}}},"404":{"description":"Usulan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-suggestions/:id/approve":{"post":{"tags":["Admin","Suggestions"],"summary":"Setujui usulan dan terapkan perubahan ke kata. JSON atau multipart (file_<key> sensor opsional)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"comment":{"type":"string","maxLength":500},"image_decisions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","minLength":1,"maxLength":255},"decision":{"type":"string","enum":["approve","reject"]}},"required":["key","decision"]},"maxItems":10}}}}}},"responses":{"200":{"description":"Usulan disetujui + perubahan diterapkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"suggestion_id":{"type":"string","minLength":26,"maxLength":26},"word_id":{"type":"string","minLength":26,"maxLength":26},"word_lemma":{"type":"string"},"status":{"type":"string","enum":["approved"]},"changes_applied":{"type":"number"},"message":{"type":"string"}},"required":["suggestion_id","word_id","word_lemma","status","changes_applied","message"]}},"required":["success","data"]}}}},"404":{"description":"Usulan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Usulan sudah diverifikasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-suggestions/:id/reject":{"post":{"tags":["Admin","Suggestions"],"summary":"Tolak usulan dengan alasan","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"comment":{"type":"string","minLength":1,"maxLength":500}},"required":["comment"]}}}},"responses":{"200":{"description":"Usulan ditolak","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"suggestion_id":{"type":"string","minLength":26,"maxLength":26},"status":{"type":"string","enum":["rejected"]}},"required":["suggestion_id","status"]}},"required":["success","data"]}}}},"400":{"description":"Alasan wajib diisi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Usulan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Usulan sudah diverifikasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-suggestions/:id/correct":{"post":{"tags":["Admin","Suggestions"],"summary":"Koreksi usulan sebelum menyetujui","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"entity_type":{"type":"string","enum":["word_suggestion"]},"publish":{"type":"boolean","default":true},"corrected_changes":{"type":"object","properties":{"lemma":{"type":"string","minLength":1,"maxLength":255},"notes":{"type":"string","maxLength":2000},"meanings":{"type":"array","items":{"type":"object","properties":{"meaning_id":{"type":"string","minLength":26,"maxLength":26},"action":{"type":"string","enum":["update","add","delete"]},"word_class_id":{"type":"string","minLength":26,"maxLength":26},"definition":{"type":"string","maxLength":5000},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1,"maxLength":500},"translation_type":{"type":"string","maxLength":50}},"required":["language_id","translation_text"]}},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","maxLength":2000},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string","maxLength":2000},"source_type":{"type":"string","maxLength":100}},"required":["source_language_id","source_sentence"]}}},"required":["action"]},"maxItems":10},"category_ids_to_add":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26}},"category_ids_to_remove":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26}},"relations":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string","enum":["add","remove"]},"relation_type":{"type":"string","enum":["synonym","antonym","has_component","derived_from"]},"word_id":{"type":"string","minLength":26,"maxLength":26}},"required":["action","relation_type","word_id"]},"maxItems":10},"variants":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string","enum":["add","remove"]},"form":{"type":"string","minLength":1,"maxLength":255},"variant_type":{"type":"string","enum":["alternative","inflection","derivation","reduplication"],"default":"alternative"},"dialect_id":{"type":"string","nullable":true,"minLength":26,"maxLength":26}},"required":["action","form"]},"maxItems":10},"images":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string","enum":["add","remove","set_primary"]},"image_id":{"type":"string","minLength":26,"maxLength":26},"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1,"maxLength":255},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean"}},"required":["action"]},"maxItems":5}}},"comment":{"type":"string","maxLength":500}},"required":["entity_type","corrected_changes"]}}}},"responses":{"200":{"description":"Koreksi diterapkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"suggestion_id":{"type":"string"},"status":{"type":"string"},"applied":{"type":"boolean"},"changes_applied":{"type":"number"},"word_lemma":{"type":"string"},"message":{"type":"string"}},"required":["suggestion_id","status","applied","changes_applied","word_lemma","message"]}},"required":["success","data"]}}}}}}},"/api/v1/meanings/:meaningId/examples":{"post":{"tags":["Words"],"summary":"Kontribusi contoh kalimat (sample) pada makna existing","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"meaningId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]},"notes":{"type":"string"}},"required":["source_language_id","source_sentence"]}}}},"responses":{"201":{"description":"Contoh kalimat tersimpan (status per role)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"meaning_id":{"type":"string"},"source_language_id":{"type":"string"},"source_sentence":{"type":"string"},"target_language_id":{"type":"string","nullable":true},"target_sentence":{"type":"string","nullable":true},"source_type":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending_review","published","rejected"]},"is_verified":{"type":"boolean"},"is_corrected":{"type":"boolean"}},"required":["id","meaning_id","source_language_id","source_sentence","target_language_id","target_sentence","source_type","notes","status","is_verified","is_corrected"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid / bahasa tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Makna tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/word-classes":{"get":{"tags":["Words"],"summary":"Daftar kelas kata untuk dropdown (termasuk hierarki parent)","responses":{"200":{"description":"Daftar kelas kata","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"alias":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"parent_id":{"type":"string","nullable":true}},"required":["id","code","name","alias","description","parent_id"]}}},"required":["success","data"]}}}}}}},"/api/v1/votes":{"post":{"tags":["Votes"],"summary":"Toggle upvote/downvote - vote searah kedua kali = batal, beda arah = ganti (login, semua role)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"target_type":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"target_id":{"type":"string","minLength":26,"maxLength":26},"value":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[-1]}]}},"required":["target_type","target_id","value"]}}}},"responses":{"200":{"description":"State vote final + counts segar","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"target_type":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"target_id":{"type":"string"},"my_vote":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[-1]},{"nullable":true}]},"upvotes":{"type":"integer"},"downvotes":{"type":"integer"}},"required":["target_type","target_id","my_vote","upvotes","downvotes"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Target vote tidak ditemukan / sudah dihapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak toggle (60/menit per user)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/votes/counts":{"get":{"tags":["Votes"],"summary":"Batch jumlah vote per target (publik) - client memegang id dari word detail","parameters":[{"schema":{"type":"string"},"required":true,"name":"targets","in":"query"}],"responses":{"200":{"description":"Counts per target (target tanpa vote = 0/0)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"target_type":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"target_id":{"type":"string"},"upvotes":{"type":"integer"},"downvotes":{"type":"integer"}},"required":["target_type","target_id","upvotes","downvotes"]}}},"required":["success","data"]}}}},"400":{"description":"Format targets tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak permintaan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/votes/history":{"get":{"tags":["Votes"],"summary":"Riwayat vote milik user login (semua jenis target, lemma kata induk)","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"required":false,"name":"target_type","in":"query"},{"schema":{"type":"string","enum":["1","-1"]},"required":false,"name":"value","in":"query"}],"responses":{"200":{"description":"Daftar vote milik pemohon","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"target_type":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"target_id":{"type":"string"},"value":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[-1]}]},"voted_at":{"type":"string"},"word":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"lemma":{"type":"string"},"word_type":{"type":"string"},"is_verified":{"type":"boolean"}},"required":["id","lemma","word_type","is_verified"]}},"required":["id","target_type","target_id","value","voted_at","word"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"400":{"description":"Query tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak permintaan (100/menit per user)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/votes/deck":{"get":{"tags":["Votes"],"summary":"Antrean kata published yang user belum vote - deck nilai di tab Kontribusi (login)","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":20,"default":10},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":1},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar kartu deck","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"language_id":{"type":"string"},"language_code":{"type":"string"},"word_type":{"type":"string"},"status":{"type":"string"},"is_verified":{"type":"boolean"},"approved_at":{"type":"string"},"sense":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"downvotes":{"type":"integer"}},"required":["id","lemma","language_id","language_code","word_type","status","is_verified","approved_at","sense","upvotes","downvotes"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"400":{"description":"Query tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak permintaan (100/menit per user)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/votes/my":{"get":{"tags":["Votes"],"summary":"Vote milik user login untuk batch target - state tombol upvote/downvote di UI","parameters":[{"schema":{"type":"string"},"required":true,"name":"targets","in":"query"}],"responses":{"200":{"description":"Vote user untuk target yang dipilih saja","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"target_type":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"target_id":{"type":"string"},"value":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[-1]}]}},"required":["target_type","target_id","value"]}}},"required":["success","data"]}}}},"400":{"description":"Format targets tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/comments/my":{"get":{"tags":["Comments"],"summary":"Komentar milik user login (semua status kecuali soft-delete)","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"Daftar komentar milik pemohon","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"word_lemma":{"type":"string","nullable":true},"body":{"type":"string"},"status":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"created_at":{"type":"string"},"reviewed_at":{"type":"string","nullable":true}},"required":["id","word_id","word_lemma","body","status","created_at","reviewed_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"400":{"description":"Query tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak permintaan (100/menit per user)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/comments/:id":{"delete":{"tags":["Comments"],"summary":"Hapus komentar oleh penulis → status deleted_by_author","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Komentar ditandai dihapus penulis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan penulis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Komentar tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/bookmarks":{"post":{"tags":["Bookmarks"],"summary":"Toggle bookmark kata - sudah ada = lepas, belum = pasang (login, semua role)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"word_id":{"type":"string","minLength":26,"maxLength":26}},"required":["word_id"]}}}},"responses":{"200":{"description":"State bookmark final kata","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"word_id":{"type":"string"},"is_bookmarked":{"type":"boolean"},"bookmarked_at":{"type":"string","nullable":true}},"required":["word_id","is_bookmarked","bookmarked_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kata tidak ditemukan / sudah dihapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak toggle (30/menit per user)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/bookmarks/my":{"get":{"tags":["Bookmarks"],"summary":"Daftar bookmark user login (cursor) - word_ids opsional untuk cek status batch","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string"},"required":false,"name":"word_ids","in":"query"}],"responses":{"200":{"description":"Bookmark user + ringkasan kata; meta hanya tanpa word_ids","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"bookmarked_at":{"type":"string"},"word":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"word_type":{"type":"string"},"is_verified":{"type":"boolean"},"available":{"type":"boolean"}},"required":["id","lemma","word_type","is_verified","available"]}},"required":["word_id","bookmarked_at","word"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data"]}}}},"400":{"description":"Format limit/cursor/word_ids tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/users/me":{"get":{"tags":["Users"],"summary":"Profil sendiri (prefill editor)","responses":{"200":{"description":"Profil sendiri","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"username":{"type":"string"},"display_name":{"type":"string"},"bio":{"type":"string","nullable":true},"avatar_url":{"type":"string","nullable":true,"format":"uri"}},"required":["username","display_name","bio","avatar_url"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"patch":{"tags":["Users"],"summary":"Edit display_name dan/atau bio","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"display_name":{"type":"string","minLength":1,"maxLength":100},"bio":{"type":"string","nullable":true,"maxLength":500}}}}}},"responses":{"200":{"description":"Profil diperbarui","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"username":{"type":"string"},"display_name":{"type":"string"},"bio":{"type":"string","nullable":true},"avatar_url":{"type":"string","nullable":true,"format":"uri"}},"required":["username","display_name","bio","avatar_url"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/users/me/avatar":{"post":{"tags":["Users"],"summary":"Upload / ganti avatar (multipart field `file`)","responses":{"200":{"description":"Avatar tersimpan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"avatar_url":{"type":"string","format":"uri"}},"required":["avatar_url"]}},"required":["success","data"]}}}},"400":{"description":"File tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"503":{"description":"Storage belum dikonfigurasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"delete":{"tags":["Users"],"summary":"Hapus avatar","responses":{"204":{"description":"Avatar dihapus"},"401":{"description":"Token tidak ada","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/users/:username/activity":{"get":{"tags":["Users"],"summary":"Aktivitas publik terbaru by username (tanpa auth)","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":100},"required":true,"name":"username","in":"path"}],"responses":{"200":{"description":"Daftar aktivitas","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["contribution","comment","verification"]},"occurred_at":{"type":"string"},"word_id":{"type":"string","nullable":true},"lemma":{"type":"string","nullable":true},"summary":{"type":"string"}},"required":["kind","occurred_at","word_id","lemma","summary"]}}},"required":["items"]}},"required":["success","data"]}}}},"400":{"description":"Username tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"User tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/users/:username":{"get":{"tags":["Users"],"summary":"Profil publik by username (tanpa auth, tanpa PII)","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":100},"required":true,"name":"username","in":"path"}],"responses":{"200":{"description":"Profil publik","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"username":{"type":"string"},"display_name":{"type":"string"},"bio":{"type":"string","nullable":true},"role":{"type":"string"},"is_verifier":{"type":"boolean"},"joined_at":{"type":"string"},"avatar_url":{"type":"string","nullable":true,"format":"uri"},"stats":{"type":"object","properties":{"contributions_approved":{"type":"integer"},"verifications_done":{"type":"integer"},"comments_published":{"type":"integer"}},"required":["contributions_approved","verifications_done","comments_published"]}},"required":["username","display_name","bio","role","is_verifier","joined_at","avatar_url","stats"]}},"required":["success","data"]}}}},"400":{"description":"Username tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"User tidak ditemukan / nonaktif / terhapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/images":{"post":{"tags":["Images"],"summary":"Upload gambar kata ke penyimpanan publik (GitHub) - multipart field `file`","parameters":[{"schema":{"type":"string","enum":["word"],"default":"word"},"required":false,"name":"purpose","in":"query"}],"responses":{"201":{"description":"Gambar tersimpan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider":{"type":"string"},"provider_file_id":{"type":"string"},"sha":{"type":"string"}},"required":["url","provider","provider_file_id","sha"]}},"required":["success","data"]}}}},"400":{"description":"File/MIME tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"503":{"description":"Storage belum dikonfigurasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/device/register":{"post":{"tags":["Device"],"summary":"Daftarkan / update FCM token perangkat (login)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"udid":{"type":"string","minLength":1,"maxLength":255},"fcm_token":{"type":"string","minLength":1,"maxLength":4096}},"required":["udid","fcm_token"]}}}},"responses":{"200":{"description":"Token tersimpan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"udid":{"type":"string"},"fcm_token_registered":{"type":"boolean"},"revoked":{"type":"boolean"}},"required":["udid"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/device/revoke":{"patch":{"tags":["Device"],"summary":"Detach FCM token perangkat ini (logout)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"udid":{"type":"string","minLength":1,"maxLength":255}},"required":["udid"]}}}},"responses":{"200":{"description":"Revoke dicoba (idempotent)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"udid":{"type":"string"},"fcm_token_registered":{"type":"boolean"},"revoked":{"type":"boolean"}},"required":["udid"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/notifications":{"get":{"tags":["Notifications"],"summary":"Daftar notifikasi inbox milik user login","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"unread","in":"query"}],"responses":{"200":{"description":"Daftar inbox","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["contribution_approved","contribution_rejected","contribution_corrected","suggestion_approved","suggestion_rejected","suggestion_corrected","word_taken_down","contribution_paused","contribution_resumed","translation_help_approved","translation_help_rejected","translation_help_taken_down","campaign"]},"title":{"type":"string"},"body":{"type":"string"},"target_kind":{"type":"string","enum":["contribution","suggestion","word","translation_help","campaign"]},"target_id":{"type":"string"},"read_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","type","title","body","target_kind","target_id","read_at","created_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/notifications/unread-count":{"get":{"tags":["Notifications"],"summary":"Jumlah notifikasi belum dibaca milik user login","responses":{"200":{"description":"Unread count","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"unread_count":{"type":"integer"}},"required":["unread_count"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/notifications/read-all":{"post":{"tags":["Notifications"],"summary":"Tandai semua notifikasi milik user sebagai dibaca","responses":{"200":{"description":"Jumlah baris yang diubah","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"updated":{"type":"integer"}},"required":["updated"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/notifications/:id/read":{"post":{"tags":["Notifications"],"summary":"Tandai satu notifikasi sebagai dibaca (idempotent)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Status baca","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"already_read":{"type":"boolean"}},"required":["id","already_read"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Bukan milik pemohon atau tidak ada","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/comments":{"get":{"tags":["Comments","Admin"],"summary":"List komentar admin (filter status + word_id) - cursor pagination","parameters":[{"schema":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"word_id","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar komentar + username + info moderasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"word_lemma":{"type":"string","nullable":true},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string"},"status":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"created_at":{"type":"string"},"body_original":{"type":"string","nullable":true},"is_censored":{"type":"boolean"},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true}},"required":["id","word_id","word_lemma","user_id","username","body","status","created_at","body_original","is_censored","reviewed_by","reviewed_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator (admin/root/reviewer)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/comments/:id/takedown":{"post":{"tags":["Comments","Admin"],"summary":"Takedown komentar published → taken_down","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Komentar di-takedown","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["taken_down"]},"reviewed_by":{"type":"string"},"reviewed_at":{"type":"string"}},"required":["id","status","reviewed_by","reviewed_at"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Komentar tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Sudah di-takedown / bukan published","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/comments/:id/uncensor":{"post":{"tags":["Comments","Admin"],"summary":"Pulihkan teks asli yang disensor blocklist","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Teks asli dipulihkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"body_original":{"nullable":true},"is_censored":{"type":"boolean","enum":[false]}},"required":["id","body","body_original","is_censored"]}},"required":["success","data"]}}}},"400":{"description":"Tidak ada teks tersensor","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Komentar tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/comment-blocklist":{"get":{"tags":["Comment Blocklist","Admin"],"summary":"List kata blocklist aktif","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":100},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Daftar kata","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"word":{"type":"string"},"created_by":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","word","created_by","created_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"post":{"tags":["Comment Blocklist","Admin"],"summary":"Tambah kata ke blocklist","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"word":{"type":"string","minLength":1,"maxLength":100}},"required":["word"]}}}},"responses":{"201":{"description":"Kata ditambahkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word":{"type":"string"},"created_by":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","word","created_by","created_at"]}},"required":["success","data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Duplikat","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/comment-blocklist/bulk":{"post":{"tags":["Comment Blocklist","Admin"],"summary":"Tambah banyak kata ke blocklist; duplikat diabaikan","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"words":{"type":"array","items":{"type":"string","maxLength":1000},"minItems":1,"maxItems":2000}},"required":["words"]}}}},"responses":{"200":{"description":"Batch diproses","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"created_count":{"type":"integer"},"skipped_count":{"type":"integer"},"invalid_count":{"type":"integer"}},"required":["created_count","skipped_count","invalid_count"]}},"required":["success","data"]}}}},"400":{"description":"Tidak ada kata valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/comment-blocklist/:id":{"delete":{"tags":["Comment Blocklist","Admin"],"summary":"Hapus (soft) kata blocklist","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Terhapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/votes":{"get":{"tags":["Admin Votes"],"summary":"Daftar vote dengan cursor pagination (root/admin/reviewer)","parameters":[{"schema":{"type":"string","maxLength":100},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"required":false,"name":"target_type","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"value","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"target_id","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar vote + meta cursor","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":26,"maxLength":26},"voter_id":{"type":"string","minLength":26,"maxLength":26},"voter_username":{"type":"string"},"voter_email":{"type":"string","format":"email"},"target_type":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"target_id":{"type":"string","minLength":26,"maxLength":26},"target_preview":{"type":"string","nullable":true},"value":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[-1]}]},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","voter_id","voter_username","voter_email","target_type","target_id","target_preview","value","created_at","updated_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"400":{"description":"Query params tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan (hanya root/admin/reviewer)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/votes/reset-target":{"delete":{"tags":["Admin Votes"],"summary":"Reset SEMUA vote untuk target tertentu (anti-brigading massal)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"target_type":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"target_id":{"type":"string","minLength":26,"maxLength":26}},"required":["target_type","target_id"]}}}},"responses":{"200":{"description":"Reset target sukses, return jumlah vote yang dihapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"target_type":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"target_id":{"type":"string","minLength":26,"maxLength":26},"deleted_count":{"type":"integer","minimum":0}},"required":["target_type","target_id","deleted_count"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/votes/top-targets":{"get":{"tags":["Admin Votes"],"summary":"Top targets terurut skor bersih (net = upvotes-downvotes) desc","parameters":[{"schema":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"],"default":"word"},"required":false,"name":"target_type","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":20},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Daftar top targets per type","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"target_type":{"type":"string","enum":["word","meaning","example","pronunciation","word_image","comment","translation_help_reply","translation_help"]},"target_id":{"type":"string","minLength":26,"maxLength":26},"target_preview":{"type":"string","nullable":true},"upvotes":{"type":"integer","minimum":0},"downvotes":{"type":"integer","minimum":0},"net":{"type":"integer"}},"required":["target_type","target_id","target_preview","upvotes","downvotes","net"]}}},"required":["success","data"]}}}},"400":{"description":"Query params tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/votes/:id":{"delete":{"tags":["Admin Votes"],"summary":"Hapus satu vote individual by id (root/admin/reviewer)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Vote berhasil dihapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Vote tidak ditemukan (VOTE_NOT_FOUND)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/contributions":{"get":{"tags":["Contributions","Admin"],"summary":"Antrean review kontribusi (filter status/entity_type) - cursor pagination","parameters":[{"schema":{"type":"string","enum":["pending","approved","rejected","corrected"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","enum":["word","pronunciation","word_image","word_audio","example","meaning"]},"required":false,"name":"entity_type","in":"query"},{"schema":{"type":"string","minLength":1},"required":false,"name":"action","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"word_id","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar kontribusi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"contributor_username":{"type":"string","nullable":true},"entity_type":{"type":"string","enum":["word","pronunciation","word_image","word_audio","example","meaning"]},"entity_id":{"type":"string"},"action":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected","corrected"]},"created_at":{"type":"string"},"word_lemma":{"type":"string","nullable":true},"search_miss_id":{"type":"string","nullable":true},"search_miss_term":{"type":"string","nullable":true},"search_miss_direction":{"type":"string","nullable":true,"enum":["lemma","translation",null]}},"required":["id","user_id","contributor_username","entity_type","entity_id","action","status","created_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator (admin/root/reviewer)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/contributions/:id":{"get":{"tags":["Contributions","Admin"],"summary":"Detail kontribusi + payload entity utuh untuk layar review","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail kontribusi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"contribution":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"contributor_username":{"type":"string","nullable":true},"entity_type":{"type":"string","enum":["word","pronunciation","word_image","word_audio","example","meaning"]},"entity_id":{"type":"string"},"action":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected","corrected"]},"created_at":{"type":"string"},"word_lemma":{"type":"string","nullable":true},"search_miss_id":{"type":"string","nullable":true},"search_miss_term":{"type":"string","nullable":true},"search_miss_direction":{"type":"string","nullable":true,"enum":["lemma","translation",null]}},"required":["id","user_id","contributor_username","entity_type","entity_id","action","status","created_at"]},"review":{"type":"object","nullable":true,"properties":{"reviewer_id":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","approved","rejected","corrected"]},"comment":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["reviewer_id","status","comment","created_at"]},"entity":{"nullable":true}},"required":["contribution","review"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kontribusi tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/contributions/:id/approve":{"post":{"tags":["Contributions","Admin"],"summary":"Setujui kontribusi - entity published + is_verified true. JSON atau multipart (file_<imageId> sensor opsional)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"comment":{"type":"string","maxLength":2000},"image_decisions":{"type":"array","items":{"type":"object","properties":{"image_id":{"type":"string","minLength":26,"maxLength":26},"decision":{"type":"string","enum":["approve","reject"]}},"required":["image_id","decision"]},"maxItems":10}}}}}},"responses":{"200":{"description":"Kontribusi disetujui","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"contribution_id":{"type":"string"},"entity_type":{"type":"string","enum":["word","pronunciation","word_image","word_audio","example","meaning"]},"entity_id":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected","corrected"]},"is_corrected":{"type":"boolean"},"merged_into_word_id":{"type":"string"}},"required":["contribution_id","entity_type","entity_id","status"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kontribusi tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Sudah ada keputusan review","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/contributions/:id/reject":{"post":{"tags":["Contributions","Admin"],"summary":"Tolak kontribusi - comment (alasan) WAJIB, entity rejected","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"comment":{"type":"string","minLength":1,"maxLength":2000}},"required":["comment"]}}}},"responses":{"200":{"description":"Kontribusi ditolak","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"contribution_id":{"type":"string"},"entity_type":{"type":"string","enum":["word","pronunciation","word_image","word_audio","example","meaning"]},"entity_id":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected","corrected"]},"is_corrected":{"type":"boolean"},"merged_into_word_id":{"type":"string"}},"required":["contribution_id","entity_type","entity_id","status"]}},"required":["success","data"]}}}},"400":{"description":"comment wajib diisi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kontribusi tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Sudah ada keputusan review","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/contributions/:id/correct":{"post":{"tags":["Contributions","Admin"],"summary":"Koreksi kontribusi oleh verifikator - is_corrected true, lalu published","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"lemma":{"type":"string","minLength":1,"maxLength":255},"lemma_allows_comma":{"type":"boolean","default":false},"notes":{"type":"string"},"meanings":{"type":"array","items":{"type":"object","properties":{"word_class_id":{"type":"string","minLength":26,"maxLength":26},"definition":{"type":"string","minLength":1},"is_have_definition":{"type":"boolean","default":true},"is_have_translation":{"type":"boolean","default":true},"order_index":{"type":"integer","minimum":1,"default":1},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text"]},"default":[]},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]}},"required":["source_language_id","source_sentence"]}}},"required":["word_class_id","definition"]},"minItems":1},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"],"default":"word"},"usage_labels":{"type":"array","items":{"type":"string","enum":["kasar","tabu","informal","halus","seksual","diskriminatif"]},"default":[]},"category_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"default":[]},"related_words":{"type":"array","items":{"type":"object","properties":{"relation_type":{"type":"string","enum":["synonym","antonym","has_component","derived_from"]},"word_id":{"type":"string","minLength":26,"maxLength":26},"word":{"type":"object","properties":{"lemma":{"type":"string","minLength":1,"maxLength":255},"notes":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"],"default":"word"},"usage_labels":{"type":"array","items":{"type":"string","enum":["kasar","tabu","informal","halus","seksual","diskriminatif"]},"default":[]},"category_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"default":[]},"inherit_meanings":{"type":"boolean","default":true},"meaning_overrides":{"type":"array","items":{"type":"object","properties":{"meaning_index":{"type":"integer","nullable":true,"minimum":0},"definition":{"type":"string","minLength":1},"word_class_id":{"type":"string","minLength":26,"maxLength":26},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"}},"required":["language_id","translation_text"]}},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]}},"required":["source_language_id","source_sentence"]}}},"required":["meaning_index"]},"maxItems":20},"meanings":{"type":"array","items":{"type":"object","properties":{"word_class_id":{"type":"string","minLength":26,"maxLength":26},"definition":{"type":"string","minLength":1},"is_have_definition":{"type":"boolean","default":true},"is_have_translation":{"type":"boolean","default":true},"order_index":{"type":"integer","minimum":1,"default":1},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text"]},"default":[]},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]}},"required":["source_language_id","source_sentence"]}}},"required":["word_class_id","definition"]},"minItems":1},"variants":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string","minLength":1,"maxLength":255},"variant_type":{"type":"string","enum":["inflection","derivation","alternative","reduplication"],"default":"alternative"},"affix_type":{"type":"string","enum":["prefix","suffix","circumfix","reduplication"]},"affix_value":{"type":"string","maxLength":50},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"notes":{"type":"string","maxLength":1000}},"required":["form"]},"maxItems":20},"pronunciation":{"type":"object","properties":{"notation":{"type":"string","minLength":1,"default":"ipa"},"value":{"type":"string","minLength":1}},"required":["value"]},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1},"sha":{"type":"string","minLength":1,"maxLength":128},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean","default":false},"content_warnings":{"type":"array","items":{"type":"string","enum":["kekerasan"]},"default":[]}},"required":["url","provider_file_id"]},"maxItems":10},"status":{"type":"string","enum":["draft","published"]}},"required":["lemma"]}},"required":["relation_type"]},"default":[]},"variants":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string","minLength":1,"maxLength":255},"variant_type":{"type":"string","enum":["inflection","derivation","alternative","reduplication"],"default":"alternative"},"affix_type":{"type":"string","enum":["prefix","suffix","circumfix","reduplication"]},"affix_value":{"type":"string","maxLength":50},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"notes":{"type":"string","maxLength":1000}},"required":["form"]},"maxItems":20},"pronunciation":{"type":"object","properties":{"notation":{"type":"string","minLength":1,"default":"ipa"},"value":{"type":"string","minLength":1}},"required":["value"]},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1},"sha":{"type":"string","minLength":1,"maxLength":128},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean","default":false},"content_warnings":{"type":"array","items":{"type":"string","enum":["kekerasan"]},"default":[]}},"required":["url","provider_file_id"]},"maxItems":10},"search_miss_id":{"type":"string","minLength":26,"maxLength":26},"entity_type":{"type":"string","enum":["word"]},"comment":{"type":"string","maxLength":2000},"publish":{"type":"boolean","default":true}},"required":["language_id","lemma","meanings","entity_type"]},{"type":"object","properties":{"dialect_id":{"type":"string","minLength":26,"maxLength":26},"notation":{"type":"string","minLength":1,"default":"ipa"},"value":{"type":"string","minLength":1,"maxLength":500},"audio_url":{"type":"string","format":"uri"},"speaker_name":{"type":"string","maxLength":255},"notes":{"type":"string"},"entity_type":{"type":"string","enum":["pronunciation"]},"comment":{"type":"string","maxLength":2000},"publish":{"type":"boolean","default":true}},"required":["value","entity_type"]},{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1},"sha":{"type":"string","minLength":1,"maxLength":128},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean","default":false},"content_warnings":{"type":"array","items":{"type":"string","enum":["kekerasan"]},"default":[]},"entity_type":{"type":"string","enum":["word_image"]},"comment":{"type":"string","maxLength":2000},"publish":{"type":"boolean","default":true}},"required":["url","provider_file_id","entity_type"]},{"type":"object","properties":{"entity_type":{"type":"string","enum":["word_audio"]},"comment":{"type":"string","maxLength":2000},"publish":{"type":"boolean","default":true},"speaker_name":{"type":"string","nullable":true,"maxLength":255},"dialect_id":{"type":"string","nullable":true,"minLength":26,"maxLength":26},"is_primary":{"type":"boolean","default":false}},"required":["entity_type"]},{"type":"object","properties":{"entity_type":{"type":"string","enum":["example"]},"comment":{"type":"string","maxLength":2000},"publish":{"type":"boolean","default":true},"source_sentence":{"type":"string","minLength":1},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]},"notes":{"type":"string"}},"required":["entity_type","source_sentence"]}]}}}},"responses":{"200":{"description":"Kontribusi dikoreksi & dipublikasikan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"contribution_id":{"type":"string"},"entity_type":{"type":"string","enum":["word","pronunciation","word_image","word_audio","example","meaning"]},"entity_id":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected","corrected"]},"is_corrected":{"type":"boolean"},"merged_into_word_id":{"type":"string"}},"required":["contribution_id","entity_type","entity_id","status"]}},"required":["success","data"]}}}},"400":{"description":"entity_type tidak cocok / body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Kontribusi tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Sudah ada keputusan review","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/contributions/words":{"post":{"tags":["Contributions"],"summary":"Submit kata (publik). Tanpa login → anonim; dengan Bearer → atribusi user login","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"lemma":{"type":"string","minLength":1,"maxLength":255},"lemma_allows_comma":{"type":"boolean","default":false},"notes":{"type":"string"},"meanings":{"type":"array","items":{"type":"object","properties":{"word_class_id":{"type":"string","minLength":26,"maxLength":26},"definition":{"type":"string","minLength":1},"is_have_definition":{"type":"boolean","default":true},"is_have_translation":{"type":"boolean","default":true},"order_index":{"type":"integer","minimum":1,"default":1},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text"]},"default":[]},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]}},"required":["source_language_id","source_sentence"]}}},"required":["word_class_id","definition"]},"minItems":1},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"],"default":"word"},"usage_labels":{"type":"array","items":{"type":"string","enum":["kasar","tabu","informal","halus","seksual","diskriminatif"]},"default":[]},"category_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"default":[]},"related_words":{"type":"array","items":{"type":"object","properties":{"relation_type":{"type":"string","enum":["synonym","antonym","has_component","derived_from"]},"word_id":{"type":"string","minLength":26,"maxLength":26},"word":{"type":"object","properties":{"lemma":{"type":"string","minLength":1,"maxLength":255},"notes":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"],"default":"word"},"usage_labels":{"type":"array","items":{"type":"string","enum":["kasar","tabu","informal","halus","seksual","diskriminatif"]},"default":[]},"category_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"default":[]},"inherit_meanings":{"type":"boolean","default":true},"meaning_overrides":{"type":"array","items":{"type":"object","properties":{"meaning_index":{"type":"integer","nullable":true,"minimum":0},"definition":{"type":"string","minLength":1},"word_class_id":{"type":"string","minLength":26,"maxLength":26},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"}},"required":["language_id","translation_text"]}},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]}},"required":["source_language_id","source_sentence"]}}},"required":["meaning_index"]},"maxItems":20},"meanings":{"type":"array","items":{"type":"object","properties":{"word_class_id":{"type":"string","minLength":26,"maxLength":26},"definition":{"type":"string","minLength":1},"is_have_definition":{"type":"boolean","default":true},"is_have_translation":{"type":"boolean","default":true},"order_index":{"type":"integer","minimum":1,"default":1},"translations":{"type":"array","items":{"type":"object","properties":{"language_id":{"type":"string","minLength":26,"maxLength":26},"translation_text":{"type":"string","minLength":1},"translation_type":{"type":"string","enum":["direct","descriptive","idiomatic"],"default":"direct"},"translation_allows_comma":{"type":"boolean","default":false}},"required":["language_id","translation_text"]},"default":[]},"examples":{"type":"array","items":{"type":"object","properties":{"source_language_id":{"type":"string","minLength":26,"maxLength":26},"source_sentence":{"type":"string","minLength":1},"target_language_id":{"type":"string","minLength":26,"maxLength":26},"target_sentence":{"type":"string"},"source_type":{"type":"string","enum":["native_speaker","book","corpus","interview","other"]}},"required":["source_language_id","source_sentence"]}}},"required":["word_class_id","definition"]},"minItems":1},"variants":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string","minLength":1,"maxLength":255},"variant_type":{"type":"string","enum":["inflection","derivation","alternative","reduplication"],"default":"alternative"},"affix_type":{"type":"string","enum":["prefix","suffix","circumfix","reduplication"]},"affix_value":{"type":"string","maxLength":50},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"notes":{"type":"string","maxLength":1000}},"required":["form"]},"maxItems":20},"pronunciation":{"type":"object","properties":{"notation":{"type":"string","minLength":1,"default":"ipa"},"value":{"type":"string","minLength":1}},"required":["value"]},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1},"sha":{"type":"string","minLength":1,"maxLength":128},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean","default":false},"content_warnings":{"type":"array","items":{"type":"string","enum":["kekerasan"]},"default":[]}},"required":["url","provider_file_id"]},"maxItems":10},"status":{"type":"string","enum":["draft","published"]}},"required":["lemma"]}},"required":["relation_type"]},"default":[]},"variants":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string","minLength":1,"maxLength":255},"variant_type":{"type":"string","enum":["inflection","derivation","alternative","reduplication"],"default":"alternative"},"affix_type":{"type":"string","enum":["prefix","suffix","circumfix","reduplication"]},"affix_value":{"type":"string","maxLength":50},"dialect_id":{"type":"string","minLength":26,"maxLength":26},"notes":{"type":"string","maxLength":1000}},"required":["form"]},"maxItems":20},"pronunciation":{"type":"object","properties":{"notation":{"type":"string","minLength":1,"default":"ipa"},"value":{"type":"string","minLength":1}},"required":["value"]},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["pexels","pixabay","openverse","wikimedia","unsplash","github","imagekit"]},"provider_file_id":{"type":"string","minLength":1},"sha":{"type":"string","minLength":1,"maxLength":128},"alt_text":{"type":"string","maxLength":500},"is_primary":{"type":"boolean","default":false},"content_warnings":{"type":"array","items":{"type":"string","enum":["kekerasan"]},"default":[]}},"required":["url","provider_file_id"]},"maxItems":10},"search_miss_id":{"type":"string","minLength":26,"maxLength":26}},"required":["language_id","lemma","meanings"]}}}},"responses":{"201":{"description":"Kontribusi tersimpan (selalu pending_review untuk non-verifier)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"created_at":{"type":"string"},"search_miss_id":{"type":"string","nullable":true},"warnings":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},"inline_created_words":{"type":"array","items":{"type":"object","properties":{"word_id":{"type":"string"},"lemma":{"type":"string"},"relation_type":{"type":"string","enum":["synonym","antonym","has_component","derived_from"]},"word_type":{"type":"string","enum":["word","idiom","peribahasa","ungkapan"]},"status":{"type":"string","enum":["draft","pending_review","published","rejected","taken_down"]},"is_verified":{"type":"boolean"},"meanings_count":{"type":"integer"},"inherited_meanings_count":{"type":"integer"},"overridden_meanings_count":{"type":"integer"},"warnings":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["word_id","lemma","relation_type","word_type","status","is_verified","meanings_count","inherited_meanings_count","overridden_meanings_count"]}}},"required":["word_id","lemma","word_type","status","is_verified","created_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid / referensi id tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Bearer ada tapi invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/contributions/my":{"get":{"tags":["Contributions"],"summary":"Daftar kontribusi + usulan perubahan milik user login","parameters":[{"schema":{"type":"string","enum":["pending","approved","rejected","corrected"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar milik pemohon","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["contribution","suggestion"]},"entity_type":{"type":"string","enum":["word","pronunciation","word_image","word_audio","example","meaning","word_suggestion"]},"lemma":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","approved","rejected","corrected"]},"created_at":{"type":"string"},"review_comment":{"type":"string","nullable":true},"word_id":{"type":"string","nullable":true},"action":{"type":"string","nullable":true},"reason":{"type":"string","nullable":true},"reason_code":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true}},"required":["id","kind","entity_type","lemma","status","created_at","review_comment","word_id"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/contributions/my/:kind/:id":{"get":{"tags":["Contributions"],"summary":"Detail satu usulan milik user login","parameters":[{"schema":{"type":"string","enum":["contribution","suggestion"]},"required":true,"name":"kind","in":"path"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail milik pemohon","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["contribution","suggestion"]},"entity_type":{"type":"string","enum":["word","pronunciation","word_image","word_audio","example","meaning","word_suggestion"]},"lemma":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","approved","rejected","corrected"]},"created_at":{"type":"string"},"review_comment":{"type":"string","nullable":true},"word_id":{"type":"string","nullable":true},"action":{"type":"string","nullable":true},"reason":{"type":"string","nullable":true},"reason_code":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true}},"required":["id","kind","entity_type","lemma","status","created_at","review_comment","word_id"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Tidak ditemukan atau bukan milik pemohon","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/search-misses":{"get":{"tags":["Search Misses"],"summary":"Pencarian kosong terpopuler - peluang kontribusi untuk beranda (hanya yang tayang)","parameters":[{"schema":{"type":"string","enum":["lemma","translation"]},"required":false,"name":"direction","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":10},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Daftar miss belum terjawab + tayang (paling dicari)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"term":{"type":"string"},"direction":{"type":"string","enum":["lemma","translation"]},"hit_count":{"type":"integer"},"last_searched_at":{"type":"string"},"is_fulfilled":{"type":"boolean"},"is_visible":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","term","direction","hit_count","last_searched_at","is_fulfilled","is_visible","created_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"400":{"description":"Query tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/search-misses":{"get":{"tags":["Search Misses","Admin"],"summary":"Panel admin: semua pencarian kosong + status terjawab/tayang (cursor pagination)","parameters":[{"schema":{"type":"string","enum":["lemma","translation"]},"required":false,"name":"direction","in":"query"},{"schema":{"type":"boolean","nullable":true},"required":false,"name":"fulfilled","in":"query"},{"schema":{"type":"boolean","nullable":true},"required":false,"name":"visible","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar miss","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"term":{"type":"string"},"direction":{"type":"string","enum":["lemma","translation"]},"hit_count":{"type":"integer"},"last_searched_at":{"type":"string"},"is_fulfilled":{"type":"boolean"},"is_visible":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","term","direction","hit_count","last_searched_at","is_fulfilled","is_visible","created_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/search-misses/:id":{"patch":{"tags":["Search Misses","Admin"],"summary":"Koreksi term dan/atau toggle tayang beranda (14-api)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"term":{"type":"string","minLength":1,"maxLength":255},"is_visible":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Miss diperbarui","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"term":{"type":"string"},"direction":{"type":"string","enum":["lemma","translation"]},"hit_count":{"type":"integer"},"last_searched_at":{"type":"string"},"is_fulfilled":{"type":"boolean"},"is_visible":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","term","direction","hit_count","last_searched_at","is_fulfilled","is_visible","created_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Miss tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Term bentrok unique","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/search-misses/:id/dismiss":{"post":{"tags":["Search Misses","Admin"],"summary":"Singkirkan miss dari panel/beranda (spam / tidak layak) - soft delete","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Miss disembunyikan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Miss tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/search-misses/:id/resolve":{"post":{"tags":["Search Misses","Admin"],"summary":"Selesaikan miss: tempel sebagai varian/sinonim (lemma) atau terjemahan (translation) ke kata existing","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["variant","synonym","translation"]},"word_id":{"type":"string","minLength":26,"maxLength":26},"meaning_id":{"type":"string","minLength":26,"maxLength":26}},"required":["action","word_id"]}}}},"responses":{"200":{"description":"Miss diselesaikan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"term":{"type":"string"},"direction":{"type":"string","enum":["lemma","translation"]},"hit_count":{"type":"integer"},"last_searched_at":{"type":"string"},"is_fulfilled":{"type":"boolean"},"is_visible":{"type":"boolean"},"created_at":{"type":"string"},"resolved_as":{"type":"string","enum":["variant","synonym","translation"]},"target_word_id":{"type":"string"},"created_word_id":{"type":"string","nullable":true},"variant_id":{"type":"string","nullable":true}},"required":["id","term","direction","hit_count","last_searched_at","is_fulfilled","is_visible","created_at","resolved_as","target_word_id","created_word_id","variant_id"]}},"required":["success","data"]}}}},"400":{"description":"Body/arah tidak cocok","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Miss atau kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Varian/lemma/terjemahan bentrok","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/languages":{"get":{"tags":["Languages"],"summary":"Daftar bahasa (dropdown form admin)","parameters":[{"schema":{"type":"boolean","nullable":true,"default":true},"required":false,"name":"is_active","in":"query"}],"responses":{"200":{"description":"Daftar bahasa","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"native_name":{"type":"string","nullable":true},"is_active":{"type":"boolean"}},"required":["id","code","name","native_name","is_active"]}}},"required":["success","data"]}}}}}}},"/api/v1/dialects":{"get":{"tags":["Languages"],"summary":"Daftar dialek per bahasa (dropdown form admin)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"language_id","in":"query"}],"responses":{"200":{"description":"Daftar dialek","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"language_id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"is_active":{"type":"boolean"},"is_default":{"type":"boolean"}},"required":["id","language_id","code","name","is_active","is_default"]}}},"required":["success","data"]}}}},"400":{"description":"Query tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"nullable":true}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/categories":{"get":{"tags":["Categories"],"summary":"Daftar kategori/glosarium (multi-select form admin)","responses":{"200":{"description":"Daftar kategori","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"parent_id":{"type":"string","nullable":true},"name":{"type":"string"},"description":{"type":"string","nullable":true}},"required":["id","parent_id","name","description"]}}},"required":["success","data"]}}}}}}},"/api/v1/admin/audit-logs":{"get":{"tags":["Audit"],"summary":"Jejak audit mutasi data (auditor: admin & root)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"user_id","in":"query"},{"schema":{"type":"string","maxLength":100},"required":false,"name":"user_name","in":"query"},{"schema":{"type":"string","maxLength":50},"required":false,"name":"action","in":"query"},{"schema":{"type":"string","maxLength":100},"required":false,"name":"entity_type","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"entity_id","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"to","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar audit log + meta","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string","nullable":true},"user_name":{"type":"string","nullable":true},"action":{"type":"string"},"entity_type":{"type":"string"},"entity_id":{"type":"string"},"old_data":{"type":"object","nullable":true,"additionalProperties":{"nullable":true}},"new_data":{"type":"object","nullable":true,"additionalProperties":{"nullable":true}},"request_id":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","user_id","user_name","action","entity_type","entity_id","old_data","new_data","request_id","created_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan (hanya admin/root)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/images/upload-token":{"get":{"tags":["Images"],"summary":"Kredensial direct-upload ke provider gambar (client upload sendiri ke CDN)","parameters":[{"schema":{"type":"string","maxLength":255},"required":false,"name":"folder","in":"query"}],"responses":{"200":{"description":"Token + signature upload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"token":{"type":"string"},"signature":{"type":"string"},"expire":{"type":"integer"},"public_key":{"type":"string"},"upload_endpoint":{"type":"string"}},"required":["token","signature","expire","public_key","upload_endpoint"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"503":{"description":"Provider gambar belum dikonfigurasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/bug-reports/upload-token":{"get":{"tags":["Bug Reports"],"summary":"Kredensial direct-upload ImageKit, folder hanya /bug-reports (publik)","parameters":[{"schema":{"type":"string"},"required":true,"name":"folder","in":"query"}],"responses":{"200":{"description":"Token + signature upload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"token":{"type":"string"},"signature":{"type":"string"},"expire":{"type":"integer"},"public_key":{"type":"string"},"upload_endpoint":{"type":"string"}},"required":["token","signature","expire","public_key","upload_endpoint"]}},"required":["success","data"]}}}},"400":{"description":"Folder bukan /bug-reports","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Rate limit","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"503":{"description":"Provider gambar belum dikonfigurasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/bug-reports":{"post":{"tags":["Bug Reports"],"summary":"Kirim laporan masalah (auth opsional: tamu atau login)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string","minLength":10,"maxLength":2000},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider_file_id":{"type":"string","minLength":1}},"required":["url","provider_file_id"]},"maxItems":4,"default":[]},"app_version":{"type":"string","nullable":true,"maxLength":20},"platform":{"type":"string","nullable":true,"enum":["android","ios",null]}},"required":["description"]}}}},"responses":{"200":{"description":"Laporan tersimpan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["open"]},"submitted_at":{"type":"string"},"is_anonymous":{"type":"boolean"}},"required":["id","status","submitted_at","is_anonymous"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Bearer ada tapi invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Rate limit","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/bug-reports":{"get":{"tags":["Bug Reports","Admin"],"summary":"Antrean laporan masalah (admin/root, cursor)","parameters":[{"schema":{"type":"string","enum":["open","resolved","rejected"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar laporan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string","nullable":true},"username":{"type":"string","nullable":true},"device_id":{"type":"string","nullable":true},"description":{"type":"string"},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"}},"required":["url","provider_file_id"]}},"app_version":{"type":"string","nullable":true},"platform":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","resolved","rejected"]},"resolution_note":{"type":"string","nullable":true},"resolved_by":{"type":"string","nullable":true},"resolved_at":{"type":"string","nullable":true},"created_by":{"type":"string","nullable":true},"updated_by":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","user_id","username","device_id","description","images","app_version","platform","status","resolution_note","resolved_by","resolved_at","created_by","updated_by","created_at","updated_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan admin/root","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/bug-reports/:id/resolve":{"post":{"tags":["Bug Reports","Admin"],"summary":"Selesaikan atau tolak laporan (terminal)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["resolved","rejected"]},"note":{"type":"string","nullable":true,"maxLength":2000}},"required":["status"]}}}},"responses":{"200":{"description":"Laporan diperbarui","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string","nullable":true},"username":{"type":"string","nullable":true},"device_id":{"type":"string","nullable":true},"description":{"type":"string"},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"}},"required":["url","provider_file_id"]}},"app_version":{"type":"string","nullable":true},"platform":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","resolved","rejected"]},"resolution_note":{"type":"string","nullable":true},"resolved_by":{"type":"string","nullable":true},"resolved_at":{"type":"string","nullable":true},"created_by":{"type":"string","nullable":true},"updated_by":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","user_id","username","device_id","description","images","app_version","platform","status","resolution_note","resolved_by","resolved_at","created_by","updated_by","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan admin/root","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Laporan tidak ditemukan / sudah selesai","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/translation-helps/upload-token":{"get":{"tags":["Translation Helps"],"summary":"Kredensial direct-upload ImageKit, folder hanya /translation-helps (login)","parameters":[{"schema":{"type":"string"},"required":true,"name":"folder","in":"query"}],"responses":{"200":{"description":"Token + signature upload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"token":{"type":"string"},"signature":{"type":"string"},"expire":{"type":"integer"},"public_key":{"type":"string"},"upload_endpoint":{"type":"string"}},"required":["token","signature","expire","public_key","upload_endpoint"]}},"required":["success","data"]}}}},"400":{"description":"Folder bukan /translation-helps","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Rate limit","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"503":{"description":"Provider gambar belum dikonfigurasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/translation-helps":{"post":{"tags":["Translation Helps"],"summary":"Kirim permintaan bantuan terjemahan (wajib login)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","nullable":true,"minLength":1,"maxLength":1000},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider_file_id":{"type":"string","minLength":1}},"required":["url","provider_file_id"]},"maxItems":4,"default":[]}}}}}},"responses":{"200":{"description":"Tersimpan pending_review","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["pending_review"]},"submitted_at":{"type":"string"}},"required":["id","status","submitted_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Rate limit","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"get":{"tags":["Translation Helps"],"summary":"Feed bantuan terjemahan yang tayang (publik)","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":200},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","enum":["latest","popular"],"default":"latest"},"required":false,"name":"sort","in":"query"}],"responses":{"200":{"description":"Daftar published","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"object","properties":{"public_url":{"type":"string"}},"required":["public_url"]}},"status":{"type":"string","enum":["published"]},"pinned_reply_id":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"created_at":{"type":"string"}},"required":["id","user_id","username","body","images","status","pinned_reply_id","upvotes","created_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}}}}},"/api/v1/translation-helps/my":{"get":{"tags":["Translation Helps"],"summary":"Riwayat permintaan bantuan saya","parameters":[{"schema":{"type":"string","enum":["pending_review","published","rejected","taken_down"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar milik user","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"},"public_url":{"type":"string","nullable":true}},"required":["url","provider_file_id","public_url"]}},"status":{"type":"string","enum":["pending_review","published","rejected","taken_down"]},"rejection_note":{"type":"string","nullable":true},"pinned_reply_id":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","user_id","username","body","images","status","rejection_note","pinned_reply_id","reviewed_at","upvotes","created_at","updated_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/translation-helps/:id":{"get":{"tags":["Translation Helps"],"summary":"Detail bantuan (published publik; pending/rejected hanya pemilik)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"object","properties":{"public_url":{"type":"string"}},"required":["public_url"]}},"status":{"type":"string","enum":["published"]},"pinned_reply_id":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"created_at":{"type":"string"},"replies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"status":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"is_verifier":{"type":"boolean"},"is_pinned":{"type":"boolean"},"upvotes":{"type":"integer"},"downvotes":{"type":"integer"},"created_at":{"type":"string"}},"required":["id","user_id","username","body","status","is_verifier","is_pinned","upvotes","downvotes","created_at"]}}},"required":["id","user_id","username","body","images","status","pinned_reply_id","upvotes","created_at","replies"]}},"required":["success","data"]},{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"},"public_url":{"type":"string","nullable":true}},"required":["url","provider_file_id","public_url"]}},"status":{"type":"string","enum":["pending_review","published","rejected","taken_down"]},"rejection_note":{"type":"string","nullable":true},"pinned_reply_id":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true},"replies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"status":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"is_verifier":{"type":"boolean"},"is_pinned":{"type":"boolean"},"upvotes":{"type":"integer"},"downvotes":{"type":"integer"},"created_at":{"type":"string"}},"required":["id","user_id","username","body","status","is_verifier","is_pinned","upvotes","downvotes","created_at"]}}},"required":["id","user_id","username","body","images","status","rejection_note","pinned_reply_id","reviewed_at","upvotes","created_at","updated_at","replies"]}},"required":["success","data"]}]}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/translation-helps/:id/replies":{"post":{"tags":["Translation Helps"],"summary":"Balas bantuan yang sudah tayang (login)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":500}},"required":["body"]}}}},"responses":{"201":{"description":"Balasan tersimpan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"status":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"is_verifier":{"type":"boolean"},"is_pinned":{"type":"boolean"},"upvotes":{"type":"integer"},"downvotes":{"type":"integer"},"created_at":{"type":"string"}},"required":["id","user_id","username","body","status","is_verifier","is_pinned","upvotes","downvotes","created_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Bantuan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Bantuan belum tayang","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/translation-helps/replies/:id":{"delete":{"tags":["Translation Helps"],"summary":"Hapus balasan sendiri","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Dihapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan penulis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Balasan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/translation-helps":{"get":{"tags":["Translation Helps","Admin"],"summary":"Antrean bantuan terjemahan (filter status)","parameters":[{"schema":{"type":"string","enum":["pending_review","published","rejected","taken_down"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"},"public_url":{"type":"string","nullable":true}},"required":["url","provider_file_id","public_url"]}},"status":{"type":"string","enum":["pending_review","published","rejected","taken_down"]},"rejection_note":{"type":"string","nullable":true},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"pinned_reply_id":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","user_id","username","body","images","status","rejection_note","reviewed_by","reviewed_at","pinned_reply_id","upvotes","created_at","updated_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/translation-helps/:id":{"get":{"tags":["Translation Helps","Admin"],"summary":"Detail admin (termasuk URL ImageKit staging saat pending)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"},"public_url":{"type":"string","nullable":true}},"required":["url","provider_file_id","public_url"]}},"status":{"type":"string","enum":["pending_review","published","rejected","taken_down"]},"rejection_note":{"type":"string","nullable":true},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"pinned_reply_id":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true},"replies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"status":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"is_verifier":{"type":"boolean"},"is_pinned":{"type":"boolean"},"upvotes":{"type":"integer"},"downvotes":{"type":"integer"},"created_at":{"type":"string"},"body_original":{"type":"string","nullable":true},"is_censored":{"type":"boolean"},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true}},"required":["id","user_id","username","body","status","is_verifier","is_pinned","upvotes","downvotes","created_at","body_original","is_censored","reviewed_by","reviewed_at"]}}},"required":["id","user_id","username","body","images","status","rejection_note","reviewed_by","reviewed_at","pinned_reply_id","upvotes","created_at","updated_at","replies"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/translation-helps/:id/approve":{"post":{"tags":["Translation Helps","Admin"],"summary":"Setujui & tayangkan: multipart file_0.. / file opsional (sensor), atau JSON tanpa file","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{},"additionalProperties":{"nullable":true}}},"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Tayang","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"},"public_url":{"type":"string","nullable":true}},"required":["url","provider_file_id","public_url"]}},"status":{"type":"string","enum":["pending_review","published","rejected","taken_down"]},"rejection_note":{"type":"string","nullable":true},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"pinned_reply_id":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","user_id","username","body","images","status","rejection_note","reviewed_by","reviewed_at","pinned_reply_id","upvotes","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"File/gambar tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Tidak ditemukan / bukan pending","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/translation-helps/:id/reject":{"post":{"tags":["Translation Helps","Admin"],"summary":"Tolak (note wajib); hapus ImageKit","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","minLength":1,"maxLength":2000}},"required":["note"]}}}},"responses":{"200":{"description":"Ditolak","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"},"public_url":{"type":"string","nullable":true}},"required":["url","provider_file_id","public_url"]}},"status":{"type":"string","enum":["pending_review","published","rejected","taken_down"]},"rejection_note":{"type":"string","nullable":true},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"pinned_reply_id":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","user_id","username","body","images","status","rejection_note","reviewed_by","reviewed_at","pinned_reply_id","upvotes","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Note wajib","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Tidak ditemukan / bukan pending","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/translation-helps/:id/takedown":{"post":{"tags":["Translation Helps","Admin"],"summary":"Tarik dari feed setelah tayang","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Di-takedown","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"},"public_url":{"type":"string","nullable":true}},"required":["url","provider_file_id","public_url"]}},"status":{"type":"string","enum":["pending_review","published","rejected","taken_down"]},"rejection_note":{"type":"string","nullable":true},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"pinned_reply_id":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","user_id","username","body","images","status","rejection_note","reviewed_by","reviewed_at","pinned_reply_id","upvotes","created_at","updated_at"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Tidak ditemukan / bukan published","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/translation-helps/:id/pin-reply":{"post":{"tags":["Translation Helps","Admin"],"summary":"Pin balasan terbaik","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reply_id":{"type":"string","minLength":26,"maxLength":26}},"required":["reply_id"]}}}},"responses":{"200":{"description":"Pinned","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"},"public_url":{"type":"string","nullable":true}},"required":["url","provider_file_id","public_url"]}},"status":{"type":"string","enum":["pending_review","published","rejected","taken_down"]},"rejection_note":{"type":"string","nullable":true},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"pinned_reply_id":{"type":"string","nullable":true},"upvotes":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","user_id","username","body","images","status","rejection_note","reviewed_by","reviewed_at","pinned_reply_id","upvotes","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"reply_id tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Help/reply tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/translation-helps/replies/:id/takedown":{"post":{"tags":["Translation Helps","Admin"],"summary":"Takedown balasan","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Balasan di-takedown","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"status":{"type":"string","enum":["published","taken_down","deleted_by_author"]},"is_verifier":{"type":"boolean"},"is_pinned":{"type":"boolean"},"upvotes":{"type":"integer"},"downvotes":{"type":"integer"},"created_at":{"type":"string"},"body_original":{"type":"string","nullable":true},"is_censored":{"type":"boolean"},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true}},"required":["id","user_id","username","body","status","is_verifier","is_pinned","upvotes","downvotes","created_at","body_original","is_censored","reviewed_by","reviewed_at"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan verifikator","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Balasan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-reports":{"get":{"tags":["Word Reports","Admin"],"summary":"Antrean laporan entri","parameters":[{"schema":{"type":"string","enum":["open","resolved"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar laporan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"image_id":{"type":"string","nullable":true},"lemma":{"type":"string"},"word_status":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"reason_code":{"type":"string","enum":["not_sambas","inaccurate","duplicate","inappropriate","spam","other","violent_image"]},"note":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","resolved"]},"resolution":{"type":"string","nullable":true,"enum":["dismissed","taken_down","corrected","flagged_image",null]},"resolution_note":{"type":"string","nullable":true},"resolved_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","word_id","image_id","lemma","word_status","user_id","username","reason_code","note","status","resolution","resolution_note","resolved_at","created_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-reports/:id":{"get":{"tags":["Word Reports","Admin"],"summary":"Detail satu laporan entri","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Laporan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"image_id":{"type":"string","nullable":true},"lemma":{"type":"string"},"word_status":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"reason_code":{"type":"string","enum":["not_sambas","inaccurate","duplicate","inappropriate","spam","other","violent_image"]},"note":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","resolved"]},"resolution":{"type":"string","nullable":true,"enum":["dismissed","taken_down","corrected","flagged_image",null]},"resolution_note":{"type":"string","nullable":true},"resolved_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","word_id","image_id","lemma","word_status","user_id","username","reason_code","note","status","resolution","resolution_note","resolved_at","created_at"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Laporan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-reports/:id/dismiss":{"post":{"tags":["Word Reports","Admin"],"summary":"Tolak laporan. Kata tetap tayang.","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":1000}}}}}},"responses":{"200":{"description":"Laporan ditutup","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"image_id":{"type":"string","nullable":true},"lemma":{"type":"string"},"word_status":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"reason_code":{"type":"string","enum":["not_sambas","inaccurate","duplicate","inappropriate","spam","other","violent_image"]},"note":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","resolved"]},"resolution":{"type":"string","nullable":true,"enum":["dismissed","taken_down","corrected","flagged_image",null]},"resolution_note":{"type":"string","nullable":true},"resolved_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","word_id","image_id","lemma","word_status","user_id","username","reason_code","note","status","resolution","resolution_note","resolved_at","created_at"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Laporan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Laporan sudah ditutup","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-reports/:id/mark-corrected":{"post":{"tags":["Word Reports","Admin"],"summary":"Tandai laporan selesai karena entri sudah diperbaiki. Kata tetap tayang.","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":1000}}}}}},"responses":{"200":{"description":"Laporan ditutup","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"image_id":{"type":"string","nullable":true},"lemma":{"type":"string"},"word_status":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"reason_code":{"type":"string","enum":["not_sambas","inaccurate","duplicate","inappropriate","spam","other","violent_image"]},"note":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","resolved"]},"resolution":{"type":"string","nullable":true,"enum":["dismissed","taken_down","corrected","flagged_image",null]},"resolution_note":{"type":"string","nullable":true},"resolved_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","word_id","image_id","lemma","word_status","user_id","username","reason_code","note","status","resolution","resolution_note","resolved_at","created_at"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Laporan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Laporan sudah ditutup","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-reports/:id/takedown":{"post":{"tags":["Word Reports","Admin"],"summary":"Tarik entri dan tutup semua laporan terbuka pada kata itu","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason_code":{"type":"string","enum":["not_sambas","inaccurate","duplicate","inappropriate","spam","other"]},"note":{"type":"string","maxLength":1000}},"required":["reason_code"]}}}},"responses":{"200":{"description":"Entri ditarik","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"image_id":{"type":"string","nullable":true},"lemma":{"type":"string"},"word_status":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"reason_code":{"type":"string","enum":["not_sambas","inaccurate","duplicate","inappropriate","spam","other","violent_image"]},"note":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","resolved"]},"resolution":{"type":"string","nullable":true,"enum":["dismissed","taken_down","corrected","flagged_image",null]},"resolution_note":{"type":"string","nullable":true},"resolved_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","word_id","image_id","lemma","word_status","user_id","username","reason_code","note","status","resolution","resolution_note","resolved_at","created_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Laporan atau kata tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Laporan sudah ditutup atau kata bukan published","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/word-reports/:id/flag-violent-image":{"post":{"tags":["Word Reports","Admin"],"summary":"Tandai foto berisi kekerasan (blur) dan tutup laporan. Kata tetap tayang.","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":1000}}}}}},"responses":{"200":{"description":"Foto ditandai kekerasan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"word_id":{"type":"string"},"image_id":{"type":"string","nullable":true},"lemma":{"type":"string"},"word_status":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"reason_code":{"type":"string","enum":["not_sambas","inaccurate","duplicate","inappropriate","spam","other","violent_image"]},"note":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","resolved"]},"resolution":{"type":"string","nullable":true,"enum":["dismissed","taken_down","corrected","flagged_image",null]},"resolution_note":{"type":"string","nullable":true},"resolved_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","word_id","image_id","lemma","word_status","user_id","username","reason_code","note","status","resolution","resolution_note","resolved_at","created_at"]}},"required":["success","data"]}}}},"400":{"description":"Bukan laporan foto kekerasan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Laporan atau foto tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Laporan sudah ditutup","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/dashboard/stats":{"get":{"tags":["Dashboard"],"summary":"Statistik agregat dashboard (kata, kontribusi, pengguna, aktivitas)","responses":{"200":{"description":"Statistik dashboard","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"words":{"type":"object","properties":{"total":{"type":"integer"},"verified":{"type":"integer"},"deleted":{"type":"integer"},"by_status":{"type":"object","properties":{"draft":{"type":"integer"},"pending_review":{"type":"integer"},"published":{"type":"integer"},"rejected":{"type":"integer"}}}},"required":["total","verified","deleted","by_status"]},"contributions":{"type":"object","properties":{"total":{"type":"integer"},"by_status":{"type":"object","properties":{"pending":{"type":"integer"},"approved":{"type":"integer"},"rejected":{"type":"integer"},"corrected":{"type":"integer"}}}},"required":["total","by_status"]},"users":{"type":"object","properties":{"active":{"type":"integer"},"by_role":{"type":"object","properties":{"root":{"type":"integer"},"admin":{"type":"integer"},"editor":{"type":"integer"},"reviewer":{"type":"integer"},"contributor":{"type":"integer"}}}},"required":["active","by_role"]},"activity":{"type":"object","properties":{"audit_logs_last_7_days":{"type":"integer"}},"required":["audit_logs_last_7_days"]}},"required":["words","contributions","users","activity"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/users":{"get":{"tags":["Admin Users"],"summary":"Daftar user dengan cursor pagination (admin & root)","parameters":[{"schema":{"type":"string","maxLength":100},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","enum":["contributor","editor","reviewer","admin","root"]},"required":false,"name":"role","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"can_contribute","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar user + meta","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"username":{"type":"string"},"email":{"type":"string"},"role":{"type":"string","enum":["contributor","editor","reviewer","admin","root"]},"is_active":{"type":"boolean"},"can_contribute":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","username","email","role","is_active","can_contribute","created_at","updated_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan (hanya admin/root)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"post":{"tags":["Admin Users"],"summary":"Buat akun manual (admin & root). Email dianggap sudah terverifikasi.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string","minLength":1,"maxLength":100},"email":{"type":"string","format":"email"},"phone":{"type":"string","maxLength":20},"password":{"type":"string","minLength":8,"pattern":"[a-zA-Z]"},"confirm_password":{"type":"string"},"role":{"type":"string","enum":["contributor","editor","reviewer","admin"]},"is_active":{"type":"boolean","default":true}},"required":["username","email","password","confirm_password","role"]}}}},"responses":{"201":{"description":"Akun dibuat","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"username":{"type":"string"},"email":{"type":"string"},"role":{"type":"string","enum":["contributor","editor","reviewer","admin","root"]},"is_active":{"type":"boolean"},"can_contribute":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","username","email","role","is_active","can_contribute","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Peran tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Role tidak diizinkan (hanya admin/root)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Username, email, atau HP sudah dipakai","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/users/:id/active":{"patch":{"tags":["Admin Users"],"summary":"Aktifkan atau nonaktifkan akun (admin & root)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"is_active":{"type":"boolean"}},"required":["is_active"]}}}},"responses":{"200":{"description":"Status aktif diperbarui","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"is_active":{"type":"boolean"}},"required":["id","is_active"]}},"required":["success","data"]}}}},"400":{"description":"User tidak ditemukan atau user sistem anonim","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Target root atau akun sendiri (CANNOT_CHANGE_ROOT/CANNOT_DEACTIVATE_SELF)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/users/:id/contribution":{"patch":{"tags":["Admin Users"],"summary":"Izinkan atau hentikan kontribusi akun (admin & root)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"can_contribute":{"type":"boolean"}},"required":["can_contribute"]}}}},"responses":{"200":{"description":"Hak kontribusi diperbarui","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"can_contribute":{"type":"boolean"}},"required":["id","can_contribute"]}},"required":["success","data"]}}}},"400":{"description":"User tidak ditemukan atau user sistem anonim","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/users/:id/role":{"patch":{"tags":["Admin Users"],"summary":"Ubah role user target + logout semua perangkat target (admin & root)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["contributor","editor","reviewer","admin"]}},"required":["role"]}}}},"responses":{"200":{"description":"Role berhasil diubah","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"role":{"type":"string","enum":["contributor","editor","reviewer","admin","root"]}},"required":["id","role"]}},"required":["success","data"]}}}},"400":{"description":"Role tidak valid / user tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Target adalah root / ubah role sendiri (CANNOT_CHANGE_ROOT/CANNOT_CHANGE_SELF_ROLE)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"User target tidak ada","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/contribution-access/:id":{"patch":{"tags":["Admin Users"],"summary":"Izinkan atau hentikan kontribusi (admin, root, reviewer)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"can_contribute":{"type":"boolean"}},"required":["can_contribute"]}}}},"responses":{"200":{"description":"Hak kontribusi diperbarui","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"can_contribute":{"type":"boolean"}},"required":["id","can_contribute"]}},"required":["success","data"]}}}},"400":{"description":"User tidak ditemukan atau user sistem anonim","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/verifier-applications":{"post":{"tags":["Verifier Applications"],"summary":"Ajukan jadi verifikator (contributor, 30/menit)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","minLength":1,"maxLength":20},"address":{"type":"string","minLength":10,"maxLength":500},"social_links":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["instagram","facebook","tiktok","youtube","x","website"]},"username":{"type":"string","minLength":1,"maxLength":80},"screenshot":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider_file_id":{"type":"string","minLength":1}},"required":["url","provider_file_id"]}},"required":["platform","username","screenshot"]},"minItems":1,"maxItems":5}},"required":["phone","address","social_links"]}}}},"responses":{"201":{"description":"Pengajuan tersimpan (pending)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected"]},"phone":{"type":"string"},"address":{"type":"string"},"social_links":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["instagram","facebook","tiktok","youtube","x","website"]},"username":{"type":"string"},"screenshot":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"}},"required":["url","provider_file_id"]}},"required":["platform","username","screenshot"]}},"admin_comment":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","status","phone","address","social_links","admin_comment","reviewed_at","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan contributor","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Sudah ada pengajuan / HP dipakai user lain","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak percobaan (30/menit)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/verifier-applications/me":{"get":{"tags":["Verifier Applications"],"summary":"Pengajuan milik user login","responses":{"200":{"description":"Pengajuan milik sendiri","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected"]},"phone":{"type":"string"},"address":{"type":"string"},"social_links":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["instagram","facebook","tiktok","youtube","x","website"]},"username":{"type":"string"},"screenshot":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"}},"required":["url","provider_file_id"]}},"required":["platform","username","screenshot"]}},"admin_comment":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","status","phone","address","social_links","admin_comment","reviewed_at","created_at","updated_at"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Belum pernah mengajukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"patch":{"tags":["Verifier Applications"],"summary":"Perbaiki pengajuan yang ditolak (contributor, 30/menit)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","minLength":1,"maxLength":20},"address":{"type":"string","minLength":10,"maxLength":500},"social_links":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["instagram","facebook","tiktok","youtube","x","website"]},"username":{"type":"string","minLength":1,"maxLength":80},"screenshot":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"provider_file_id":{"type":"string","minLength":1}},"required":["url","provider_file_id"]}},"required":["platform","username","screenshot"]},"minItems":1,"maxItems":5}},"required":["phone","address","social_links"]}}}},"responses":{"200":{"description":"Pengajuan dikirim ulang (pending)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected"]},"phone":{"type":"string"},"address":{"type":"string"},"social_links":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["instagram","facebook","tiktok","youtube","x","website"]},"username":{"type":"string"},"screenshot":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"}},"required":["url","provider_file_id"]}},"required":["platform","username","screenshot"]}},"admin_comment":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","status","phone","address","social_links","admin_comment","reviewed_at","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Body tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan contributor","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Belum pernah mengajukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Status bukan rejected / HP dipakai user lain","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Terlalu banyak percobaan (30/menit)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/verifier-applications":{"get":{"tags":["Verifier Applications","Admin"],"summary":"Antrean pengajuan verifikator (admin/root, cursor)","parameters":[{"schema":{"type":"string","enum":["pending","approved","rejected"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar pengajuan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"phone":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected"]},"created_at":{"type":"string"}},"required":["id","user_id","username","phone","status","created_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"number"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan admin/root","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/verifier-applications/:id":{"get":{"tags":["Verifier Applications","Admin"],"summary":"Detail pengajuan verifikator (termasuk alamat dan sosial)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail pengajuan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"username":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","approved","rejected"]},"phone":{"type":"string"},"address":{"type":"string"},"social_links":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["instagram","facebook","tiktok","youtube","x","website"]},"username":{"type":"string"},"screenshot":{"type":"object","properties":{"url":{"type":"string"},"provider_file_id":{"type":"string"}},"required":["url","provider_file_id"]}},"required":["platform","username","screenshot"]}},"admin_comment":{"type":"string","nullable":true},"reviewed_by":{"type":"string","nullable":true},"reviewed_by_username":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","user_id","username","status","phone","address","social_links","admin_comment","reviewed_by","reviewed_by_username","reviewed_at","created_at","updated_at"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan admin/root","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Pengajuan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/verifier-applications/:id/approve":{"post":{"tags":["Verifier Applications","Admin"],"summary":"Setujui: role pemohon menjadi reviewer + FCM","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Disetujui, role reviewer","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["approved"]},"role":{"type":"string","enum":["reviewer"]}},"required":["id","status","role"]}},"required":["success","data"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan admin/root","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Pengajuan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Sudah ada keputusan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/verifier-applications/:id/reject":{"post":{"tags":["Verifier Applications","Admin"],"summary":"Tolak pengajuan (comment wajib) + FCM","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"comment":{"type":"string","minLength":1,"maxLength":2000}},"required":["comment"]}}}},"responses":{"200":{"description":"Ditolak","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["rejected"]}},"required":["id","status"]}},"required":["success","data"]}}}},"400":{"description":"comment wajib","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"401":{"description":"Token tidak ada/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Bukan admin/root","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"404":{"description":"Pengajuan tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"409":{"description":"Sudah ada keputusan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/notification-templates":{"get":{"tags":["Admin Notification Templates"],"summary":"Daftar template notifikasi campaign","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Daftar template","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","name","title","body","deep_link_kind","deep_link_value","created_by","created_at","updated_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"post":{"tags":["Admin Notification Templates"],"summary":"Buat template notifikasi","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"title":{"type":"string","minLength":1,"maxLength":80},"body":{"type":"string","minLength":1,"maxLength":500},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"],"default":"none"},"deep_link_value":{"type":"string","nullable":true,"maxLength":500}},"required":["name","title","body"]}}}},"responses":{"201":{"description":"Template dibuat","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","name","title","body","deep_link_kind","deep_link_value","created_by","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Validasi gagal","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/notification-templates/:id":{"get":{"tags":["Admin Notification Templates"],"summary":"Detail template","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","name","title","body","deep_link_kind","deep_link_value","created_by","created_at","updated_at"]}},"required":["success","data"]}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"patch":{"tags":["Admin Notification Templates"],"summary":"Ubah template","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"title":{"type":"string","minLength":1,"maxLength":80},"body":{"type":"string","minLength":1,"maxLength":500},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true,"maxLength":500}}}}}},"responses":{"200":{"description":"Diperbarui","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","name","title","body","deep_link_kind","deep_link_value","created_by","created_at","updated_at"]}},"required":["success","data"]}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}},"delete":{"tags":["Admin Notification Templates"],"summary":"Hapus (soft) template","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Dihapus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"nullable":true}},"required":["success","data"]}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/notification-campaigns":{"get":{"tags":["Admin Notification Campaigns"],"summary":"Daftar campaign","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":26,"maxLength":26},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","enum":["draft","scheduled","sending","completed","failed","cancelled"]},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"Daftar","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"template_id":{"type":"string","nullable":true},"title":{"type":"string"},"body":{"type":"string"},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true},"audience_type":{"type":"string","enum":["all","selected"]},"status":{"type":"string","enum":["draft","scheduled","sending","completed","failed","cancelled"]},"send_at":{"type":"string","nullable":true},"targeted_users":{"type":"integer"},"push_success":{"type":"integer"},"push_failed":{"type":"integer"},"inbox_written":{"type":"integer"},"topic_sent":{"type":"boolean"},"last_error":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","template_id","title","body","deep_link_kind","deep_link_value","audience_type","status","send_at","targeted_users","push_success","push_failed","inbox_written","topic_sent","last_error","created_by","created_at","updated_at"]}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}},"required":["limit","next_cursor","has_more"]}},"required":["success","data","meta"]}}}}}},"post":{"tags":["Admin Notification Campaigns"],"summary":"Buat draft campaign","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"template_id":{"type":"string","nullable":true,"minLength":26,"maxLength":26},"title":{"type":"string","minLength":1,"maxLength":80},"body":{"type":"string","minLength":1,"maxLength":500},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true,"maxLength":500},"audience_type":{"type":"string","enum":["all","selected"]},"user_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"maxItems":500},"send_at":{"type":"string","nullable":true,"format":"date-time"}},"required":["audience_type"]}}}},"responses":{"201":{"description":"Draft dibuat","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"template_id":{"type":"string","nullable":true},"title":{"type":"string"},"body":{"type":"string"},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true},"audience_type":{"type":"string","enum":["all","selected"]},"status":{"type":"string","enum":["draft","scheduled","sending","completed","failed","cancelled"]},"send_at":{"type":"string","nullable":true},"targeted_users":{"type":"integer"},"push_success":{"type":"integer"},"push_failed":{"type":"integer"},"inbox_written":{"type":"integer"},"topic_sent":{"type":"boolean"},"last_error":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","template_id","title","body","deep_link_kind","deep_link_value","audience_type","status","send_at","targeted_users","push_success","push_failed","inbox_written","topic_sent","last_error","created_by","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Validasi gagal","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/notification-campaigns/estimate":{"post":{"tags":["Admin Notification Campaigns"],"summary":"Estimasi audience (user dengan device aktif)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"audience_type":{"type":"string","enum":["all","selected"]},"user_ids":{"type":"array","items":{"type":"string","minLength":26,"maxLength":26},"maxItems":500}},"required":["audience_type"]}}}},"responses":{"200":{"description":"Estimasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"users_with_device":{"type":"integer"},"devices":{"type":"integer"}},"required":["users_with_device","devices"]}},"required":["success","data"]}}}}}}},"/api/v1/admin/notification-campaigns/:id":{"get":{"tags":["Admin Notification Campaigns"],"summary":"Detail campaign + stats + sample failures","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detail","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"template_id":{"type":"string","nullable":true},"title":{"type":"string"},"body":{"type":"string"},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true},"audience_type":{"type":"string","enum":["all","selected"]},"status":{"type":"string","enum":["draft","scheduled","sending","completed","failed","cancelled"]},"send_at":{"type":"string","nullable":true},"targeted_users":{"type":"integer"},"push_success":{"type":"integer"},"push_failed":{"type":"integer"},"inbox_written":{"type":"integer"},"topic_sent":{"type":"boolean"},"last_error":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true},"recipient_counts":{"type":"object","nullable":true,"properties":{"pending":{"type":"integer"},"sent":{"type":"integer"},"failed":{"type":"integer"},"skipped_no_token":{"type":"integer"}},"required":["pending","sent","failed","skipped_no_token"]},"failures":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"status":{"type":"string"},"error":{"type":"string","nullable":true}},"required":["id","user_id","status","error"]}}},"required":["id","template_id","title","body","deep_link_kind","deep_link_value","audience_type","status","send_at","targeted_users","push_success","push_failed","inbox_written","topic_sent","last_error","created_by","created_at","updated_at","recipient_counts","failures"]}},"required":["success","data"]}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/notification-campaigns/:id/send":{"post":{"tags":["Admin Notification Campaigns"],"summary":"Kirim sekarang atau jadwalkan (jika send_at masa depan)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Dikirim / dijadwalkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"template_id":{"type":"string","nullable":true},"title":{"type":"string"},"body":{"type":"string"},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true},"audience_type":{"type":"string","enum":["all","selected"]},"status":{"type":"string","enum":["draft","scheduled","sending","completed","failed","cancelled"]},"send_at":{"type":"string","nullable":true},"targeted_users":{"type":"integer"},"push_success":{"type":"integer"},"push_failed":{"type":"integer"},"inbox_written":{"type":"integer"},"topic_sent":{"type":"boolean"},"last_error":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","template_id","title","body","deep_link_kind","deep_link_value","audience_type","status","send_at","targeted_users","push_success","push_failed","inbox_written","topic_sent","last_error","created_by","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Tidak bisa dikirim","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/notification-campaigns/:id/cancel":{"post":{"tags":["Admin Notification Campaigns"],"summary":"Batalkan draft / scheduled","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Dibatalkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"template_id":{"type":"string","nullable":true},"title":{"type":"string"},"body":{"type":"string"},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true},"audience_type":{"type":"string","enum":["all","selected"]},"status":{"type":"string","enum":["draft","scheduled","sending","completed","failed","cancelled"]},"send_at":{"type":"string","nullable":true},"targeted_users":{"type":"integer"},"push_success":{"type":"integer"},"push_failed":{"type":"integer"},"inbox_written":{"type":"integer"},"topic_sent":{"type":"boolean"},"last_error":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","template_id","title","body","deep_link_kind","deep_link_value","audience_type","status","send_at","targeted_users","push_success","push_failed","inbox_written","topic_sent","last_error","created_by","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Tidak bisa dibatalkan","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/admin/notification-campaigns/:id/retry":{"post":{"tags":["Admin Notification Campaigns"],"summary":"Ulangi penerima gagal (audience selected)","parameters":[{"schema":{"type":"string","minLength":26,"maxLength":26},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Retry dimulai","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"template_id":{"type":"string","nullable":true},"title":{"type":"string"},"body":{"type":"string"},"deep_link_kind":{"type":"string","enum":["word","contribution","suggestion","url","none"]},"deep_link_value":{"type":"string","nullable":true},"audience_type":{"type":"string","enum":["all","selected"]},"status":{"type":"string","enum":["draft","scheduled","sending","completed","failed","cancelled"]},"send_at":{"type":"string","nullable":true},"targeted_users":{"type":"integer"},"push_success":{"type":"integer"},"push_failed":{"type":"integer"},"inbox_written":{"type":"integer"},"topic_sent":{"type":"boolean"},"last_error":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string","nullable":true}},"required":["id","template_id","title","body","deep_link_kind","deep_link_value","audience_type","status","send_at","targeted_users","push_success","push_failed","inbox_written","topic_sent","last_error","created_by","created_at","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Tidak bisa di-retry","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/lemma-definitions/lookup":{"get":{"tags":["Lemma Definitions"],"summary":"Lookup definisi lemma dari KBBI (publik - prefill form makna/kontribusi)","description":"Memanggil penyedia KBBI pihak ketiga, lalu memetakan ke bentuk standar (entries + suggestions). Query opsional `provider` (whitelist, mis. raf555) meng-override default env KBBI_PROVIDER. Tidak menulis ke database. Lookup miss = 200 + found:false.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[\\p{L}\\p{N}\\s'\\-.]+$/u"},"required":true,"name":"lemma","in":"query"},{"schema":{"type":"string","enum":["raf555"]},"required":false,"name":"provider","in":"query"}],"responses":{"200":{"description":"Hasil lookup (found true/false)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"query":{"type":"string"},"normalized_query":{"type":"string"},"found":{"type":"boolean"},"provider":{"type":"string"},"fetched_at":{"type":"string"},"cache_hit":{"type":"boolean"},"entries":{"type":"array","items":{"type":"object","properties":{"lemma":{"type":"string"},"homonym_index":{"type":"integer","minimum":0,"exclusiveMinimum":true},"senses":{"type":"array","items":{"type":"object","properties":{"sense_index":{"type":"integer","minimum":0,"exclusiveMinimum":true},"word_class_code":{"type":"string","nullable":true},"word_class_label":{"type":"string","nullable":true},"definition":{"type":"string"},"examples":{"type":"array","items":{"type":"string"}},"notes":{"type":"string","nullable":true}},"required":["sense_index","word_class_code","word_class_label","definition","examples","notes"]}}},"required":["lemma","homonym_index","senses"]}},"suggestions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"lemma":{"type":"string"},"homonym_index":{"type":"integer","minimum":0,"exclusiveMinimum":true},"sense_index":{"type":"integer","minimum":0,"exclusiveMinimum":true},"word_class_code":{"type":"string","nullable":true},"word_class_label":{"type":"string","nullable":true},"definition":{"type":"string"},"preview":{"type":"string"}},"required":["id","lemma","homonym_index","sense_index","word_class_code","word_class_label","definition","preview"]}}},"required":["query","normalized_query","found","provider","fetched_at","cache_hit","entries","suggestions"]}},"required":["success","data"]}}}},"400":{"description":"Query lemma/provider tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Rate limit","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"502":{"description":"Provider KBBI gagal","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"503":{"description":"Provider belum dikonfigurasi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/share/backgrounds":{"get":{"tags":["Share"],"summary":"Cari foto atau video latar untuk kartu share","description":"Default `provider=pixabay`, `media=photo`. `sort=relevant` butuh `q`. `sort=popular` untuk Media Explorer (q opsional). `limit` 1-30 (default 3). `media=video` hanya `pixabay`. Safe search always-on; Openverse dibatasi lisensi CC. Tanpa konfigurasi / gagal upstream → items kosong + degraded:true.","parameters":[{"schema":{"type":"string","maxLength":120,"default":""},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","enum":["relevant","popular"],"default":"relevant"},"required":false,"name":"sort","in":"query"},{"schema":{"type":"string","enum":["unsplash","pixabay","openverse"],"default":"pixabay"},"required":false,"name":"provider","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":30,"default":3},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","enum":["photo","video"],"default":"photo"},"required":false,"name":"media","in":"query"},{"schema":{"type":"string","enum":["portrait","landscape","square"]},"required":false,"name":"orientation","in":"query"}],"responses":{"200":{"description":"Daftar kandidat latar (boleh kosong)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"provider":{"type":"string","enum":["unsplash","pixabay","openverse"]},"query":{"type":"string"},"page":{"type":"integer","minimum":0,"exclusiveMinimum":true},"cache_hit":{"type":"boolean"},"degraded":{"type":"boolean"},"media":{"type":"string","enum":["photo","video"]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"photographer":{"type":"string"},"username":{"type":"string"},"attribution_url":{"type":"string"},"unsplash_url":{"type":"string"},"provider":{"type":"string","enum":["unsplash","pixabay","openverse"]},"kind":{"type":"string","enum":["photo","video"]},"preview_url":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"},"duration_seconds":{"type":"integer"},"mime_type":{"type":"string"}},"required":["id","url","photographer","username","attribution_url","unsplash_url","provider","kind","preview_url","width","height","duration_seconds","mime_type"]}}},"required":["provider","query","page","cache_hit","degraded","media","items"]}},"required":["success","data"]}}}},"400":{"description":"Query tidak valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}},"429":{"description":"Rate limit","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}},"/api/v1/share/background-providers":{"get":{"tags":["Share"],"summary":"Daftar provider latar yang didukung","responses":{"200":{"description":"Daftar provider","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"providers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["unsplash","pixabay","openverse"]},"label":{"type":"string"},"available":{"type":"boolean"},"media":{"type":"array","items":{"type":"string","enum":["photo","video"]}}},"required":["id","label","available","media"]}}},"required":["providers"]}},"required":["success","data"]}}}},"429":{"description":"Rate limit","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error_code":{"type":"string"},"message":{"type":"string"},"details":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}},{"nullable":true}]}},"required":["success","error_code","message","details"]}}}}}}}}}