Wiki
REST API
uVersion sunucusunun HTTP uç noktalarının tam referansı: auth, repos, files, locks, comments, watchlist, modification requests, builds, admin.
uVersion sunucusu, JWT ile kimlik doğrulaması yapılan bir JSON HTTP API sunar. Bu sayfa, masaüstü istemcisi,
editör eklentileri ve uversion CLI tarafından kullanılan tüm uç noktaları belgeler.
Bunları doğrudan çağırarak uVersion'ı dahili araçlarınıza
(özel dashboard, denetim betikleri, webhook'lar vb.) entegre edebilirsiniz.
Kurallar
Temel URL
Belgelenen tüm yollar, örneğinizin URL'sine göre görecelidir. Örnekler
https://uversion.mygamestudio.com kullanır. Kendi URL'nizle değiştirin.
Gerekli başlıklar
| Başlık | Değer |
|---|---|
Authorization | /api/auth/* ve /api/server-info (ve /health) hariç tüm /api/* rotalarında Bearer <jwt> |
Content-Type | JSON body içeren POST/PUT için application/json. İkili yüklemeler (build files) için application/octet-stream. |
Accept | application/json önerilir (sunucu varsayılan olarak JSON döndürür) |
Tek biçimli yanıt formatı
Tüm rotalar aşağıdaki zarfla yanıt verir:
{
"success": true,
"data": { /* payload */ }
}
Hata durumunda:
{
"success": false,
"error": "Permission denied: capability 'manage_users' required"
}
success alanı her zaman bulunur ve isteğin başarılı olup olmadığını belirtir.
Başarı durumunda data alanı bulunur. Başarısızlık durumunda error alanı bulunur.
Asla ikisi birlikte bulunmaz.
Sayfalama
Potansiyel olarak uzun listeler döndüren rotalar, query param olarak limit ve offset
kabul eder (?limit=20&offset=40). Yanıt, yinelemeyi kolaylaştırmak için total ve has_more
içerir. Maksimum limit: 100.
Hız sınırlama
Genel hız sınırlama kaldırıldı (CLAUDE.md, Security bölümüne bakın). Yalnızca /api/auth/login
hız sınırlamasına tabidir: her username için 15 dakikada 5 başarısız deneme. Geçerli denemeler
sayılmaz.
Token sürümleme
Her JWT, DB'deki users.token_version ile eşleşen bir tv alanı (token version) içerir.
Auth ara katmanı bu değeri her istekte kontrol eder. Kullanıcı POST /api/auth/logout yaptığında,
bir yönetici şifresini sıfırladığında veya bir yönetici hesabını devre dışı bıraktığında, token_version artırılır
ve o kullanıcının tüm makinelerindeki mevcut tüm token'lar anında geçersiz kılınır.
Curl
API'yi bir terminalden çağırmak için:
TOKEN=$(curl -s -X POST https://uversion.mygamestudio.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"alice","password":"secret"}' | jq -r '.data.token')
curl -H "Authorization: Bearer $TOKEN" \
https://uversion.mygamestudio.com/api/repositories
Kimlik doğrulama
POST /api/auth/login
Bir kullanıcıyı kimlik doğrulaması yapar ve 30 günlük bir JWT döndürür.
Body:
{
"username": "alice",
"password": "secret"
}
Response 200:
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2026-06-13T14:30:00Z",
"user": {
"id": 12,
"username": "alice",
"email": "alice@mygamestudio.com",
"role": "lead",
"is_active": true
}
}
}
Hatalar:
401: geçersiz kimlik bilgileri veya devre dışı kullanıcı429: bu username için 15 dakikalık pencerede 5 başarısız denemeye ulaşıldı
Sunucu, zamanlama saldırılarını etkisiz hale getirmek için her zaman argon2id::verify_password çalıştırır (kullanıcı yoksa sahte bir hash'e karşı).
Yanıt, kullanıcı var olsa da olmasa da aynı süreyi alır.
POST /api/auth/refresh
Şifreyi yeniden girmeden JWT'yi yeniler.
Başlıklar: Authorization: Bearer <current_token>. Body yok.
Response 200: /login ile aynı, süresi 30 gün ileri atılmış ve yeni bir token içerir.
Hatalar:
401: mevcut token geçersiz, süresi dolmuş veyatoken_versionuyuşmazlığı
POST /api/auth/logout
users.token_version'ı artırarak geçerli kullanıcının tüm token'larını (tüm makinelerinde) geçersiz kılar.
Kullanıcının her yerde yeniden oturum açması gerekir.
Response 200: { "success": true }.
POST /api/auth/validate
Token'ın hâlâ geçerli olup olmadığını kontrol eder. Süresinin dolmasına 7 günden az kalan token'lar için, sunucu yanıta
bir refreshed_token ekler (otomatik uzatma). İstemci, eskisinin yerine bunu kalıcı hale getirmelidir.
Response 200:
{
"success": true,
"data": {
"valid": true,
"user_id": 12,
"expires_at": "2026-06-13T14:30:00Z",
"refreshed_token": "eyJhbGciOiJIUzI1NiIs..."
}
}
POST /api/auth/register
Bir kullanıcı hesabı oluşturur (genel rota, kimlik doğrulaması olmadan).
POST /api/auth/change-password
Geçerli kullanıcının şifresini değiştirir. token_version'ı artırır, bu da tüm eski token'ları geçersiz kılar.
Depolar
GET /api/repositories
Geçerli kullanıcının erişebildiği depoları listeler (izinler tablosu üzerinden filtrelenir). Bir depoda hiçbir izin desenine sahip olmayan bir kullanıcı onu görmez.
Query param: limit, offset.
Response 200:
{
"success": true,
"data": [
{
"id": 1,
"name": "hero-rpg",
"owner": "acme",
"description": "Main RPG project",
"current_revision": "7f3a9b1c2d...",
"file_count": 8432,
"size_bytes": 14211938405,
"created_at": "2026-01-15T10:00:00Z"
},
{
"id": 2,
"name": "shared-assets",
"owner": "acme",
"description": "Shared asset library",
"current_revision": "3a4b5c6d...",
"file_count": 412,
"size_bytes": 980000000,
"created_at": "2026-02-01T09:00:00Z"
}
]
}
GET /api/repositories/{repo_id}
Toplu istatistikler dahil, bir deponun ayrıntısı.
Response 200:
{
"success": true,
"data": {
"id": 1,
"name": "hero-rpg",
"owner": "acme",
"description": "Main RPG project",
"current_revision": "7f3a9b1c2d...",
"file_count": 8432,
"size_bytes": 14211938405,
"dedup_ratio": 4.2,
"created_at": "2026-01-15T10:00:00Z",
"last_commit_at": "2026-05-15T08:30:00Z"
}
}
Hatalar:
403: bu depoya erişim yok404: depo mevcut değil
POST /api/repositories
Yeni bir depo oluşturur. create_repos capability gerekir (varsayılan olarak admin).
Body:
{
"name": "new-project",
"description": "Optional description"
}
Doğrulama:
- name: 1 ila 64 karakter, alfasayısal + tireler + alt çizgiler. owner başına benzersiz.
- description: 0 ila 1024 karakter. İsteğe bağlı.
Hatalar:
400: geçersiz veya çok uzun ad403:create_reposcapability eksik409: bu owner için bu adda bir depo zaten var
Dosyalar
POST /api/files/{repo_id}/upload-chunks
Bir ikili chunk grubu yükler. Aynı chunk'lar (SHA-256'ya göre) otomatik olarak yinelenmeden kaldırılır.
Sunucu, zaten mevcut olan bir chunk'ı yeniden depolamaz. Yanıt, her chunk için hash'ini + boyutunu +
sıkıştırılmış boyutunu döndürür; bunlar bir sonraki POST /commit'te kullanılır.
Body:
{
"chunks": [
{ "data": "<base64-encoded chunk bytes>" },
{ "data": "<base64-encoded chunk bytes>" }
]
}
Response 200:
{
"success": true,
"data": {
"chunks": [
{ "hash": "abc123...", "size": 1048576, "compressed_size": 423152 },
{ "hash": "def456...", "size": 2097152, "compressed_size": 891204 }
]
}
}
Sınırlar: body maks. 1 GB (security.max_body_size_files ile yapılandırılabilir). Daha büyük dosyalar için birden çok gruba bölün.
POST /api/files/{repo_id}/commit
Bir dosya listesi ve chunk'larıyla atomik bir commit oluşturur. Ya tüm dosyalar geçer ya da hiçbiri.
Body:
{
"message": "Updated main level + hero pose pass",
"files": [
{
"path": "Content/Maps/MainLevel.umap",
"action": "modified",
"chunks": ["abc123...", "def456..."]
},
{
"path": "Content/Characters/NewVillain.uasset",
"action": "added",
"chunks": ["fed789..."]
},
{
"path": "Content/OldAsset.uasset",
"action": "deleted"
}
]
}
Olası eylemler: added, modified, deleted.
added ve modified için chunks dizisi, /upload-chunks tarafından döndürülen hash'leri içerir.
deleted için chunks'ı atlayın.
Response 200:
{
"success": true,
"data": {
"commit_hash": "7f3a9b1c2d3e4f...",
"files_changed": 3,
"bytes_uploaded": 88080384,
"bytes_deduped": 4194304,
"revision": 47
}
}
Hatalar:
400: boş mesaj, eylemsiz dosya, var olmayan chunk'lara referans403:checkincapability yok veya dosyalardan birinde write izni yok409: değiştirilen bir dosyada kilit zaten başka bir kullanıcı tarafından tutuluyor veya eşzamanlı commit (aynı dosyada race condition)
GET /api/files/{repo_id}/snapshot
Deponun geçerli revizyondaki tam durumunu döndürür: tüm dosyalar, revizyonları ve chunk'ları. İstemci tarafından clone ve zorunlu sync işlemleri için kullanılır.
Query param:
revision(isteğe bağlı): geçmiş bir revizyondaki snapshot. Varsayılan: HEAD.
Response 200:
{
"success": true,
"data": {
"revision": 47,
"files": [
{
"path": "Content/Maps/MainLevel.umap",
"revision": 12,
"size_bytes": 84934656,
"chunks": ["abc123...", "def456..."]
}
]
}
}
GET /api/files/{repo_id}/content
Belirli bir revizyondaki bir dosyanın içeriğini indirir (sunucu chunk'ları yeniden birleştirir). clone ve sync tarafından kullanılır.
Query param:
path: dosya yolu (depo köküne göre görece)revision(isteğe bağlı): revizyon numarası. Varsayılan: en son.
Response 200: dosyanın ikili içeriği.
GET /api/files/{repo_id}/history
Deponun commit'lerinin sayfalanmış geçmişi.
Query param:
limit(1 ila 100, varsayılan 20)offset(varsayılan 0)path(isteğe bağlı): dosya yoluna göre filtrele (bu dosyayı değiştiren commit'ler)author(isteğe bağlı): username'e göre filtrelesince(isteğe bağlı): ISO 8601 timestamp
Response 200:
{
"success": true,
"data": {
"commits": [
{
"hash": "7f3a9b1c...",
"author": "alice",
"author_id": 12,
"date": "2026-05-15T08:30:00Z",
"message": "Fixed lighting in main level",
"files_changed": 1,
"bytes_uploaded": 84934656
}
],
"total": 423,
"limit": 20,
"offset": 0,
"has_more": true
}
}
Artımlı sync
Masaüstü istemcisinin verimli şekilde senkronize etmek için kullandığı uç noktalar:
GET /api/files/{repo_id}/sync: bir revizyondan bu yana değişen dosyalar, delta sync için.GET /api/files/{repo_id}/deletions: sunucu tarafında silinen dosyalar, silmeleri yerele yaymak için.GET /api/files/{repo_id}/list: deponun dosya listesi.POST /api/files/{repo_id}/checkout: kilitleri edinir ve düzenlemeyi hazırlar.
Kilitler
POST /api/locks/{repo_id}/acquire
Bir yol listesi üzerinde kilitler edinir. Edinmeler bağımsızdır: acquired listesi
başarıları, failed listesi ise başarısızlıkları nedenleriyle birlikte içerir.
Body:
{
"paths": [
"Content/Maps/MainLevel.umap",
"Content/Characters/Hero.uasset"
]
}
Response 200:
{
"success": true,
"data": {
"acquired": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"file_id": 12345,
"file_path": "Content/Maps/MainLevel.umap",
"user_id": 12,
"username": "alice",
"acquired_at": "2026-05-15T14:30:00Z",
"last_heartbeat_at": "2026-05-15T14:30:00Z",
"expires_at": "2026-05-15T15:30:00Z"
}
],
"failed": [
{
"path": "Content/Characters/Hero.uasset",
"reason": "ALREADY_LOCKED",
"lock_holder": "bob",
"lock_acquired_at": "2026-05-15T13:00:00Z"
}
]
}
}
Kilitler, heartbeat olmadan 60 dakika sonra sona erer. expires_at alanı bu son tarihi yansıtır.
Kilidi yenilemek için düzenli olarak /heartbeat'i, serbest bırakmak için /release'i çağırın.
failed nedenleri:
ALREADY_LOCKED: başka bir kullanıcı kilidi tutuyor (lock_holdervelock_acquired_atalanları doldurulur)PERMISSION_DENIED: bu yolda write izni yokINVALID_PATH: bozuk yol (mutlak,..içeriyor vb.)
POST /api/locks/{repo_id}/release
Sahip olduğunuz kilitleri serbest bırakır. Body:
{
"paths": ["Content/Maps/MainLevel.umap"],
"force": false
}
force: true, force_unlock capability gerektirir. Eylem denetlenir.
POST /api/locks/{repo_id}/heartbeat
Kilitlerinizde last_heartbeat_at'i günceller. Yöneticilerin etkinliği görmesini isteyen uzun süre çalışan CI işleri için
her 5 dakikada bir önerilir.
GET /api/locks/{repo_id}/status
Deponun tüm aktif kilitlerini listeler; adları doğrudan döndürmek için users ve files üzerinde join yapar.
Query param: user (username'e göre filtrele), limit, offset.
Response 200:
{
"success": true,
"data": {
"locks": [
{
"file_path": "Content/Maps/MainLevel.umap",
"user_id": 12,
"username": "alice",
"acquired_at": "2026-05-15T14:30:00Z",
"last_heartbeat_at": "2026-05-15T16:00:00Z"
}
],
"total": 1
}
}
Yorumlar ve incelemeler
GET /api/comments/{repo_id}/comments?commit_hash=<hash>
Bir commit'in yorumlarını iş parçacığı halinde (ebeveyn → çocuklar) listeler.
Response 200:
{
"success": true,
"data": [
{
"id": 42,
"commit_hash": "7f3a9b1c...",
"file_path": "Content/Maps/MainLevel.umap",
"author_id": 12,
"author_username": "alice",
"body": "LGTM, ship it",
"parent_id": null,
"created_at": "2026-05-15T15:00:00Z",
"replies": [
{
"id": 43,
"author_username": "bob",
"body": "Thanks!",
"parent_id": 42,
"created_at": "2026-05-15T15:05:00Z"
}
]
}
]
}
POST /api/comments/{repo_id}/comments
Bir yorum oluşturur. file_path isteğe bağlıdır (commit yorumu vs. dosya yorumu). Mevcut bir iş parçacığına yanıt vermek için parent_id.
Body:
{
"commit_hash": "7f3a9b1c...",
"file_path": "Content/Maps/MainLevel.umap",
"body": "LGTM, ship it",
"parent_id": null
}
POST /api/comments/{repo_id}/reviews
Bir commit üzerine bir inceleme gönderir. approve_changes capability gerekir.
Body:
{
"commit_hash": "7f3a9b1c...",
"status": "approved",
"comment": "Lighting looks great, approving"
}
Kabul edilen status: approved, changes_requested, pending.
İzleme listesi
GET /api/watchlist/{repo_id}/watchlist
Geçerli kullanıcının bu depodaki watch desenlerini listeler.
Response 200:
{
"success": true,
"data": [
{
"id": 1,
"user_id": 12,
"pattern": "Content/Characters/Hero/**",
"notify_on": ["commit", "lock"],
"created_at": "2026-04-10T10:00:00Z"
}
]
}
POST /api/watchlist/{repo_id}/watchlist
Bir watch deseni ekler. Body:
{
"pattern": "Content/Characters/Hero/**",
"notify_on": ["commit", "lock"]
}
Olası olaylar: commit (bir commit eşleşen bir dosyayı değiştirdi),
lock (bir kilit edinildi), review (bir inceleme gönderildi).
DELETE /api/watchlist/{repo_id}/watchlist/{watch_id}
Bir watch desenini kaldırır. { "success": true } döndürür.
Üretim panosu (görevler)
Eski modification-requests API'si kaldırıldı: üretim panosu onu içine alır
(istekler kartlara dönüşür, origin='request'). Uç noktalar
/api/tasks/{repo_id} altında iç içe yerleştirilmiştir.
| Rota | Açıklama |
|---|---|
GET /api/tasks/{repo_id}/board | Tam pano: sütunlar + kartlar |
POST /api/tasks/{repo_id}/tasks | Bir kart oluşturur |
PUT/DELETE /api/tasks/{repo_id}/tasks/{task_id} | Bir kartı günceller / siler |
PUT /api/tasks/{repo_id}/tasks/{task_id}/assignees | Bir karta kullanıcılar atar |
GET /api/tasks/{repo_id}/assignable-users | Atanabilir kullanıcıların listesi |
POST /api/tasks/{repo_id}/columns | Panonun sütunlarını yapılandırır |
Ayrıca mevcut alt rotalar: kart yorumları, assets ve commit'lere bağlantılar ve ekler
(kapak resmiyle birlikte). Sütunların yapılandırılması manage_board capability (admin / lead) gerektirir.
Derlemeler
POST /api/builds/{repo_id}/upload?hash=<sha256>
Bir build dosyasını <storage_path>/builds/<hash>'e yükler.
Sunucu, query param'da verilen SHA-256'yı alınan içeriğe göre doğrular. Hash sunucu tarafında zaten varsa,
yeniden kopyalamadan hemen 200 döndürür (build storage tarafında dedup).
Başlıklar: Content-Type: application/octet-stream.
Body: ham ikili (JSON sarmalama yok).
Sınırlar: dosya başına 8 GB.
Hatalar:
400: hash query param eksik veya bozuk, ya da hesaplanan SHA-256 != verilen hash413: dosya > 8 GB
POST /api/builds/{repo_id}/publish
Tüm dosyaları yüklendikten sonra bir build'in manifest'ini kaydeder. publish_builds capability gerekir.
Body:
{
"version": "0.1.5-nightly",
"config": "Development",
"platform": "Win64",
"executable_path": "HeroRPG/Binaries/Win64/HeroRPG.exe",
"release_notes": "Nightly build of main branch, 2026-05-15",
"files": [
{ "path": "HeroRPG.exe", "hash": "abc123...", "size_bytes": 12345678 },
{ "path": "HeroRPG/Content/Paks/pak0.pak", "hash": "def456...", "size_bytes": 2147483648 }
]
}
GET /api/builds/{repo_id}
Yayımlanan build'leri listeler. İndirme bağlantılarını görmek için download_builds capability gerekir.
Response 200:
{
"success": true,
"data": [
{
"id": 5,
"version": "0.1.5-nightly",
"config": "Development",
"platform": "Win64",
"published_by": "ci-nightly",
"published_at": "2026-05-15T03:00:00Z",
"size_bytes": 2159829326,
"file_count": 142,
"release_notes": "Nightly build of main branch, 2026-05-15"
}
]
}
GET /api/builds/{repo_id}/{build_id}/file
Bir build'den bir dosya indirir. download_builds capability gerekir. Bir build'in manifest'i GET /api/builds/{repo_id}/{build_id}/manifest üzerinden kullanılabilir.
Yönetim
Tüm /api/admin/* rotaları, kullanıcının en az bir admin capability'sine sahip olmasını gerektirir
(uç noktaya göre: manage_users, manage_permissions, manage_rules vb.).
Aşağıda özlü belgeler var. Çoğu, standart REST desenini (GET/POST/PUT/DELETE) izler.
| Rota | Capability | Açıklama |
|---|---|---|
GET/POST /api/admin/users | manage_users | Kullanıcıları listeler / oluşturur |
PUT/DELETE /api/admin/users/{id} | manage_users | Günceller / siler |
POST /api/admin/users/{id}/reset-password | manage_users | Şifreyi sıfırlar, token_version'ı artırır |
GET/POST /api/admin/groups | manage_users | Grup yönetimi |
GET/POST /api/admin/permissions/{repo_id} | manage_permissions | Yola göre glob izin kuralları |
GET/POST /api/admin/repositories/{repo_id}/rules | manage_rules | Checkin öncesi doğrulama kuralları |
GET/POST /api/admin/repositories/{repo_id}/webhooks | manage_rules | Discord / Slack / Teams / custom |
GET /api/admin/audit | view_all_activity | Filtrelenmiş ve sayfalanmış audit log |
GET /api/admin/stats | view_all_activity | Storage metrics, dedup ratio, büyüme |
GET /api/admin/repositories/{repo_id}/gc/preview | admin | Çalıştırmadan GC önizlemesi |
POST /api/admin/repositories/{repo_id}/gc | admin | Garbage collection'ı başlatır |
POST /api/admin/locks/{id}/force-release | force_unlock | Üçüncü tarafa ait bir kilidi zorla açar, denetlenir |
Sağlık
GET /health
Sunucu veritabanına erişebiliyorsa 200 OK döndüren kimlik doğrulaması gerektirmeyen uç nokta.
Yük dengeleyici veya izleme sağlık kontrolleri için kullanılır (Prometheus blackbox, Datadog synthetic vb.).
Response 200: OK (text/plain).
Response 503: veritabanına ulaşılamıyorsa.
GET /api/server-info
Sunucu meta verilerini (sürüm vb.) döndüren genel, kimlik doğrulaması gerektirmeyen uç nokta.
/health gibi, auth ara katmanı tarafından korunmaz.
Hata biçimi
Hata durumunda yanıt, uygun bir HTTP status ile { "success": false, "error": "..." }'dir.
error alanı, insan tarafından okunabilir bir mesajdır. Kararlı, makine tarafından okunabilir kodlara
ihtiyaç duyan istemciler için, öneki ayrıştırın (ör.: "Permission denied: ..." her zaman "Permission denied" ile başlar).
| HTTP | Anlamı | Ne zaman |
|---|---|---|
| 400 | Bad request | Geçersiz parametre, bozuk JSON, çok büyük body (sabit 413 sınırından önce) |
| 401 | Not authenticated | Token yok, süresi dolmuş, imza geçersiz, ya da token_version uyuşmazlığı |
| 403 | Permission denied | Eksik capability, ya da yol / depo üzerinde izin yok |
| 404 | Resource not found | Depo / dosya / commit / kullanıcı mevcut değil veya erişilemez |
| 409 | Conflict | Kilit zaten tutuluyor, eşzamanlı commit, benzersiz kısıtlama ihlali |
| 413 | Payload too large | Body sınırın ötesinde (/files'te 1 GB, /builds/upload'da 8 GB) |
| 429 | Too many requests | Yalnızca /auth/login'de (kullanıcı başına hız sınırlama) |
| 500 | Internal server error | DB hatası, IO hatası. Sunucu tarafında loglanır; hatayı bildirirseniz timestamp ekleyin. |
| 503 | Service unavailable | Veritabanına ulaşılamıyor (health check) veya migrasyon sürüyor |