# Dating App - Mobile Development Guide

## Project Overview

A modern dating application with swipe-based matching, real-time chat, premium subscriptions, and Firebase push notifications. The backend REST API is built with CodeIgniter 3 (PHP 8.4) and is fully functional and tested (51 endpoints) at `http://localhost/dating_app/ci3_backend_api/`.

---

## API Configuration

### Base URL
```
Production: https://api.yourdatingapp.com/v1
Development: http://localhost/dating_app/ci3_backend_api/v1
```

### Authentication
- **Type**: JWT Bearer Token
- **Header**: `Authorization: Bearer <token>`
- **Token Expiry**: 7 days
- **Refresh**: Use `/auth/refresh_token` endpoint (30-day grace period)

### Response Format
All endpoints return:
```json
{
  "status": true|false,
  "message": "...",
  "data": { ... }
}
```

---

## API Endpoints Reference

### Authentication

| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| POST | `/auth/register` | Register new user | No |
| POST | `/auth/login` | Login user | No |
| POST | `/auth/logout` | Logout user | Yes |
| POST | `/auth/forgot_password` | Request password reset | No |
| POST | `/auth/reset_password` | Reset password with token | No |
| POST | `/auth/refresh_token` | Refresh JWT token | Yes |

#### Register Request
```json
{
  "email": "user@example.com",
  "password": "securepassword",
  "full_name": "John Doe",
  "phone": "+1234567890"
}
```

#### Login Request
```json
{
  "email": "user@example.com",
  "password": "securepassword"
}
```

#### Login Response
```json
{
  "status": true,
  "message": "Login successful",
  "data": {
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
    "user": {
      "id": 1,
      "email": "user@example.com",
      "full_name": "John Doe",
      "is_verified": true,
      "is_premium": false
    }
  }
}
```

#### Reset Password Request
```json
{
  "token": "reset_token_from_email",
  "password": "newsecurepassword"
}
```

#### Logout Request
```json
{
  "push_token": "fcm_device_token_to_unregister"
}
```

### User Profile

| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| GET | `/users/profile` | Get current user profile | Yes |
| GET | `/users/view/{id}` | Get public profile by ID | Yes |
| POST | `/users/update_profile` | Update user profile | Yes |
| POST | `/users/location` | Update user location | Yes |
| POST | `/users/upload_photo` | Upload profile photo (multipart) | Yes |
| DELETE | `/users/photo/{id}` | Delete a photo | Yes |
| POST | `/users/photo/primary` | Set primary photo | Yes |
| POST | `/users/change_password` | Change password | Yes |
| POST | `/users/verify_email` | Verify email address | Yes |
| DELETE | `/users/account` | Delete account (soft-delete) | Yes |

#### Profile Response
```json
{
  "status": true,
  "message": "User profile",
  "data": {
    "user": {
      "id": "2",
      "email": "john@example.com",
      "full_name": "John Smith",
      "phone": null,
      "is_verified": true,
      "is_premium": false,
      "premium_until": null,
      "bio": "Love hiking and photography",
      "interests": ["travel", "music", "cooking"],
      "gender": "male",
      "age": 28,
      "job_title": "Software Engineer",
      "company": "Tech Corp",
      "education": "MIT",
      "city": "New York",
      "country": "USA",
      "height": 180,
      "looking_for": "relationship",
      "relationship_type": "monogamous",
      "drinking": "socially",
      "smoking": "never",
      "children": "want_someday",
      "religion": "agnostic",
      "pref_min_age": 18,
      "pref_max_age": 50,
      "pref_distance": 50,
      "pref_gender": "female",
      "photos": [
        {
          "id": "1",
          "photo_url": "https://example.com/photo.jpg",
          "is_primary": true,
          "status": "approved",
          "created_at": "2026-01-13 02:36:49"
        }
      ]
    }
  }
}
```

#### Update Profile Request
```json
{
  "full_name": "John Smith",
  "bio": "Love hiking and photography",
  "gender": "male",
  "age": 28,
  "interests": ["travel", "music", "cooking"],
  "job_title": "Software Engineer",
  "company": "Tech Corp",
  "education": "MIT",
  "city": "New York",
  "country": "USA",
  "height": 180,
  "looking_for": "relationship",
  "relationship_type": "monogamous",
  "drinking": "socially",
  "smoking": "never",
  "children": "want_someday",
  "religion": "agnostic"
}
```

**Validation Rules:**
- `age`: 18–120
- `height`: 50–300
- `gender`: male | female | other
- `looking_for`: relationship | casual | friendship | both
- `drinking` / `smoking`: never | socially | regularly
- `children`: have | want | dont_want | want_someday
- `interests`: JSON array

#### Upload Photo Request
Multipart form data:
- `photo` (file, required): Max 5MB, jpg/png/gif/webp
- `is_primary` (string, optional): `"0"` or `"1"`
- Max 6 photos per user

#### Set Primary Photo Request
```json
{
  "photo_id": 1
}
```

#### Change Password Request
```json
{
  "current_password": "oldpassword",
  "new_password": "newsecurepassword"
}
```

#### Update Location Request
```json
{
  "latitude": 40.7128,
  "longitude": -74.0060
}
```

#### Delete Account Request
```json
{
  "password": "yourpassword"
}
```

### Discovery (Swiping)

| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| GET | `/discovery/cards` | Get swipeable profiles | Yes |
| POST | `/discovery/like` | Like a user | Yes |
| POST | `/discovery/pass` | Pass on a user | Yes |
| POST | `/discovery/superlike` | Super like a user | Yes |
| POST | `/discovery/rewind` | Undo last swipe (premium) | Yes |
| GET | `/discovery/likes_me` | See who liked you | Yes |
| POST | `/discovery/boost` | Boost profile (premium) | Yes |
| GET | `/discovery/get_preferences` | Get discovery preferences | Yes |
| POST | `/discovery/preferences` | Update preferences | Yes |

#### Discovery Cards Response
```json
{
  "status": true,
  "message": "Discovery cards",
  "data": {
    "cards": [
      {
        "id": 3,
        "full_name": "Jane Doe",
        "age": 25,
        "bio": "Adventure seeker",
        "city": "Los Angeles",
        "distance_km": 15.5,
        "photos": [
          {
            "id": 2,
            "photo_url": "https://example.com/jane.jpg",
            "is_primary": true
          }
        ],
        "interests": ["travel", "photography"],
        "job_title": "Designer",
        "education": "UCLA"
      }
    ],
    "count": 1
  }
}
```

#### Like/Pass/Superlike Request
> **⚠️ Field name is `target_user_id`, NOT `user_id`**

```json
{
  "target_user_id": 3
}
```

#### Like Response (Match!)
```json
{
  "status": true,
  "message": "It's a match!",
  "data": {
    "is_match": true,
    "match_id": 5,
    "matched_user": {
      "id": 3,
      "full_name": "Jane Doe",
      "photo_url": "https://example.com/jane.jpg"
    }
  }
}
```

#### Superlike Response
```json
{
  "status": true,
  "message": "Super liked!",
  "data": {
    "is_match": false,
    "remaining_superlikes": 2
  }
}
```

#### Rewind Response (Premium Only)
```json
{
  "status": true,
  "message": "Last swipe undone",
  "data": {
    "rewound_user": {
      "id": 3,
      "full_name": "Jane Doe",
      "photo_url": "https://example.com/jane.jpg"
    },
    "remaining_rewinds": 2
  }
}
```

#### Likes Me Response (Premium)
```json
{
  "status": true,
  "message": "Users who liked you",
  "data": {
    "users": [
      {
        "id": 5,
        "full_name": "Sarah Wilson",
        "photo_url": "https://example.com/sarah.jpg",
        "age": 27,
        "liked_at": "2026-01-13 03:00:00"
      }
    ],
    "count": 1
  }
}
```

#### Likes Me Response (Free — Premium Feature Gate)
```json
{
  "status": true,
  "message": "Upgrade to Premium to see who likes you",
  "data": {
    "count": 3,
    "is_premium_feature": true
  }
}
```

#### Boost Response (Premium Only)
```json
{
  "status": true,
  "message": "Profile boosted for 30 minutes!",
  "data": {
    "expires_at": "2026-01-13 03:30:00"
  }
}
```

#### Discovery Preferences Request
> **⚠️ Field names are `min_age`, `max_age`, `distance_km`, `gender_preference` — NOT `pref_min_age` etc.**

```json
{
  "min_age": 22,
  "max_age": 35,
  "distance_km": 50,
  "gender_preference": "female"
}
```

#### Discovery Preferences Response
```json
{
  "status": true,
  "message": "Discovery preferences",
  "data": {
    "preferences": {
      "pref_min_age": 22,
      "pref_max_age": 35,
      "pref_distance": 50,
      "pref_gender": "female"
    }
  }
}
```

**Daily Limits (Free Users):**
- Swipes (like/pass): 50/day
- Super Likes: 3/day
- Rewind: Not available
- Boost: Not available

**Daily Limits (Premium Users):**
- Swipes: Unlimited
- Super Likes: 5/day
- Rewind: 3/day
- Boost: 1/day

### Matches

| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| GET | `/matches/list` | Get all matches | Yes |
| GET | `/matches/detail/{match_id}` | Get match detail with partner profile | Yes |
| POST | `/matches/swipe` | Alternative swipe endpoint | Yes |

#### Matches List Response
```json
{
  "status": true,
  "message": "Matches list",
  "data": {
    "new_matches": [
      {
        "id": 1,
        "full_name": "Jane Doe",
        "photo_url": "https://example.com/jane.jpg",
        "matched_at": "2026-01-13 02:36:19"
      }
    ],
    "conversations": [
      {
        "match_id": 1,
        "partner_id": 3,
        "partner_name": "Jane Doe",
        "partner_photo": "https://example.com/jane.jpg",
        "last_message": "Hey! How are you?",
        "last_message_at": "2026-01-13 03:00:00",
        "unread_count": 2,
        "matched_at": "2026-01-13 02:36:19"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 5,
      "pages": 1
    }
  }
}
```

#### Match Detail Response
```json
{
  "status": true,
  "message": "Match detail",
  "data": {
    "match_id": 1,
    "matched_at": "2026-01-13 02:36:19",
    "partner": {
      "id": 3,
      "full_name": "Jane Doe",
      "bio": "Adventure seeker",
      "age": 25,
      "city": "Los Angeles",
      "photos": [],
      "interests": ["travel"]
    }
  }
}
```

#### Swipe Request (Alternative)
```json
{
  "target_user_id": 3,
  "action": "like"
}
```
Valid actions: `like`, `dislike`, `superlike`

### Chat/Messaging

| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| GET | `/chat/conversations` | Get all conversations | Yes |
| GET | `/chat/messages/{match_id}` | Get messages for match | Yes |
| POST | `/chat/send` | Send a message | Yes |
| DELETE | `/chat/message/{id}` | Delete a message (soft-delete, sender only) | Yes |
| POST | `/chat/typing` | Send typing indicator (FCM data push) | Yes |
| GET | `/chat/unread` | Get unread message count | Yes |

#### Conversations Response
```json
{
  "status": true,
  "message": "Conversations list",
  "data": {
    "conversations": [
      {
        "match_id": "1",
        "matched_at": "2026-01-13 02:36:19",
        "last_message": "Hey! How are you?",
        "last_message_at": "2026-01-13 03:00:00",
        "partner_id": "3",
        "partner_name": "Jane Doe",
        "partner_photo": "https://example.com/jane.jpg",
        "unread_count": 2
      }
    ]
  }
}
```

#### Messages Response
```json
{
  "status": true,
  "message": "Messages",
  "data": {
    "messages": [
      {
        "id": "1",
        "match_id": "1",
        "sender_id": "2",
        "message": "Hey! How are you?",
        "message_type": "text",
        "is_read": false,
        "read_at": null,
        "is_deleted": false,
        "created_at": "2026-01-13 02:36:19",
        "sender_name": "John Smith"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 50,
      "total": 10,
      "pages": 1
    }
  }
}
```

**Notes:**
- Messages are automatically marked as read when fetched
- 410 status returned if match is inactive (unmatched)
- Max message length: 5000 characters
- Sending a message triggers FCM push notification to partner

#### Send Message Request
```json
{
  "match_id": 1,
  "message": "Hey! How are you?",
  "message_type": "text"
}
```
Valid message types: `text`, `image`, `gif` (default: `text`)

#### Send Message Response
```json
{
  "status": true,
  "message": "Message sent",
  "data": {
    "message_id": 15,
    "created_at": "2026-01-13 03:00:00"
  }
}
```

#### Typing Indicator Request
```json
{
  "match_id": 1,
  "is_typing": true
}
```

#### Unread Count Response
```json
{
  "status": true,
  "message": "Unread count",
  "data": {
    "unread_count": 5
  }
}
```

### Notifications

| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| GET | `/notifications` | Get notifications | Yes |
| POST | `/notifications/read` | Mark as read | Yes |
| GET | `/notifications/count` | Get unread count | Yes |
| POST | `/notifications/settings` | Update notification settings | Yes |
| POST | `/notifications/token` | Register FCM push token | Yes |

#### Notifications Response
```json
{
  "status": true,
  "message": "Notifications",
  "data": {
    "notifications": [
      {
        "id": 1,
        "type": "match",
        "title": "New Match!",
        "message": "You matched with Jane",
        "data": {"match_id": 1, "user_id": 3},
        "is_read": false,
        "created_at": "2026-01-13 03:00:00",
        "sender_name": "Jane Doe",
        "sender_photo": "https://example.com/jane.jpg"
      }
    ],
    "unread_count": 5,
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 15,
      "pages": 1
    }
  }
}
```

#### Mark as Read Request
```json
{
  "notification_id": 1
}
```
Or mark all as read:
```json
{
  "all": true
}
```

#### Notification Settings Request
```json
{
  "push_matches": true,
  "push_messages": true,
  "push_likes": true,
  "email_notifications": false
}
```

#### Register Push Token Request
> **⚠️ Field name is `platform`, NOT `device_type`**

```json
{
  "token": "fcm_device_token_here",
  "platform": "ios"
}
```
Valid platforms: `ios`, `android`

### Report & Block

| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| POST | `/report/user` | Report a user | Yes |
| POST | `/report/block` | Block a user | Yes |
| POST | `/report/unblock` | Unblock a user | Yes |
| GET | `/report/blocked` | Get blocked users | Yes |
| POST | `/report/unmatch` | Unmatch a user | Yes |

#### Report User Request
> **⚠️ Field name is `user_id`, NOT `reported_user_id`**

```json
{
  "user_id": 5,
  "reason": "inappropriate",
  "description": "Sending inappropriate messages"
}
```
Valid reasons: `inappropriate`, `fake`, `harassment`, `spam`, `other`

#### Block/Unblock Request
```json
{
  "user_id": 5
}
```

**Notes:**
- Blocking also soft-deletes any active match between the users
- Blocked users are excluded from discovery cards

#### Blocked Users Response
```json
{
  "status": true,
  "message": "Blocked users",
  "data": {
    "blocked_users": [
      {
        "id": 5,
        "full_name": "Blocked User",
        "photo_url": "https://example.com/user.jpg",
        "blocked_at": "2026-01-13 03:00:00"
      }
    ]
  }
}
```

#### Unmatch Request
```json
{
  "match_id": 1
}
```

**Note:** Unmatch performs a soft-delete (`is_active=0`, `unmatched_by` recorded)

### Subscription (Premium)

| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| GET | `/subscription/plans` | Get available plans | Yes |
| GET | `/subscription/status` | Get subscription status | Yes |
| POST | `/subscription/purchase` | Purchase subscription | Yes |
| POST | `/subscription/cancel` | Cancel subscription | Yes |
| POST | `/subscription/restore` | Restore purchase | Yes |
| GET | `/subscription/history` | Get purchase history | Yes |

#### Plans Response
```json
{
  "status": true,
  "message": "Subscription plans",
  "data": {
    "plans": [
      {
        "id": "monthly",
        "name": "1 Month",
        "duration_months": 1,
        "price": 14.99,
        "price_per_month": 14.99,
        "currency": "USD",
        "savings_percent": 0,
        "badge": null,
        "features": [
          "Unlimited likes",
          "See who likes you",
          "5 Super Likes per day",
          "3 Rewinds per day",
          "1 Boost per day",
          "No ads"
        ]
      },
      {
        "id": "6months",
        "name": "6 Months",
        "duration_months": 6,
        "price": 59.99,
        "price_per_month": 10.00,
        "currency": "USD",
        "savings_percent": 33,
        "badge": "Popular",
        "features": ["...same features..."]
      },
      {
        "id": "12months",
        "name": "12 Months",
        "duration_months": 12,
        "price": 89.99,
        "price_per_month": 7.50,
        "currency": "USD",
        "savings_percent": 50,
        "badge": "Best Value",
        "features": ["...same features..."]
      }
    ]
  }
}
```

#### Subscription Status Response
```json
{
  "status": true,
  "message": "Subscription status",
  "data": {
    "is_premium": true,
    "subscription": {
      "plan_name": "6 Months",
      "starts_at": "2026-01-13",
      "expires_at": "2026-07-13",
      "is_active": true,
      "payment_method": "apple_pay"
    },
    "days_remaining": 182
  }
}
```

#### Purchase Request
```json
{
  "plan_id": "6months",
  "transaction_id": "TXN_123456",
  "payment_method": "apple_pay",
  "receipt": "base64_receipt_data_here"
}
```
Valid payment methods: `apple_pay`, `google_pay`, `stripe`, `card`

**Note:** If user already has an active subscription, the new plan extends from the current expiry date.

#### Cancel Response
```json
{
  "status": true,
  "message": "Subscription cancelled. Access continues until expiry date.",
  "data": {
    "premium_until": "2026-07-13"
  }
}
```

#### Restore Request
```json
{
  "transaction_id": "TXN_123456"
}
```

### Settings

| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| GET | `/settings` | Get app settings | Yes |

#### Settings Response
```json
{
  "status": true,
  "message": "App settings",
  "data": {
    "settings": {
      "max_photos": "6",
      "max_photo_size_mb": "5",
      "free_swipes_per_day": "50",
      "free_superlikes_per_day": "3",
      "premium_superlikes_per_day": "5",
      "boost_duration_minutes": "30",
      "app_version": "1.0.0",
      "maintenance_mode": "0"
    }
  }
}
```

---

## Data Models

### User
```typescript
interface User {
  id: number;
  email: string;
  full_name: string;
  phone?: string;
  is_verified: boolean;
  is_premium: boolean;
  premium_until?: string;
  created_at: string;
}
```

### UserProfile
```typescript
interface UserProfile {
  id: number;
  email: string;
  full_name: string;
  phone?: string;
  is_verified: boolean;
  is_premium: boolean;
  premium_until?: string;
  bio?: string;
  gender: 'male' | 'female' | 'other';
  age: number;
  interests?: string[];
  job_title?: string;
  company?: string;
  education?: string;
  city?: string;
  country?: string;
  height?: number;
  looking_for: 'relationship' | 'casual' | 'friendship' | 'both';
  relationship_type?: string;
  drinking?: 'never' | 'socially' | 'regularly';
  smoking?: 'never' | 'socially' | 'regularly';
  children?: 'have' | 'want' | 'dont_want' | 'want_someday';
  religion?: string;
  latitude?: number;
  longitude?: number;
  pref_min_age: number;
  pref_max_age: number;
  pref_distance: number;
  pref_gender: 'male' | 'female' | 'both';
  photos: Photo[];
}
```

### Photo
```typescript
interface Photo {
  id: number;
  photo_url: string;
  is_primary: boolean;
  status: 'pending' | 'approved' | 'rejected';
  created_at: string;
}
```

### DiscoveryCard
```typescript
interface DiscoveryCard {
  id: number;
  full_name: string;
  age: number;
  bio?: string;
  city?: string;
  distance_km?: number;
  photos: Photo[];
  interests: string[];
  job_title?: string;
  education?: string;
}
```

### Match
```typescript
interface Match {
  id: number;
  user1_id: number;
  user2_id: number;
  matched_at: string;
  last_message?: string;
  last_message_at?: string;
  is_active: boolean;
  unmatched_by?: number;
}
```

### Conversation
```typescript
interface Conversation {
  match_id: number;
  matched_at: string;
  last_message?: string;
  last_message_at?: string;
  partner_id: number;
  partner_name: string;
  partner_photo?: string;
  unread_count: number;
}
```

### Message
```typescript
interface Message {
  id: number;
  match_id: number;
  sender_id: number;
  message: string;
  message_type: 'text' | 'image' | 'gif';
  is_read: boolean;
  read_at?: string;
  is_deleted: boolean;
  created_at: string;
  sender_name?: string;
}
```

### Notification
```typescript
interface Notification {
  id: number;
  user_id: number;
  type: 'match' | 'message' | 'like' | 'superlike' | 'system';
  title: string;
  message: string;
  data?: Record<string, any>;
  is_read: boolean;
  created_at: string;
  sender_name?: string;
  sender_photo?: string;
}
```

### SubscriptionPlan
```typescript
interface SubscriptionPlan {
  id: string;           // 'monthly' | '6months' | '12months'
  name: string;
  duration_months: number;
  price: number;
  price_per_month: number;
  currency: string;
  savings_percent: number;
  badge?: string;
  features: string[];
}
```

### SubscriptionRecord
```typescript
interface SubscriptionRecord {
  id: number;
  plan_name: string;
  price: number;
  currency: string;
  starts_at: string;
  expires_at: string;
  is_active: boolean;
  payment_method: string;
  transaction_id: string;
  created_at: string;
}
```

### Pagination
```typescript
interface Pagination {
  page: number;
  limit: number;
  total: number;
  pages: number;
}
```

---

## ⚠️ Critical Field Name Reference

These field names are **exactly what the API expects**. Using wrong names will cause errors:

| Context | Correct Field | ~~Incorrect~~ |
|---------|--------------|----------------|
| Like/Pass/Superlike body | `target_user_id` | ~~`user_id`~~ |
| Update preferences body | `min_age` | ~~`pref_min_age`~~ |
| Update preferences body | `max_age` | ~~`pref_max_age`~~ |
| Update preferences body | `distance_km` | ~~`pref_distance`~~ |
| Update preferences body | `gender_preference` | ~~`pref_gender`~~ |
| Reset password body | `password` | ~~`new_password`~~ |
| Push token body | `platform` | ~~`device_type`~~ |
| Report user body | `user_id` | ~~`reported_user_id`~~ |
| Subscription purchase body | `plan_id` | — |
| Subscription purchase body | `transaction_id` | — |
| Subscription purchase body | `payment_method` | — |
| Subscription purchase body | `receipt` | — |

---

## App Screens & Features

### 1. Onboarding Flow
- **Splash Screen**: Logo animation, auto-login check via token refresh
- **Welcome Screen**: 3-page carousel with feature highlights
- **Login Screen**: Email/password login
- **Register Screen**: Multi-step registration
  - Step 1: Email, password, name, phone (optional)
  - Step 2: Profile basics (gender, age, looking for)
  - Step 3: Photo upload (minimum 1, max 6)
  - Step 4: Bio and interests (min 3 interests)
- **Forgot Password**: Email input → reset token flow

### 2. Main Navigation (Bottom Tab Bar)
- **Discover** (🔥 fire/cards icon)
- **Matches** (❤️ heart icon) — badge: new match count
- **Chat** (💬 message icon) — badge: unread count
- **Profile** (👤 user icon)

Badge counts: poll `/chat/unread` and `/notifications/count` every 30 seconds, or react to FCM push.

### 3. Discover Screen
- **Card Stack**: Swipeable profile cards (3 visible, top = interactive)
- **Card Content**:
  - Primary photo with gradient overlay
  - Name, age, distance
  - Job title, education
  - Bio preview
  - Shared interests badges
- **Swipe Actions**:
  - Swipe left = Pass → `POST /discovery/pass` with `target_user_id`
  - Swipe right = Like → `POST /discovery/like` with `target_user_id`
  - Swipe up = Super Like → `POST /discovery/superlike` with `target_user_id`
  - Tap = View full profile
- **Action Buttons** (below card):
  - ↩️ Rewind (gold, premium only) → `POST /discovery/rewind`
  - ✖️ Pass (red)
  - ⭐ Super Like (blue)
  - ❤️ Like (green)
  - ⚡ Boost (purple, premium only) → `POST /discovery/boost`
- **Overlay Stamps**: green "LIKE", red "NOPE", blue "SUPER LIKE" while swiping
- **Filter Button**: Top-right → opens Discovery Preferences
- **Rate Limited (429)**: Show premium upgrade prompt

### 4. Profile Detail View
- **Photo Gallery**: Swipeable photos with dots indicator
- **Info Sections**:
  - About (bio)
  - Basics (job, education, location)
  - Lifestyle (height, drinking, smoking, children, religion)
  - Interests (tags/chips)
- **Actions**: Like, Super Like, Report, Block

### 5. Matches Screen
- **New Matches**: Horizontal scrollable avatars (from `new_matches`)
- **Conversations**: Vertical list (from `conversations`)
  - Partner photo, name
  - Last message preview (truncated)
  - Relative timestamp
  - Unread badge
- Pull to refresh

### 6. Chat Screen
- **Header**: Partner photo, name, actions menu (unmatch, report, block)
- **Messages**: Bubble-style messages
  - Sent (right-aligned, coral gradient bubble, white text)
  - Received (left-aligned, light gray bubble, dark text)
  - Date separators between groups
  - Timestamps below each bubble
  - Read receipts (double check icon)
- **Typing Indicator**: Bouncing dots animation at bottom
- **Input Bar**: Text field, send button (disabled when empty), emoji, image picker
- **Behavior**:
  - On open: `GET /chat/messages/{match_id}?page=1&limit=50`
  - Scroll up → load more (infinite scroll)
  - Send: `POST /chat/send` → append optimistically
  - Typing: debounce 1s → `POST /chat/typing` (is_typing: true/false)
  - Poll for new messages every 5 seconds (or react to FCM)
  - 410 response → show "Conversation ended", disable input

### 7. Profile Screen
- **Header**: Primary photo, name, age
- **Edit Profile**: Navigate to edit screen
- **Settings Sections**:
  - Discovery Preferences
  - Notification Settings
  - Privacy Settings
  - Account Settings (change password, delete account)
  - Blocked Users
  - Premium/Subscription
  - Help & Support
  - Logout → `POST /auth/logout`

### 8. Edit Profile Screen
- **Photos**: 2×3 grid of 6 slots, add/remove, first = primary
- **Basic Info**: Name, bio (max 500 chars), job, company, education
- **Details**: City, country, height, gender, looking for
- **Lifestyle**: Drinking, smoking, children, religion (pill button selectors)
- **Interests**: Tag selection from predefined list (min 3)
- **Save Button**: Sticky at bottom → `POST /users/update_profile`

### 9. Settings Screens
- **Discovery Preferences**:
  - Age range slider (18–100)
  - Distance slider (1–500 km)
  - Gender preference (Male / Female / Both)
  - Save → `POST /discovery/preferences` with `min_age`, `max_age`, `distance_km`, `gender_preference`
- **Notifications**:
  - Push: matches, messages, likes (toggles)
  - Email notifications toggle
  - Save → `POST /notifications/settings`
- **Account**:
  - Change password → `POST /users/change_password`
  - Delete account → `DELETE /users/account`
- **Blocked Users**:
  - List → `GET /report/blocked`
  - Unblock → `POST /report/unblock`

### 10. Premium Features Screen
- **Benefits Grid** (2 column):
  - ♾️ Unlimited Likes
  - 👀 See Who Likes You
  - ↩️ Rewind Last Swipe
  - ⚡ Boost Your Profile
  - ⭐ 5 Super Likes/Day
  - 🚫 No Ads
- **Plan Cards**:

| Plan | Price | Per Month | Badge |
|------|-------|-----------|-------|
| Monthly | $14.99 | $14.99/mo | — |
| 6 Months | $59.99 | $10.00/mo | Popular (Save 33%) |
| 12 Months | $89.99 | $7.50/mo | Best Value (Save 50%) ⭐ |

- **Subscribe Button**: Triggers in-app purchase → `POST /subscription/purchase` with receipt
- **Restore Purchases**: `POST /subscription/restore`

### 11. Notifications Screen
- List of notifications with icons by type:
  - 💕 Match → coral heart icon
  - 💬 Message → chat bubble icon
  - ❤️ Like → heart icon
  - ⭐ Super Like → star icon
  - 📢 System → bell icon
- Each: icon, title, message, relative time, unread dot
- Tap → navigate based on data (match_id, etc.)
- Mark as read on view

### 12. FCM Push Notifications
- **Initialization**: Request permission → get FCM token → `POST /notifications/token` with `platform`
- **Token Refresh**: Listen `onTokenRefresh` → re-register
- **Foreground**: Show local notification banner
- **Background/Terminated**: Tap → deep link based on type:
  - `match` → Chat screen
  - `message` → Chat screen
  - `like` → Discovery or Premium
  - `typing` → Data-only, update typing indicator (no visible notification)

---

## UI/UX Guidelines

### Color Palette
```scss
// Primary Colors
$primary: #FF6B6B;        // Coral Red - main brand color
$primary-dark: #E85555;   // Darker shade for pressed states
$primary-light: #FF8A8A;  // Lighter shade for backgrounds

// Secondary Colors  
$secondary: #4ECDC4;      // Teal - accents
$accent: #FFE66D;         // Yellow - highlights, super like

// Neutral Colors
$background: #FFFFFF;
$surface: #F8F9FA;
$text-primary: #2D3436;
$text-secondary: #636E72;
$text-muted: #B2BEC3;
$border: #DFE6E9;

// Semantic Colors
$success: #00B894;
$warning: #FDCB6E;
$error: #D63031;
$info: #0984E3;

// Gradients
$gradient-primary: linear-gradient(135deg, #FF6B6B 0%, #FF8E53 100%);
$gradient-premium: linear-gradient(135deg, #667EEA 0%, #764BA2 100%);

// Action Button Colors
$pass-red: #FF6B6B;
$like-green: #00B894;
$superlike-blue: #0984E3;
$rewind-gold: #FDCB6E;
$boost-purple: #764BA2;
```

### Typography
```scss
// Font Family
$font-primary: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;

// Font Sizes
$text-xs: 12px;
$text-sm: 14px;
$text-base: 16px;
$text-lg: 18px;
$text-xl: 20px;
$text-2xl: 24px;
$text-3xl: 30px;
$text-4xl: 36px;

// Font Weights
$font-regular: 400;
$font-medium: 500;
$font-semibold: 600;
$font-bold: 700;
```

### Spacing
```scss
$space-1: 4px;
$space-2: 8px;
$space-3: 12px;
$space-4: 16px;
$space-5: 20px;
$space-6: 24px;
$space-8: 32px;
$space-10: 40px;
$space-12: 48px;
```

### Border Radius
```scss
$radius-sm: 4px;
$radius-md: 8px;
$radius-lg: 12px;
$radius-xl: 16px;
$radius-2xl: 24px;
$radius-full: 9999px;
```

### Shadows
```scss
$shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
$shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
$shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
$shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15);
```

### Component Styles

#### Buttons
```scss
.btn-primary {
  background: $gradient-primary;
  color: white;
  border-radius: $radius-full;
  padding: $space-4 $space-6;
  font-weight: $font-semibold;
  box-shadow: $shadow-md;
}

.btn-secondary {
  background: white;
  color: $primary;
  border: 2px solid $primary;
  border-radius: $radius-full;
}

.btn-icon {
  width: 56px;
  height: 56px;
  border-radius: $radius-full;
  box-shadow: $shadow-lg;
}
```

#### Cards
```scss
.profile-card {
  border-radius: $radius-xl;
  overflow: hidden;
  box-shadow: $shadow-xl;
  height: 580px;
}

.match-card {
  border-radius: $radius-lg;
  padding: $space-4;
  background: white;
}
```

#### Input Fields
```scss
.input-field {
  border: 1px solid $border;
  border-radius: $radius-lg;
  padding: $space-4;
  font-size: $text-base;
  
  &:focus {
    border-color: $primary;
    box-shadow: 0 0 0 3px rgba($primary, 0.1);
  }
}
```

---

## Technical Specifications

### Recommended Tech Stack: Flutter + GetX

```yaml
dependencies:
  flutter:
    sdk: flutter

  # State Management & DI & Routing
  get: ^4.6.6

  # Networking
  dio: ^5.7.0

  # Storage
  get_storage: ^2.1.1
  flutter_secure_storage: ^9.2.2

  # Firebase
  firebase_core: ^3.8.0
  firebase_messaging: ^15.1.5

  # Image Handling
  cached_network_image: ^3.4.1
  image_picker: ^1.1.2
  image_cropper: ^8.0.2

  # Location
  geolocator: ^13.0.1
  geocoding: ^3.0.0

  # UI Components
  flutter_card_swiper: ^7.0.1
  smooth_page_indicator: ^1.2.0+3
  shimmer: ^3.0.0
  lottie: ^3.1.3
  flutter_animate: ^4.5.0
  confetti: ^0.7.0

  # Forms & Validation
  flutter_form_builder: ^9.4.1
  form_builder_validators: ^11.0.0

  # In-App Purchase
  in_app_purchase: ^3.2.0

  # Utilities
  intl: ^0.19.0
  url_launcher: ^6.3.1
  permission_handler: ^11.3.1
  connectivity_plus: ^6.1.0
  package_info_plus: ^8.1.1
  flutter_local_notifications: ^18.0.1
  path_provider: ^2.1.4
  uuid: ^4.5.1
  logger: ^2.5.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^5.0.0
  build_runner: ^2.4.12
  mockito: ^5.4.4
  flutter_launcher_icons: ^0.14.2
  flutter_native_splash: ^2.4.2
```

### Architecture: Clean MVC + GetX
```
Pattern: Clean Architecture with MVC separation
State Management: GetX (GetxController + Obx)
DI: GetX Bindings (lazy put)
Navigation: GetX Named Routes with middleware
HTTP Client: Dio with interceptors
Local Storage: get_storage (general) + flutter_secure_storage (tokens)
```

### Folder Structure (Flutter)
```
lib/
├── main.dart                          # App entry, init GetStorage, Firebase, DI
├── app.dart                           # GetMaterialApp with theme, routes, bindings
│
├── core/
│   ├── config/
│   │   ├── app_config.dart            # Base URLs, feature flags, timeouts
│   │   └── api_endpoints.dart         # All endpoint constants
│   ├── network/
│   │   ├── api_client.dart            # Dio singleton with base config
│   │   ├── auth_interceptor.dart      # JWT injection, 401 handling, token refresh
│   │   ├── error_interceptor.dart     # Global error parsing → AppException
│   │   └── api_response.dart          # Generic ApiResponse<T> wrapper
│   ├── storage/
│   │   ├── secure_storage.dart        # JWT token, sensitive data
│   │   └── local_storage.dart         # User prefs, cache (get_storage)
│   ├── errors/
│   │   ├── app_exception.dart         # Custom exception hierarchy
│   │   └── error_handler.dart         # Global error → user-friendly message
│   ├── theme/
│   │   ├── app_theme.dart             # ThemeData (light/dark)
│   │   ├── app_colors.dart            # Color palette constants
│   │   ├── app_text_styles.dart       # Text style presets
│   │   ├── app_dimensions.dart        # Spacing, radius, sizing constants
│   │   └── app_shadows.dart           # Shadow presets
│   ├── utils/
│   │   ├── validators.dart            # Email, password, age, phone validators
│   │   ├── date_utils.dart            # Relative time, formatting
│   │   ├── image_utils.dart           # Compression, resize before upload
│   │   └── location_utils.dart        # Permission handling, distance formatting
│   ├── widgets/                       # Reusable widgets (buttons, cards, inputs, dialogs, loaders)
│   ├── constants/
│   │   ├── app_strings.dart           # All user-facing strings
│   │   └── enums.dart                 # Gender, LookingFor, Drinking, etc.
│   ├── middleware/
│   │   └── auth_middleware.dart        # Redirect to login if no token
│   └── bindings/
│       └── initial_binding.dart        # Register all singletons
│
├── data/
│   ├── models/                        # All data models (fromJson, toJson, copyWith)
│   ├── providers/                     # API call classes per domain
│   └── repositories/                  # Business logic + caching per domain
│
├── modules/
│   ├── splash/                        # Splash screen + auto-login
│   ├── onboarding/                    # Feature highlights carousel
│   ├── auth/                          # Login, register, forgot/reset password
│   ├── home/                          # Bottom tab bar scaffold
│   ├── discovery/                     # Card stack + swipe actions
│   ├── matches/                       # Match list + conversations
│   ├── chat/                          # Messaging screen
│   ├── profile/                       # Profile view + edit
│   ├── settings/                      # Preferences, notifications, account
│   ├── subscription/                  # Premium plans + purchase
│   └── notifications/                 # Notification list
│
├── routes/
│   ├── app_routes.dart                # Route name constants
│   └── app_pages.dart                 # GetPage list with bindings & middleware
│
└── services/
    ├── auth_service.dart              # Global auth state, token management
    ├── notification_service.dart      # FCM init, foreground/background handling
    ├── location_service.dart          # GPS permission, current position
    ├── connectivity_service.dart      # Online/offline monitoring
    └── in_app_purchase_service.dart   # IAP initialization, purchase flow
```

### API Service Structure
```dart
// lib/core/network/api_client.dart
class ApiClient {
  final Dio _dio;
  
  ApiClient() : _dio = Dio(BaseOptions(
    baseUrl: AppConfig.baseUrl,
    connectTimeout: Duration(seconds: 30),
    receiveTimeout: Duration(seconds: 30),
    headers: {'Content-Type': 'application/json'},
  )) {
    _dio.interceptors.add(AuthInterceptor());
    _dio.interceptors.add(ErrorInterceptor());
    _dio.interceptors.add(LogInterceptor()); // debug only
  }
}

// lib/core/network/auth_interceptor.dart
class AuthInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    final token = SecureStorage.getToken();
    if (token != null) {
      options.headers['Authorization'] = 'Bearer $token';
    }
    handler.next(options);
  }
  
  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    if (err.response?.statusCode == 401) {
      // 1. If refresh already in flight → queue this request
      // 2. Call POST /auth/refresh_token with expired token
      // 3. If 200 → save new token → retry all queued requests
      // 4. If 401 → force logout → navigate to /login
    }
    handler.next(err);
  }
}
```

### Environment Configuration
```dart
class AppConfig {
  static String get baseUrl {
    const env = String.fromEnvironment('ENV', defaultValue: 'dev');
    switch (env) {
      case 'prod': return 'https://api.yourdatingapp.com/v1';
      default:     return 'http://localhost/dating_app/ci3_backend_api/v1';
    }
  }
}
```

```bash
# Development
flutter run --dart-define=ENV=dev

# Production
flutter build apk --dart-define=ENV=prod
flutter build ios --dart-define=ENV=prod
```

---

## Testing Credentials

### API Users
| Email | Password | Gender | Age | Description |
|-------|----------|--------|-----|-------------|
| john@example.com | password | Male | 28 | Has photos & profile |
| jane@example.com | password | Female | 25 | Has photos & profile |
| mike@example.com | password | Male | 32 | |
| sarah@example.com | password | Female | 27 | |
| alex@example.com | password | Male | 30 | |

### Development URLs
```
API Base:      http://localhost/dating_app/ci3_backend_api/v1
Swagger UI:    http://localhost/dating_app/ci3_backend_api/docs
OpenAPI JSON:  http://localhost/dating_app/ci3_backend_api/docs/openapi
Admin Panel:   http://localhost/dating_app/ci3_admin_panel/
Admin Login:   admin@datingapp.com / password
```

---

## Error Handling

### API Error Response Format
```json
{
  "status": false,
  "message": "Error message here",
  "errors": {
    "field_name": ["Validation error message"]
  }
}
```

### Common HTTP Status Codes
| Code | Meaning | Action |
|------|---------|--------|
| 200 | Success | — |
| 201 | Created | — |
| 400 | Bad Request (validation errors) | Show field-level errors inline |
| 401 | Unauthorized (invalid/expired token) | Silent refresh → if fails, logout |
| 403 | Forbidden (no permission, banned) | Show premium upgrade or "Account restricted" |
| 404 | Not Found | "Not found" screen or redirect |
| 409 | Conflict (duplicate, already interacted) | Inline message |
| 410 | Gone (conversation ended) | Disable input, "Conversation ended" |
| 422 | Unprocessable Entity | Show validation errors |
| 429 | Too Many Requests (rate limited) | Show limit dialog with upgrade CTA |
| 500 | Server Error | Snackbar "Something went wrong" |

### Snackbar Styling
- **Error**: Red left border, error icon
- **Success**: Green left border, check icon
- **Info**: Blue left border, info icon
- Position: top, floating, 3 second auto-dismiss

---

## Security Considerations

1. **Token Storage**: Use secure storage (Keychain/Keystore) — never SharedPreferences
2. **SSL Pinning**: Implement for production
3. **Input Validation**: Validate all user inputs client-side before sending
4. **Image Upload**: Validate file types (jpg/png/gif/webp), max 5MB
5. **Location**: Request permission, handle denial gracefully
6. **Biometric Auth**: Optional for quick login
7. **Session Timeout**: Auto-refresh token; force logout after 30-day grace period

---

## Performance Guidelines

1. **Image Optimization**:
   - Compress before upload (max 1024px, quality 80%)
   - Use `CachedNetworkImage` with shimmer placeholder everywhere
   - Set `memCacheWidth`/`memCacheHeight` for thumbnail contexts
   - Use WebP format when supported

2. **API Optimization**:
   - Cache `GET /users/profile` locally, refresh on pull-to-refresh
   - Cache `GET /discovery/cards` — preload next batch when 3 cards remaining
   - Cache `GET /settings` for 1 hour
   - Use pagination (`page`/`limit` params) everywhere
   - Debounce typing indicator calls (1 second)
   - Batch badge count polling: single timer for both `/chat/unread` and `/notifications/count`

3. **Offline Support**:
   - User profile: cached in GetStorage, show cached data immediately
   - Queue failed message sends → retry when online
   - Show offline banner
   - Discovery cards: show cached cards if available
   - Gracefully degrade: disable network-dependent actions

4. **Memory Management**:
   - Dispose GetxControllers properly via Bindings
   - Use `const` constructors for stateless widgets
   - Limit image cache: `PaintingBinding.instance.imageCache.maximumSize = 100`
   - Chat: only render visible messages (ListView.builder)
   - Dispose `ScrollController`, `TextEditingController` in `onClose()`

---

## Animation Guidelines

1. **Card Swipe**: Spring physics, rotation ±15° on drag, scale 0.9, velocity threshold 300px/s
2. **Match Animation**: Photos fly in from sides → meet center, heart burst Lottie, confetti, "It's a Match!" bounce text, haptic feedback
3. **Like/Pass/SuperLike Buttons**: Scale down 0.85 on press → bounce to 1.1 → 1.0, color fill from center, haptic
4. **Page Transitions**: Default right-to-left (300ms), profile detail fade-in with hero, modals bottom-to-top
5. **Loading States**: Shimmer placeholders matching layout shape (card shimmer, bubble shimmer, avatar shimmer)
6. **Pull to Refresh**: Custom `RefreshIndicator` with coral color
7. **Typing Indicator**: 3 bouncing dots with staggered timing (150ms each), muted gray
8. **Message Animations**: Sent slide from right + fade (200ms), received slide from left + fade (200ms)

---

## Accessibility

1. **Screen Reader**: Semantic labels on all elements — card reads "Name, Age, from City, Distance away"
2. **Touch Targets**: Minimum 44×44 points
3. **Color Contrast**: WCAG AA compliance (4.5:1 for text)
4. **Text Scaling**: Support `MediaQuery.textScaleFactor` — no fixed heights for text containers
5. **Motion**: Respect `MediaQuery.disableAnimations` — skip Lottie/transitions when enabled
6. **Focus Management**: Logical tab order through forms

---

## Database Schema (17 Tables)

```
users, user_profiles, user_photos, likes, matches, messages, 
blocks, reports, notifications, push_tokens, subscriptions, 
app_settings, admin_users, admin_activity_log, daily_limits, 
boosts, verification_requests
```

---

## Build & Release Checklist

- [ ] All 51 API endpoints integrated and tested
- [ ] Error handling for all failure modes (400, 401, 403, 404, 409, 410, 429, 500)
- [ ] Loading states for all async operations (shimmer placeholders)
- [ ] Empty states for all lists
- [ ] Pull-to-refresh on all list screens
- [ ] Offline mode graceful degradation
- [ ] FCM push notifications (foreground + background + terminated)
- [ ] In-app purchase flow complete (Apple Pay / Google Pay)
- [ ] Deep linking from notifications
- [ ] App icons generated for all sizes
- [ ] Splash screen configured
- [ ] Test on physical devices (iOS + Android)
- [ ] Performance profiling (no jank on card swipes)
- [ ] ProGuard rules (Android release)
- [ ] Info.plist permissions (iOS): camera, photo library, location, notifications
- [ ] AndroidManifest permissions: internet, camera, location, notifications
