# Profile

**Author**: Josh S. Sakweli, Backend Lead Team  
**Last Updated**: 2025-01-05  
**Version**: v1.0

**Base URL**: `https://api.fursahub.com/api/v1`

**Short Description**: Profile management endpoints for Fursa Hub. Allows users to view and update their profile information, manage photos, change theme and language preferences. Profile completion is the final step of onboarding.

**Hints**: 
- All profile endpoints require authentication (Bearer token)
- Username must be unique and can only contain letters, numbers, and underscores
- Profile photos should be uploaded via Files API first, then URLs added here
- Completing profile (fullName + username + bio) auto-completes onboarding if at final step
- Theme changes take effect immediately on client side

---

## Profile in Onboarding Context

```
┌─────────────────────────────────────────────────────────────────────────┐
│                     PROFILE & ONBOARDING RELATIONSHIP                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  Profile data comes from multiple sources:                               │
│                                                                          │
│  1. FIREBASE (auto-filled at registration)                              │
│     └── fullName (from Google/Apple account)                            │
│     └── profilePhotoUrl (from social account)                           │
│     └── email (from auth provider)                                      │
│                                                                          │
│  2. REGISTRATION (user choice)                                          │
│     └── preferredLanguage                                               │
│     └── theme                                                           │
│                                                                          │
│  3. ONBOARDING (user completes)                                         │
│     └── phoneNumber (verified via OTP)                                  │
│     └── preferences (from onboarding pages)                             │
│                                                                          │
│  4. PROFILE COMPLETION (final step)                                     │
│     └── username (required, unique)                                     │
│     └── bio (required)                                                  │
│     └── fullName (can edit Firebase default)                            │
│     └── gender, link (optional)                                         │
│                                                                          │
│  When user completes: fullName + username + bio                         │
│  └── Onboarding auto-completes if at PENDING_PROFILE_COMPLETION         │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## Endpoints

---

## 1. Get Profile
**Purpose**: Retrieve current user's complete profile information.

**Endpoint**: <span style="background-color: #28a745; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">GET</span> `{base_url}/profile`

**Access Level**: 🔒 Protected

**Authentication**: Bearer Token

**Request Headers**:
| Header | Type | Required | Description |
|--------|------|----------|-------------|
| Authorization | string | Yes | `Bearer {accessToken}` |

**Success Response JSON Sample**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Profile retrieved",
  "action_time": "2025-01-05T10:30:45",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "username": "johndoe",
    "phoneNumber": "+255712345678",
    "fullName": "John Doe",
    "bio": "Software developer passionate about tech",
    "gender": "MALE",
    "link": "https://johndoe.com",
    "profilePhotoUrls": [
      "https://files.fursahub.com/bucket/profile/photo1.jpg",
      "https://files.fursahub.com/bucket/profile/photo2.jpg"
    ],
    "primaryPhotoUrl": "https://files.fursahub.com/bucket/profile/photo1.jpg",
    "isPhoneVerified": true,
    "isEmailVerified": true,
    "preferredLanguage": "sw",
    "theme": "DARK",
    "authProvider": "GOOGLE",
    "role": "ROLE_USER",
    "onboardingStatus": "COMPLETED",
    "isOnboardingComplete": true,
    "createdAt": "2025-01-01T08:00:00",
    "updatedAt": "2025-01-05T10:30:00"
  }
}
```

**Success Response Fields**:
| Field | Description |
|-------|-------------|
| id | Unique user identifier (UUID) |
| email | User's email address |
| username | Unique username (lowercase) |
| phoneNumber | Verified phone number in E.164 format |
| fullName | Display name |
| bio | User biography/description |
| gender | `MALE` or `FEMALE` |
| link | Personal website or social link |
| profilePhotoUrls | Array of all profile photo URLs |
| primaryPhotoUrl | First photo URL (main profile picture) |
| isPhoneVerified | Phone verification status |
| isEmailVerified | Email verification status |
| preferredLanguage | Language code (en, sw, fr, zh) |
| theme | `LIGHT`, `DARK`, or `SYSTEM` |
| authProvider | `GOOGLE`, `APPLE`, or `EMAIL` |
| role | User role (ROLE_USER, ROLE_ADMIN, etc.) |
| onboardingStatus | Current onboarding step |
| isOnboardingComplete | `true` if onboarding finished |

---

## 2. Update Profile
**Purpose**: Update user profile information. Only provided fields are updated.

**Endpoint**: <span style="background-color: #ffc107; color: black; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">PUT</span> `{base_url}/profile`

**Access Level**: 🔒 Protected

**Authentication**: Bearer Token

**Request Headers**:
| Header | Type | Required | Description |
|--------|------|----------|-------------|
| Authorization | string | Yes | `Bearer {accessToken}` |
| Content-Type | string | Yes | `application/json` |

**Request JSON Sample**:
```json
{
  "fullName": "John Doe Updated",
  "username": "johndoe_new",
  "bio": "Building the future of opportunity in East Africa",
  "gender": "MALE",
  "link": "https://linkedin.com/in/johndoe",
  "profilePhotoUrls": [
    "https://files.fursahub.com/bucket/profile/new-photo.jpg"
  ],
  "theme": "LIGHT",
  "preferredLanguage": "en"
}
```

**Request Body Parameters**:
| Parameter | Type | Required | Description | Validation |
|-----------|------|----------|-------------|------------|
| fullName | string | No | Display name | Min: 2, Max: 100 chars |
| username | string | No | Unique username | Min: 3, Max: 30 chars, alphanumeric + underscore only |
| bio | string | No | User biography | Max: 500 chars |
| gender | string | No | User gender | enum: `MALE`, `FEMALE` |
| link | string | No | Personal/social link | Must be valid URL (https://...) |
| profilePhotoUrls | array | No | List of photo URLs | Array of strings |
| theme | string | No | UI theme preference | enum: `LIGHT`, `DARK`, `SYSTEM` |
| preferredLanguage | string | No | Language preference | Must be active language code |

**Success Response JSON Sample**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Profile updated",
  "action_time": "2025-01-05T10:35:00",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "username": "johndoe_new",
    "fullName": "John Doe Updated",
    "bio": "Building the future of opportunity in East Africa",
    "theme": "LIGHT",
    "preferredLanguage": "en",
    "onboardingStatus": "COMPLETED",
    "isOnboardingComplete": true
  }
}
```

**Error Responses**:

*Username Already Taken (409):*
```json
{
  "success": false,
  "httpStatus": "CONFLICT",
  "message": "Username already taken",
  "action_time": "2025-01-05T10:35:00",
  "data": "Username already taken"
}
```

*Invalid Language Code (400):*
```json
{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Invalid or inactive language code: xx",
  "action_time": "2025-01-05T10:35:00",
  "data": "Invalid or inactive language code: xx"
}
```

*Validation Error (422):*
```json
{
  "success": false,
  "httpStatus": "UNPROCESSABLE_ENTITY",
  "message": "Validation failed",
  "action_time": "2025-01-05T10:35:00",
  "data": {
    "username": "Username can only contain letters, numbers, and underscores",
    "fullName": "Name must be 2-100 characters"
  }
}
```

---

## 3. Update Theme (Quick Toggle)
**Purpose**: Quick endpoint to change theme without full profile update.

**Endpoint**: <span style="background-color: #fd7e14; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">PATCH</span> `{base_url}/profile/theme`

**Access Level**: 🔒 Protected

**Authentication**: Bearer Token

**Request JSON Sample**:
```json
{
  "theme": "DARK"
}
```

**Request Body Parameters**:
| Parameter | Type | Required | Description | Validation |
|-----------|------|----------|-------------|------------|
| theme | string | Yes | Theme preference | enum: `LIGHT`, `DARK`, `SYSTEM` |

**Success Response JSON Sample**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Theme updated",
  "action_time": "2025-01-05T10:40:00",
  "data": {
    "theme": "DARK"
  }
}
```

---

## 4. Check Username Availability
**Purpose**: Check if a username is available before updating profile.

**Endpoint**: <span style="background-color: #28a745; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">GET</span> `{base_url}/profile/username/check`

**Access Level**: 🔒 Protected

**Authentication**: Bearer Token

**Query Parameters**:
| Parameter | Type | Required | Description | Validation |
|-----------|------|----------|-------------|------------|
| username | string | Yes | Username to check | Min: 3 chars |

**Success Response JSON Sample (Available)**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Username available",
  "action_time": "2025-01-05T10:45:00",
  "data": {
    "username": "newusername",
    "available": true
  }
}
```

**Success Response JSON Sample (Taken)**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Username taken",
  "action_time": "2025-01-05T10:45:00",
  "data": {
    "username": "existinguser",
    "available": false
  }
}
```

---

## 5. Add Profile Photo
**Purpose**: Add a new photo to user's profile photos array.

**Endpoint**: <span style="background-color: #007bff; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">POST</span> `{base_url}/profile/photo`

**Access Level**: 🔒 Protected

**Authentication**: Bearer Token

**Request JSON Sample**:
```json
{
  "photoUrl": "https://files.fursahub.com/bucket/profile/new-photo.jpg"
}
```

**Request Body Parameters**:
| Parameter | Type | Required | Description | Validation |
|-----------|------|----------|-------------|------------|
| photoUrl | string | Yes | URL of uploaded photo | Must be valid URL |

**Success Response JSON Sample**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Photo added",
  "action_time": "2025-01-05T10:50:00",
  "data": {
    "profilePhotoUrls": [
      "https://files.fursahub.com/bucket/profile/photo1.jpg",
      "https://files.fursahub.com/bucket/profile/new-photo.jpg"
    ],
    "primaryPhotoUrl": "https://files.fursahub.com/bucket/profile/photo1.jpg"
  }
}
```

---

## 6. Remove Profile Photo
**Purpose**: Remove a photo from user's profile photos array.

**Endpoint**: <span style="background-color: #dc3545; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">DELETE</span> `{base_url}/profile/photo`

**Access Level**: 🔒 Protected

**Authentication**: Bearer Token

**Query Parameters**:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| photoUrl | string | Yes | URL of photo to remove |

**Success Response JSON Sample**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Photo removed",
  "action_time": "2025-01-05T10:55:00",
  "data": {
    "profilePhotoUrls": [
      "https://files.fursahub.com/bucket/profile/photo1.jpg"
    ],
    "primaryPhotoUrl": "https://files.fursahub.com/bucket/profile/photo1.jpg"
  }
}
```

---

## Frontend Implementation Guide

### Profile Completion Screen
```
When onboardingStatus = "PENDING_PROFILE_COMPLETION":

1. GET /profile to fetch current data
2. Show form with:
   ├── fullName (pre-filled from Firebase)
   ├── username (auto-generated, editable)
   │   └── On change: GET /profile/username/check
   ├── bio (required)
   ├── gender (optional)
   └── link (optional)
3. PUT /profile with form data
4. If isOnboardingComplete = true → Navigate to home
```

### Settings Screen
```
Theme Toggle:
└── PATCH /profile/theme with selected theme
└── Apply theme immediately on client

Language Change:
└── PUT /profile with preferredLanguage
└── Reload UI with new language strings

Profile Edit:
└── PUT /profile with changed fields only
```

### Photo Management
```
Adding Photo:
1. Upload via Files API (POST /files/upload-single)
2. Get permanentUrl from response
3. POST /profile/photo with photoUrl

Removing Photo:
1. DELETE /profile/photo?photoUrl=...
2. Optionally delete from Files API
```