feat(arayüz): API istemcisi, TanStack Query, ts-rs tip üretimi ve oturum durumu

- Backend: ts-rs ile DTO'lardan TypeScript tipleri (frontend/src/types, npm run types)
- Hata ve health yanıtları tipli yapılara çevrildi
- lib/api.ts: tek API istemcisi, Türkçe ApiError, ağ hatası mesajı
- lib/query.ts: QueryClient (4xx tekrar denenmez, 401 → oturum kapanır)
- lib/auth.ts: useMe, useLogin, useRegister, useLogout
- Vitest: 7 API istemcisi testi (toplam 29)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-12 00:39:56 +03:00
parent f9be08114d
commit 906f05f62f
41 changed files with 558 additions and 49 deletions
+25 -6
View File
@@ -6,7 +6,24 @@ use axum::{
http::StatusCode,
response::{IntoResponse, Response},
};
use serde_json::json;
use serde::Serialize;
use ts_rs::TS;
/// Tüm hata yanıtlarının gövdesi: `{ "error": { "code": "...", "message": "..." } }`
#[derive(Serialize, TS)]
#[ts(export)]
pub struct ApiErrorBody {
pub error: ApiErrorDetail,
}
#[derive(Serialize, TS)]
#[ts(export)]
pub struct ApiErrorDetail {
/// Makine için: `unauthorized`, `bad_request`, `conflict`, `not_found`, ...
pub code: String,
/// Kullanıcıya gösterilecek Türkçe mesaj
pub message: String,
}
#[derive(Debug, thiserror::Error)]
pub enum AppError {
@@ -59,11 +76,13 @@ impl IntoResponse for AppError {
self.to_string()
};
(
status,
Json(json!({ "error": { "code": code, "message": message } })),
)
.into_response()
let body = ApiErrorBody {
error: ApiErrorDetail {
code: code.into(),
message,
},
};
(status, Json(body)).into_response()
}
}