Files
next-go-blog/SOFT_DELETE_MANAGEMENT.md
Beyhan Oğur 6d95e27114 first commit
2026-04-26 22:16:43 +03:00

415 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Soft Delete Kullanıcı Yönetimi
## Genel Bakış
AuthCentral'da silinen kullanıcılar soft delete ile yönetilir. Bu, kullanıcıların veritabanından silinmeden sadece işaretlenerek pasif hale getirilmesi anlamına gelir.
## Yeni Endpoint'ler
### 1. Silinen Kullanıcıları Listele
```bash
GET /v1/admin/users/deleted
```
**Query Parameters:**
- `page` (int, optional) - Sayfa numarası (default: 1)
- `limit` (int, optional) - Sayfa başına kayıt (default: 10, max: 100)
**Örnek:**
```bash
TOKEN=$(curl -s -X POST http://localhost:8080/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@gauth.local","password":"Admin@123"}' | jq -r '.access_token')
curl -X GET "http://localhost:8080/v1/admin/users/deleted?page=1&limit=10" \
-H "Authorization: Bearer $TOKEN"
```
**Yanıt:**
```json
{
"users": [
{
"id": "ca567947-ef2a-49ad-b955-bf0ef6bbf136",
"username": "Delete Me",
"email": "deleteme@test.com",
"avatar": "",
"email_verified": true,
"created_at": "2026-02-05T00:03:08.360433+03:00",
"updated_at": "2026-02-05T00:03:08.38027+03:00",
"deleted_at": "2026-02-05T00:03:25.549299+03:00",
"roles": [
{
"id": 2,
"name": "user",
"description": "Default user role"
}
],
"social_accounts": []
}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 12,
"totalPages": 2
}
}
```
**Özellikler:**
-`deleted_at` field'ı görünür (normal endpoint'lerde gizli)
- ✅ Pagination desteği
- ✅ Sadece soft delete edilmiş kullanıcılar gösterilir
- ✅ En son silinen kullanıcılar önce gelir (deleted_at DESC)
### 2. Kullanıcıyı Geri Yükle (Restore)
```bash
POST /v1/admin/users/{id}/restore
```
**Path Parameters:**
- `id` (uuid, required) - Kullanıcı ID
**Örnek:**
```bash
TOKEN=$(curl -s -X POST http://localhost:8080/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@gauth.local","password":"Admin@123"}' | jq -r '.access_token')
USER_ID="ca567947-ef2a-49ad-b955-bf0ef6bbf136"
curl -X POST "http://localhost:8080/v1/admin/users/$USER_ID/restore" \
-H "Authorization: Bearer $TOKEN"
```
**Başarılı Yanıt:**
```json
{
"message": "User restored successfully"
}
```
**Hata Yanıtları:**
```json
{
"error": "deleted user not found"
}
```
## Kullanım Senaryoları
### Senaryo 1: Silinen Kullanıcıları İnceleme
```bash
#!/bin/bash
# Admin login
TOKEN=$(curl -s -X POST http://localhost:8080/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@gauth.local","password":"Admin@123"}' | jq -r '.access_token')
# Tüm silinen kullanıcıları listele
echo "=== Deleted Users ==="
curl -s -X GET "http://localhost:8080/v1/admin/users/deleted" \
-H "Authorization: Bearer $TOKEN" | jq '.users[] | {id, email, username, deleted_at}'
```
### Senaryo 2: Kullanıcıyı Soft Delete ve Restore
```bash
#!/bin/bash
TOKEN=$(curl -s -X POST http://localhost:8080/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@gauth.local","password":"Admin@123"}' | jq -r '.access_token')
USER_ID="abc-123-def-456"
# 1. Kullanıcıyı soft delete yap
echo "Step 1: Soft delete user"
curl -s -X DELETE "http://localhost:8080/v1/admin/users/$USER_ID" \
-H "Authorization: Bearer $TOKEN" | jq '.'
# 2. Silinen kullanıcılar listesinde kontrol et
echo -e "\nStep 2: Check deleted users"
curl -s -X GET "http://localhost:8080/v1/admin/users/deleted" \
-H "Authorization: Bearer $TOKEN" | jq ".users[] | select(.id==\"$USER_ID\")"
# 3. Kullanıcıyı geri yükle
echo -e "\nStep 3: Restore user"
curl -s -X POST "http://localhost:8080/v1/admin/users/$USER_ID/restore" \
-H "Authorization: Bearer $TOKEN" | jq '.'
# 4. Normal kullanıcı listesinde kontrol et
echo -e "\nStep 4: Verify user is restored"
curl -s -X GET "http://localhost:8080/v1/admin/users/$USER_ID" \
-H "Authorization: Bearer $TOKEN" | jq '{id, email, username}'
```
### Senaryo 3: Frontend İçin Silinen Kullanıcılar Yönetimi
**Frontend JavaScript Örneği:**
```javascript
// API Client
class AdminAPI {
constructor(baseURL, token) {
this.baseURL = baseURL;
this.token = token;
}
async getDeletedUsers(page = 1, limit = 10) {
const response = await fetch(
`${this.baseURL}/v1/admin/users/deleted?page=${page}&limit=${limit}`,
{
headers: {
'Authorization': `Bearer ${this.token}`
}
}
);
return response.json();
}
async restoreUser(userId) {
const response = await fetch(
`${this.baseURL}/v1/admin/users/${userId}/restore`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`
}
}
);
return response.json();
}
async softDeleteUser(userId) {
const response = await fetch(
`${this.baseURL}/v1/admin/users/${userId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${this.token}`
}
}
);
return response.json();
}
async hardDeleteUser(userId) {
const response = await fetch(
`${this.baseURL}/v1/admin/users/${userId}?hard=true`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${this.token}`
}
}
);
return response.json();
}
}
// Kullanım
const admin = new AdminAPI('http://localhost:8080', YOUR_TOKEN);
// Silinen kullanıcıları getir
const deletedUsers = await admin.getDeletedUsers(1, 10);
console.log(deletedUsers);
// Kullanıcıyı geri yükle
const result = await admin.restoreUser('user-uuid-here');
console.log(result);
```
## API Endpoint'leri Özeti
| Endpoint | Method | Açıklama | Query/Body |
|----------|--------|----------|------------|
| `/v1/admin/users` | GET | Aktif kullanıcılar | `?page=1&limit=10` |
| `/v1/admin/users/deleted` | GET | **Silinen kullanıcılar** | `?page=1&limit=10` |
| `/v1/admin/users/{id}` | DELETE | Soft delete | - |
| `/v1/admin/users/{id}?hard=true` | DELETE | Hard delete (kalıcı) | `?hard=true` |
| `/v1/admin/users/{id}/restore` | POST | **Kullanıcıyı geri yükle** | - |
## Soft Delete vs Hard Delete
| Özellik | Soft Delete | Hard Delete |
|---------|-------------|-------------|
| **Veritabanı** | `deleted_at` timestamp set edilir | Tamamen silinir |
| **Görünürlük** | `/deleted` endpoint'inde görünür | Hiçbir yerde görünmez |
| **Geri Getirme** | ✅ `/restore` ile mümkün | ❌ İmkansız |
| **İlişkiler** | Korunur | Silinir |
| **Kullanım** | Varsayılan, güvenli | Dikkatli kullanılmalı |
| **Komut** | `DELETE /users/{id}` | `DELETE /users/{id}?hard=true` |
## Frontend Entegrasyonu
### React Örneği
```jsx
import React, { useState, useEffect } from 'react';
function DeletedUsersManager() {
const [deletedUsers, setDeletedUsers] = useState([]);
const [loading, setLoading] = useState(false);
const [page, setPage] = useState(1);
const fetchDeletedUsers = async () => {
setLoading(true);
try {
const response = await fetch(
`http://localhost:8080/v1/admin/users/deleted?page=${page}&limit=10`,
{
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
}
);
const data = await response.json();
setDeletedUsers(data.users);
} catch (error) {
console.error('Error fetching deleted users:', error);
} finally {
setLoading(false);
}
};
const restoreUser = async (userId) => {
if (!confirm('Bu kullanıcıyı geri yüklemek istediğinize emin misiniz?')) {
return;
}
try {
const response = await fetch(
`http://localhost:8080/v1/admin/users/${userId}/restore`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
}
);
if (response.ok) {
alert('Kullanıcı başarıyla geri yüklendi!');
fetchDeletedUsers(); // Listeyi yenile
}
} catch (error) {
console.error('Error restoring user:', error);
}
};
useEffect(() => {
fetchDeletedUsers();
}, [page]);
return (
<div className="deleted-users-manager">
<h2>Silinen Kullanıcılar</h2>
{loading ? (
<p>Yükleniyor...</p>
) : (
<table>
<thead>
<tr>
<th>Email</th>
<th>Kullanıcı Adı</th>
<th>Silinme Tarihi</th>
<th>İşlemler</th>
</tr>
</thead>
<tbody>
{deletedUsers.map(user => (
<tr key={user.id}>
<td>{user.email}</td>
<td>{user.username}</td>
<td>{new Date(user.deleted_at).toLocaleString('tr-TR')}</td>
<td>
<button onClick={() => restoreUser(user.id)}>
Geri Yükle
</button>
</td>
</tr>
))}
</tbody>
</table>
)}
<div className="pagination">
<button onClick={() => setPage(p => Math.max(1, p - 1))}>
Önceki
</button>
<span>Sayfa {page}</span>
<button onClick={() => setPage(p => p + 1)}>
Sonraki
</button>
</div>
</div>
);
}
export default DeletedUsersManager;
```
## Güvenlik Notları
**İyi Pratikler:**
- Silinen kullanıcıları düzenli olarak gözden geçirin
- Restore işleminden önce kullanıcıyı doğrulayın
- Hard delete yapmadan önce soft delete kullanın
- Kritik kullanıcılar için restore geçmişi tutun
⚠️ **Dikkat Edilmesi Gerekenler:**
- Sadece admin rolündeki kullanıcılar bu endpoint'lere erişebilir
- Restore edilen kullanıcı önceki tüm rolleri ve ayarları ile geri gelir
- Soft delete edilmiş kullanıcılar login yapamaz
- Hard delete geri alınamaz, dikkatli kullanın
## Test Komutları
```bash
# 1. Kullanıcı oluştur
TOKEN=$(curl -s -X POST http://localhost:8080/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@gauth.local","password":"Admin@123"}' | jq -r '.access_token')
curl -X POST http://localhost:8080/v1/admin/users \
-H "Authorization: Bearer $TOKEN" \
-F "email=test@example.com" \
-F "password=test123" \
-F "user_name=Test User" \
-F "roles=user"
# 2. Kullanıcıyı soft delete yap
curl -X DELETE "http://localhost:8080/v1/admin/users/USER_ID" \
-H "Authorization: Bearer $TOKEN"
# 3. Silinen kullanıcıları listele
curl -X GET "http://localhost:8080/v1/admin/users/deleted" \
-H "Authorization: Bearer $TOKEN" | jq '.'
# 4. Kullanıcıyı geri yükle
curl -X POST "http://localhost:8080/v1/admin/users/USER_ID/restore" \
-H "Authorization: Bearer $TOKEN"
```
## Özet
🎯 **Yeni Özellikler:**
- ✅ Silinen kullanıcıları listeleme
- ✅ Kullanıcıyı geri yükleme (restore)
-`deleted_at` field'ı görünürlüğü
- ✅ Pagination desteği
- ✅ Frontend entegrasyonu için hazır
📊 **Kullanım:**
- Soft delete varsayılan silme yöntemi
- Hard delete sadece kalıcı silme için
- Restore ile yanlışlıkla silinen kullanıcılar kurtarılabilir
- Frontend'de silinen kullanıcılar yönetilebilir