# 📖 GOOGLE LOGIN FLOW - LUỒNG ĐĂNG NHẬP GOOGLE SSO

## 📋 TỔNG QUAN

Luồng đăng nhập Google SSO với tích hợp Keycloak và quản lý user trong hệ thống multi-tenant.

---

## 🗄️ CÁC BẢNG DỮ LIỆU

### 1. **`users`** (Bảng gốc - Default Connection)

**Mục đích:** Lưu trữ thông tin user chính trong hệ thống.

**Các trường quan trọng:**
- `id`: ID user
- `email`: Email đăng nhập
- `username`: Tên đăng nhập
- `name`: Tên hiển thị
- `password`: Mật khẩu (hashed)
- `type`: Loại user (mặc định = 0)
- `google_id`: ID từ Google SSO

**Connection:** Default connection (không phải tenant connection)

---

### 2. **`user_create_requests`** (Bảng gốc - Default Connection)

**Mục đích:** Tracking trạng thái tạo user và đăng nhập.

**Các trường:**
- `id`: Primary key
- `user_id`: Foreign key đến `users.id`
- `tenant_code`: Mã tenant (lấy từ `HelperTenant::getCurrentTenantInfo()`)
- `status`: Trạng thái
  - `0`: User đã được tạo trên Keycloak nhưng chưa đăng nhập
  - `1`: User đã đăng nhập vào hệ thống
- `created_at`, `updated_at`: Timestamps

**Connection:** Default connection

**Indexes:**
- `user_id`
- `tenant_code`
- `status`

---

### 3. **`user_logs`** (Bảng gốc - Default Connection)

**Mục đích:** Log các hoạt động đăng nhập của user.

**Các trường:**
- `id`: Primary key
- `user_id`: Foreign key đến `users.id`
- `tenant_code`: Mã tenant
- `time_login`: Thời gian đăng nhập
- `action`: Hành động (ví dụ: 'login', 'logout', etc.)
- `created_at`, `updated_at`: Timestamps

**Connection:** Default connection

**Indexes:**
- `user_id`
- `tenant_code`
- `time_login`

---

## 🔄 LUỒNG HOẠT ĐỘNG

### **Bước 1: Google OAuth Callback**

```
1. User click "Đăng nhập với Google"
   ↓
2. Google OAuth redirect về: /auth/google/callback
   ↓
3. Controller: GoogleController@handleGoogleCallback
   ↓
4. Lấy thông tin user từ Google: $googleUser = Socialite::driver('google')->user()
```

---

### **Bước 2: Kiểm tra User trong Bảng Users Gốc**

```
1. Lấy email từ Google: $email = $googleUser->getEmail()
   ↓
2. Query: User::where('email', $email)->first()
   ↓
3. Kiểm tra kết quả:
   
   ❌ NẾU KHÔNG CÓ USER:
   → return view('unauthorized')
   → Dừng luồng, không cho đăng nhập
   
   ✅ NẾU CÓ USER:
   → Tiếp tục bước 3
```

**Lưu ý:** User phải được tạo trước trong bảng `users` (có thể tạo thủ công hoặc qua API).

---

### **Bước 3: Kiểm tra User trên Keycloak**

```
1. Query Keycloak: $keycloakAdminService->findUserByEmail($email)
   ↓
2. Lấy tenant_code từ HelperTenant::getCurrentTenantInfo()
   ↓
3. Kiểm tra kết quả:
```

#### **Trường hợp 3A: KHÔNG CÓ USER TRÊN KEYCLOAK**

```
1. Tạo mới user trên Keycloak:
   - username: email
   - email: email
   - firstName: từ Google
   - lastName: từ Google
   - password: 'Hocmai@1234' (temporary = false)
   - enabled: true
   - emailVerified: true
   ↓
2. Tạo record trong user_create_requests:
   - user_id: $user->id
   - tenant_code: từ HelperTenant::getCurrentTenantInfo()['code']
   - status: 0 (đã tạo nhưng chưa đăng nhập)
   ↓
3. Redirect về trang chủ với message:
   → "Tài khoản đã được tạo trên Keycloak. Vui lòng đăng nhập lại."
   ↓
4. KẾT THÚC (không cho đăng nhập ngay)
```

---

#### **Trường hợp 3B: CÓ USER TRÊN KEYCLOAK**

```
1. Update user_create_requests:
   - Tìm record với user_id và tenant_code
   - Update status = 1 (đã đăng nhập)
   - Nếu không có record → tạo mới với status = 1
   ↓
2. Tạo record trong user_logs:
   - user_id: $user->id
   - tenant_code: từ HelperTenant::getCurrentTenantInfo()['code']
   - time_login: now()
   - action: 'login'
   ↓
3. Đăng nhập user:
   → Auth::login($user)
   ↓
4. Tiếp tục bước 4 (xử lý tenant)
```

---

### **Bước 4: Xử lý Tenant và Redirect**

```
1. Kiểm tra user có được phép dùng tenant feature:
   → HelperTenant::isUserAllowedForTenant($user->email)
   
   ❌ NẾU KHÔNG ĐƯỢC PHÉP:
   → Redirect về /dashboard
   → KẾT THÚC
   
   ✅ NẾU ĐƯỢC PHÉP:
   ↓
2. Kiểm tra user có tenant membership:
   → HelperTenant::userHasTenants($user->id)
   
   ❌ NẾU KHÔNG CÓ TENANT:
   → Redirect về /waiting-for-tenant
   → KẾT THÚC
   
   ✅ NẾU CÓ TENANT:
   ↓
3. Lấy danh sách tenants:
   → HelperTenant::getUserTenants($user->id)
   ↓
4. Xử lý theo số lượng tenant:
   
   📌 NẾU CÓ 1 TENANT:
   → Tự động chọn tenant đó
   → Setup tenant connection
   → Lưu thông tin tenant vào session
   → Redirect về /dashboard
   
   📌 NẾU CÓ NHIỀU TENANT:
   → Redirect về /auth/tenant-selection (cho user chọn)
```

---

## 📊 SƠ ĐỒ LUỒNG

```
┌─────────────────────┐
│ Google OAuth Login  │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ Get Email từ Google │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────────────┐
│ Check User trong users table│
│ WHERE email = $email        │
└──────────┬──────────────────┘
           │
    ┌──────┴──────┐
    │             │
   NO            YES
    │             │
    ▼             ▼
┌─────────┐  ┌─────────────────────┐
│UNAUTHOR │  │ Check User trên KC  │
│IZED     │  └──────────┬──────────┘
└─────────┘             │
                 ┌──────┴──────┐
                 │             │
                NO            YES
                 │             │
                 ▼             ▼
        ┌─────────────┐  ┌──────────────────┐
        │Create KC    │  │Update status = 1 │
        │User         │  │Create user_logs  │
        │Create       │  │Login user        │
        │request      │  └────────┬─────────┘
        │status = 0   │           │
        │Redirect     │           │
        └─────────────┘           ▼
                          ┌──────────────┐
                          │Process Tenant│
                          │& Redirect    │
                          └──────────────┘
```

---

## 🔍 CÁC TRƯỜNG HỢP XỬ LÝ

### **Case 1: User chưa tồn tại trong hệ thống**

- **Bảng users:** ❌ Không có
- **Keycloak:** ❓ Không kiểm tra
- **Kết quả:** `return view('unauthorized')`

---

### **Case 2: User có trong hệ thống, chưa có trên Keycloak**

- **Bảng users:** ✅ Có
- **Keycloak:** ❌ Không có
- **Hành động:**
  1. Tạo user trên Keycloak
  2. Tạo `user_create_requests` với `status = 0`
  3. Redirect với message thành công
- **Kết quả:** User phải đăng nhập lại lần sau mới vào được

---

### **Case 3: User có trong hệ thống và có trên Keycloak**

- **Bảng users:** ✅ Có
- **Keycloak:** ✅ Có
- **Hành động:**
  1. Update `user_create_requests` với `status = 1`
  2. Tạo record trong `user_logs`
  3. Đăng nhập user (`Auth::login($user)`)
  4. Xử lý tenant và redirect
- **Kết quả:** User được đăng nhập vào hệ thống

---

## 📝 LƯU Ý QUAN TRỌNG

1. **User phải được tạo trước trong bảng `users`:**
   - Có thể tạo thủ công qua admin panel
   - Hoặc qua API `/ssouser/user/store`
   - User không thể tự tạo qua Google login

2. **Tenant Code:**
   - Lấy từ `HelperTenant::getCurrentTenantInfo()['code']`
   - Có thể `null` nếu không có tenant context

3. **Status trong `user_create_requests`:**
   - `0`: User đã tạo trên KC nhưng chưa đăng nhập lần nào
   - `1`: User đã đăng nhập ít nhất 1 lần

4. **User Logs:**
   - Chỉ được tạo khi user đăng nhập thành công (case 3)
   - Mỗi lần đăng nhập sẽ tạo 1 record mới
   - Có thể dùng để tracking và audit

---

## 🛠️ MIGRATION COMMANDS

Để tạo các bảng, chạy:

```bash
php artisan migrate
```

Hoặc rollback nếu cần:

```bash
php artisan migrate:rollback --step=2
```

---

## ✅ CHECKLIST REVIEW

- [ ] User phải có trong bảng `users` trước khi đăng nhập
- [ ] Keycloak user được tạo với password mặc định 'Hocmai@1234'
- [ ] `user_create_requests` được tạo với `status = 0` khi tạo KC user
- [ ] `user_create_requests` được update với `status = 1` khi đăng nhập
- [ ] `user_logs` được tạo mỗi lần đăng nhập thành công
- [ ] Tenant code được lấy từ `HelperTenant::getCurrentTenantInfo()`
- [ ] Flow xử lý tenant hoạt động đúng (single/multiple tenant)

---

**Ngày tạo:** 2025-12-13  
**Phiên bản:** 1.0

