# E-Commerce Search Engine

**Author**: Josh S. Sakweli, Backend Lead Team
**Last Updated**: 2025-12-30
**Version**: v1.0

**Base URL**: `https://api.nextgate.com/api/v1`

**Short Description**: Public search endpoints for discovering shops, products, and active purchase groups on the Nexgate e-commerce platform. These endpoints power the main search functionality, product discovery, and group buying features across the application.

**Hints**:
* Search query must be at least 2 characters
* Results are ordered alphabetically by name
* Filter by type using the `type` parameter: `SHOP`, `PRODUCT`, or `PURCHASE_GROUP`
* Purchase groups are searched by both name and group code (e.g., `GP-ABC123`)
* All endpoints are public and do not require authentication
* Maximum page size is 50 results
* Rate limiting applies to prevent abuse

---

## Standard Response Format

All API responses follow a consistent structure using our Globe Response Builder pattern:

### Success Response Structure
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Operation completed successfully",
  "action_time": "2025-12-30T10:30:45",
  "data": {
    // Actual response data goes here
  }
}
```

### Error Response Structure
```json
{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Error description",
  "action_time": "2025-12-30T10:30:45",
  "data": null
}
```

---

## Search Result Types

Each search result contains a `type` field indicating the result category:

| Type | Description | Specific Fields |
|------|-------------|-----------------|
| `SHOP` | Active shop/store | `shop` object |
| `PRODUCT` | Active product | `product` object |
| `PURCHASE_GROUP` | Open group purchase | `purchaseGroup` object |

---

## Endpoints

---

## 1. Global Search

**Purpose**: Search across all types (shops, products, and purchase groups) with optional type filtering

**Endpoint**: <span style="background-color: #61affe; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">GET</span> `{base_url}/api/v1/e-commerce/search`

**Access Level**: 🌐 Public (No Authentication Required)

**Query Parameters**:
| Parameter | Type | Required | Default | Description | Validation |
|-----------|------|----------|---------|-------------|------------|
| query | string | Yes | - | Search term | Min 2 characters |
| type | string | No | null (all) | Filter by type | SHOP, PRODUCT, PURCHASE_GROUP |
| page | int | No | 1 | Page number | Min 1 |
| size | int | No | 20 | Results per page | Max 50 |

**Request Examples**:
```bash
# Search all types
GET /api/v1/e-commerce/search?query=iphone&page=1&size=20

# Search shops only
GET /api/v1/e-commerce/search?query=fashion&type=SHOP

# Search products only
GET /api/v1/e-commerce/search?query=dress&type=PRODUCT

# Search purchase groups only
GET /api/v1/e-commerce/search?query=GP-ABC123&type=PURCHASE_GROUP
```

**Success Response JSON Sample**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Search results retrieved successfully",
  "action_time": "2025-12-30T10:30:45",
  "data": {
    "content": [
      {
        "type": "SHOP",
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "Fashion Hub TZ",
        "imageUrl": "https://storage.example.com/shops/logo1.jpg",
        "shop": {
          "slug": "fashion-hub-tz",
          "isVerified": true,
          "rating": 4.8,
          "productsCount": 156,
          "location": "Dar es Salaam"
        }
      },
      {
        "type": "PRODUCT",
        "id": "660e8400-e29b-41d4-a716-446655440001",
        "name": "Summer Fashion Dress",
        "imageUrl": "https://storage.example.com/products/dress1.jpg",
        "product": {
          "slug": "summer-fashion-dress",
          "price": 45000.00,
          "discountPrice": 38000.00,
          "currency": "TZS",
          "inStock": true,
          "rating": 4.5,
          "shopName": "Fashion Hub TZ",
          "shopIsVerified": true
        }
      },
      {
        "type": "PURCHASE_GROUP",
        "id": "770e8400-e29b-41d4-a716-446655440002",
        "name": "Fashion Week Special Deal",
        "imageUrl": "https://storage.example.com/products/bundle.jpg",
        "purchaseGroup": {
          "groupCode": "GP-FWS123",
          "regularPrice": 150000.00,
          "groupPrice": 120000.00,
          "savingsPercentage": 20,
          "seatsRemaining": 3,
          "totalSeats": 10,
          "expiresAt": "2025-12-31T23:59:59",
          "shopName": "Fashion Hub TZ"
        }
      }
    ],
    "page": 0,
    "size": 20,
    "totalElements": 3,
    "totalPages": 1,
    "hasNext": false,
    "hasPrevious": false,
    "shopsCount": 1,
    "productsCount": 1,
    "purchaseGroupsCount": 1
  }
}
```

**Response Fields**:
| Field | Type | Description |
|-------|------|-------------|
| content | array | List of search result items |
| page | int | Current page number (0-indexed) |
| size | int | Page size |
| totalElements | long | Total number of results |
| totalPages | int | Total number of pages |
| hasNext | boolean | Whether more pages exist |
| hasPrevious | boolean | Whether previous pages exist |
| shopsCount | long | Total shops matching query |
| productsCount | long | Total products matching query |
| purchaseGroupsCount | long | Total purchase groups matching query |

**Error Response JSON Samples**:

*Query too short:*
```json
{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Search query must be at least 2 characters",
  "action_time": "2025-12-30T10:30:45",
  "data": null
}
```

*Invalid type:*
```json
{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Invalid type. Must be: SHOP, PRODUCT, or PURCHASE_GROUP",
  "action_time": "2025-12-30T10:30:45",
  "data": null
}
```

---

## 2. Search Shops

**Purpose**: Search for active shops by name

**Endpoint**: <span style="background-color: #61affe; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">GET</span> `{base_url}/api/v1/e-commerce/search/shops`

**Access Level**: 🌐 Public (No Authentication Required)

**Query Parameters**:
| Parameter | Type | Required | Default | Description | Validation |
|-----------|------|----------|---------|-------------|------------|
| query | string | Yes | - | Shop name search term | Min 2 characters |
| page | int | No | 1 | Page number | Min 1 |
| size | int | No | 20 | Results per page | Max 50 |

**Request Example**:
```bash
GET /api/v1/e-commerce/search/shops?query=fashion&page=1&size=20
```

**Success Response JSON Sample**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Shops retrieved successfully",
  "action_time": "2025-12-30T10:30:45",
  "data": {
    "content": [
      {
        "type": "SHOP",
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "Fashion Hub TZ",
        "imageUrl": "https://storage.example.com/shops/logo1.jpg",
        "shop": {
          "slug": "fashion-hub-tz",
          "isVerified": true,
          "rating": 4.8,
          "productsCount": 156,
          "location": "Dar es Salaam"
        }
      },
      {
        "type": "SHOP",
        "id": "660e8400-e29b-41d4-a716-446655440001",
        "name": "Fashion Zone",
        "imageUrl": "https://storage.example.com/shops/logo2.jpg",
        "shop": {
          "slug": "fashion-zone",
          "isVerified": false,
          "rating": 4.2,
          "productsCount": 89,
          "location": "Arusha"
        }
      }
    ],
    "page": 0,
    "size": 20,
    "totalElements": 2,
    "totalPages": 1,
    "hasNext": false,
    "hasPrevious": false,
    "shopsCount": 2,
    "productsCount": 0,
    "purchaseGroupsCount": 0
  }
}
```

**Shop Info Fields**:
| Field | Type | Description |
|-------|------|-------------|
| slug | string | URL-friendly shop identifier |
| isVerified | boolean | Whether shop is verified |
| rating | double | Shop rating (0-5) |
| productsCount | int | Number of active products |
| location | string | Shop location |

---

## 3. Search Products

**Purpose**: Search for active products by name

**Endpoint**: <span style="background-color: #61affe; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">GET</span> `{base_url}/api/v1/e-commerce/search/products`

**Access Level**: 🌐 Public (No Authentication Required)

**Query Parameters**:
| Parameter | Type | Required | Default | Description | Validation |
|-----------|------|----------|---------|-------------|------------|
| query | string | Yes | - | Product name search term | Min 2 characters |
| page | int | No | 1 | Page number | Min 1 |
| size | int | No | 20 | Results per page | Max 50 |

**Request Example**:
```bash
GET /api/v1/e-commerce/search/products?query=dress&page=1&size=20
```

**Success Response JSON Sample**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Products retrieved successfully",
  "action_time": "2025-12-30T10:30:45",
  "data": {
    "content": [
      {
        "type": "PRODUCT",
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "Summer Dress Collection",
        "imageUrl": "https://storage.example.com/products/dress1.jpg",
        "product": {
          "slug": "summer-dress-collection",
          "price": 45000.00,
          "discountPrice": 38000.00,
          "currency": "TZS",
          "inStock": true,
          "rating": 4.5,
          "shopName": "Fashion Hub TZ",
          "shopIsVerified": true
        }
      },
      {
        "type": "PRODUCT",
        "id": "660e8400-e29b-41d4-a716-446655440001",
        "name": "Evening Dress",
        "imageUrl": "https://storage.example.com/products/dress2.jpg",
        "product": {
          "slug": "evening-dress",
          "price": 85000.00,
          "discountPrice": null,
          "currency": "TZS",
          "inStock": true,
          "rating": 4.8,
          "shopName": "Elegance Store",
          "shopIsVerified": true
        }
      },
      {
        "type": "PRODUCT",
        "id": "770e8400-e29b-41d4-a716-446655440002",
        "name": "Casual Dress",
        "imageUrl": "https://storage.example.com/products/dress3.jpg",
        "product": {
          "slug": "casual-dress",
          "price": 35000.00,
          "discountPrice": 30000.00,
          "currency": "TZS",
          "inStock": false,
          "rating": 4.0,
          "shopName": "Budget Fashion",
          "shopIsVerified": false
        }
      }
    ],
    "page": 0,
    "size": 20,
    "totalElements": 3,
    "totalPages": 1,
    "hasNext": false,
    "hasPrevious": false,
    "shopsCount": 0,
    "productsCount": 3,
    "purchaseGroupsCount": 0
  }
}
```

**Product Info Fields**:
| Field | Type | Description |
|-------|------|-------------|
| slug | string | URL-friendly product identifier |
| price | decimal | Regular price |
| discountPrice | decimal | Discounted price (null if no discount) |
| currency | string | Price currency (e.g., TZS) |
| inStock | boolean | Whether product is in stock |
| rating | double | Product rating (0-5) |
| shopName | string | Name of the shop selling this product |
| shopIsVerified | boolean | Whether the shop is verified |

---

## 4. Search Purchase Groups

**Purpose**: Search for active (open, non-expired) purchase groups by name or group code

**Endpoint**: <span style="background-color: #61affe; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">GET</span> `{base_url}/api/v1/e-commerce/search/groups`

**Access Level**: 🌐 Public (No Authentication Required)

**Query Parameters**:
| Parameter | Type | Required | Default | Description | Validation |
|-----------|------|----------|---------|-------------|------------|
| query | string | Yes | - | Group name or code | Min 2 characters |
| page | int | No | 1 | Page number | Min 1 |
| size | int | No | 20 | Results per page | Max 50 |

**Request Examples**:
```bash
# Search by group name
GET /api/v1/e-commerce/search/groups?query=iPhone Deal&page=1&size=20

# Search by group code
GET /api/v1/e-commerce/search/groups?query=GP-ABC123&page=1&size=20
```

**Success Response JSON Sample**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Purchase groups retrieved successfully",
  "action_time": "2025-12-30T10:30:45",
  "data": {
    "content": [
      {
        "type": "PURCHASE_GROUP",
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "iPhone 15 Pro - Dar es Salaam Deal",
        "imageUrl": "https://storage.example.com/products/iphone15.jpg",
        "purchaseGroup": {
          "groupCode": "GP-ABC123",
          "regularPrice": 2500000.00,
          "groupPrice": 2200000.00,
          "savingsPercentage": 12,
          "seatsRemaining": 2,
          "totalSeats": 5,
          "expiresAt": "2025-12-31T08:00:00",
          "shopName": "TechZone TZ"
        }
      },
      {
        "type": "PURCHASE_GROUP",
        "id": "660e8400-e29b-41d4-a716-446655440001",
        "name": "iPhone 15 Plus Group Buy",
        "imageUrl": "https://storage.example.com/products/iphone15plus.jpg",
        "purchaseGroup": {
          "groupCode": "GP-XYZ789",
          "regularPrice": 2200000.00,
          "groupPrice": 1950000.00,
          "savingsPercentage": 11,
          "seatsRemaining": 4,
          "totalSeats": 8,
          "expiresAt": "2025-12-30T18:00:00",
          "shopName": "Mobile World"
        }
      }
    ],
    "page": 0,
    "size": 20,
    "totalElements": 2,
    "totalPages": 1,
    "hasNext": false,
    "hasPrevious": false,
    "shopsCount": 0,
    "productsCount": 0,
    "purchaseGroupsCount": 2
  }
}
```

**Purchase Group Info Fields**:
| Field | Type | Description |
|-------|------|-------------|
| groupCode | string | Unique group code (e.g., GP-ABC123) |
| regularPrice | decimal | Original product price |
| groupPrice | decimal | Discounted group price |
| savingsPercentage | int | Percentage saved |
| seatsRemaining | int | Available seats |
| totalSeats | int | Total seats in group |
| expiresAt | datetime | Group expiration time |
| shopName | string | Name of the shop |

**Note**: Only returns groups that are:
- Status: `OPEN`
- Not expired (`expiresAt` > now)
- Not deleted

---

## Endpoints Summary

| # | Method | Endpoint | Purpose |
|---|--------|----------|---------|
| 1 | GET | `/api/v1/e-commerce/search` | Search all types |
| 2 | GET | `/api/v1/e-commerce/search/shops` | Search shops only |
| 3 | GET | `/api/v1/e-commerce/search/products` | Search products only |
| 4 | GET | `/api/v1/e-commerce/search/groups` | Search purchase groups only |

---

## Common Error Responses

| Status | Message | Cause |
|--------|---------|-------|
| `400 BAD_REQUEST` | Search query must be at least 2 characters | Query too short |
| `400 BAD_REQUEST` | Invalid type. Must be: SHOP, PRODUCT, or PURCHASE_GROUP | Invalid type parameter |
| `429 TOO_MANY_REQUESTS` | Rate limit exceeded | Too many requests |

---

## Frontend Usage Examples

### JavaScript/TypeScript

```javascript
// Global search
const searchAll = async (query, page = 1, size = 20) => {
  const response = await fetch(
    `/api/v1/e-commerce/search?query=${encodeURIComponent(query)}&page=${page}&size=${size}`
  );
  return response.json();
};

// Search with type filter
const searchByType = async (query, type, page = 1) => {
  const response = await fetch(
    `/api/v1/e-commerce/search?query=${encodeURIComponent(query)}&type=${type}&page=${page}`
  );
  return response.json();
};

// Search shops only
const searchShops = async (query) => {
  const response = await fetch(
    `/api/v1/e-commerce/search/shops?query=${encodeURIComponent(query)}`
  );
  return response.json();
};

// Search products only
const searchProducts = async (query) => {
  const response = await fetch(
    `/api/v1/e-commerce/search/products?query=${encodeURIComponent(query)}`
  );
  return response.json();
};

// Search groups by name or code
const searchGroups = async (query) => {
  const response = await fetch(
    `/api/v1/e-commerce/search/groups?query=${encodeURIComponent(query)}`
  );
  return response.json();
};
```

### Rendering Results

```javascript
const renderResults = (results) => {
  results.content.forEach(item => {
    switch (item.type) {
      case 'SHOP':
        renderShopCard(item);
        break;
      case 'PRODUCT':
        renderProductCard(item);
        break;
      case 'PURCHASE_GROUP':
        renderGroupCard(item);
        break;
    }
  });
  
  // Show counts
  console.log(`Found: ${results.shopsCount} shops, ${results.productsCount} products, ${results.purchaseGroupsCount} groups`);
};
```
## 5. Get Product Details by ID

**Purpose**: Retrieve detailed product information by product ID for public viewing

**Endpoint**: <span style="background-color: #61affe; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">GET</span> `{base_url}/api/v1/e-commerce/search/id/{productId}`

**Access Level**: 🌐 Public (No Authentication Required)

**Path Parameters**:
| Parameter | Type | Required | Description | Validation |
|-----------|------|----------|-------------|------------|
| productId | UUID | Yes | Unique product identifier | Valid UUID format |

**Request Example**:
```bash
GET /api/v1/e-commerce/search/id/550e8400-e29b-41d4-a716-446655440000
```

**Success Response JSON Sample**:
```json
{
  "success": true,
  "httpStatus": "OK",
  "message": "Product retrieved successfully",
  "action_time": "2025-12-30T10:30:45",
  "data": {
    "productId": "550e8400-e29b-41d4-a716-446655440000",
    "productName": "iPhone 15 Pro Max",
    "productSlug": "iphone-15-pro-max",
    "productDescription": "The latest iPhone with advanced features, A17 Pro chip, and titanium design.",
    "shortDescription": "Latest iPhone with A17 Pro chip",
    "productImages": [
      "https://storage.example.com/products/iphone15-1.jpg",
      "https://storage.example.com/products/iphone15-2.jpg",
      "https://storage.example.com/products/iphone15-3.jpg"
    ],
    "price": 2500000.00,
    "comparePrice": 2800000.00,
    "discountPercentage": 10.71,
    "isOnSale": true,
    "stockQuantity": 25,
    "lowStockThreshold": 5,
    "isInStock": true,
    "isLowStock": false,
    "trackInventory": true,
    "brand": "Apple",
    "sku": "IPHONE15PM-256-BLK",
    "condition": "NEW",
    "status": "ACTIVE",
    "tags": ["smartphone", "apple", "iphone", "5g"],
    "metaTitle": "iPhone 15 Pro Max - Buy Online",
    "metaDescription": "Buy the latest iPhone 15 Pro Max with free shipping",
    "shopId": "660e8400-e29b-41d4-a716-446655440001",
    "shopName": "TechZone TZ",
    "shopSlug": "techzone-tz",
    "categoryId": "770e8400-e29b-41d4-a716-446655440002",
    "categoryName": "Smartphones",
    "isFeatured": true,
    "isDigital": false,
    "requiresShipping": true,
    "createdAt": "2025-12-01T08:00:00",
    "updatedAt": "2025-12-30T10:00:00",
    "specifications": {
      "Display": "6.7-inch Super Retina XDR",
      "Chip": "A17 Pro",
      "Storage": "256GB",
      "Camera": "48MP Main + 12MP Ultra Wide + 12MP Telephoto",
      "Battery": "4422 mAh",
      "5G": "Yes"
    },
    "hasSpecifications": true,
    "specificationCount": 6,
    "colors": [
      {
        "name": "Natural Titanium",
        "hex": "#9A9A98",
        "images": ["https://storage.example.com/products/iphone15-titanium.jpg"],
        "priceAdjustment": 0.00,
        "finalPrice": 2500000.00,
        "hasExtraFee": false,
        "extraFeeReason": null
      },
      {
        "name": "Blue Titanium",
        "hex": "#394C5F",
        "images": ["https://storage.example.com/products/iphone15-blue.jpg"],
        "priceAdjustment": 50000.00,
        "finalPrice": 2550000.00,
        "hasExtraFee": true,
        "extraFeeReason": "Limited edition color"
      }
    ],
    "hasMultipleColors": true,
    "colorCount": 2,
    "priceRange": {
      "minPrice": 2500000.00,
      "maxPrice": 2550000.00,
      "priceStartsFrom": 2500000.00,
      "hasPriceVariations": true
    },
    "orderingLimits": {
      "minOrderQuantity": 1,
      "maxOrderQuantity": 5,
      "canOrderQuantity": 5,
      "maxAllowedQuantity": 5,
      "hasOrderingLimits": true
    },
    "groupBuying": {
      "isEnabled": true,
      "maxGroupSize": 5,
      "groupPrice": 2200000.00,
      "groupDiscount": 300000.00,
      "groupDiscountPercentage": 12.00,
      "timeLimitHours": 48,
      "canJoinGroup": true
    },
    "installmentOptions": {
      "isEnabled": true,
      "isAvailable": true,
      "downPaymentRequired": true,
      "minDownPaymentPercentage": 20.00,
      "plans": [
        {
          "planId": "3-months",
          "duration": 3,
          "interval": "MONTHLY",
          "interestRate": 0.00,
          "description": "3 months interest-free",
          "calculations": {
            "downPayment": 500000.00,
            "remainingAmount": 2000000.00,
            "totalInterest": 0.00,
            "paymentAmount": 666667.00,
            "totalAmount": 2500000.00
          },
          "paymentSchedule": [
            {
              "paymentNumber": 1,
              "amount": 666667.00,
              "dueDate": "2026-01-30T10:30:45",
              "description": "Payment 1 of 3"
            },
            {
              "paymentNumber": 2,
              "amount": 666667.00,
              "dueDate": "2026-02-28T10:30:45",
              "description": "Payment 2 of 3"
            },
            {
              "paymentNumber": 3,
              "amount": 666666.00,
              "dueDate": "2026-03-30T10:30:45",
              "description": "Payment 3 of 3"
            }
          ],
          "isPopular": true
        },
        {
          "planId": "6-months",
          "duration": 6,
          "interval": "MONTHLY",
          "interestRate": 5.00,
          "description": "6 months with 5% interest",
          "calculations": {
            "downPayment": 500000.00,
            "remainingAmount": 2000000.00,
            "totalInterest": 100000.00,
            "paymentAmount": 350000.00,
            "totalAmount": 2600000.00
          },
          "isPopular": false
        }
      ],
      "eligibilityStatus": "ELIGIBLE",
      "creditCheckRequired": false
    },
    "purchaseOptions": {
      "canBuyNow": true,
      "canJoinGroup": true,
      "canPayInstallment": true,
      "recommendedOption": "GROUP_BUYING",
      "bestDeal": {
        "option": "GROUP_BUYING",
        "savings": 300000.00,
        "finalPrice": 2200000.00
      }
    }
  }
}
```

**Response Fields**:

### Basic Information
| Field | Type | Description |
|-------|------|-------------|
| productId | UUID | Unique product identifier |
| productName | string | Product name |
| productSlug | string | URL-friendly product identifier |
| productDescription | string | Full product description |
| shortDescription | string | Short product summary |
| productImages | array | List of product image URLs |

### Pricing Information
| Field | Type | Description |
|-------|------|-------------|
| price | decimal | Current selling price |
| comparePrice | decimal | Original/compare price |
| discountPercentage | decimal | Discount percentage |
| isOnSale | boolean | Whether product is on sale |

### Inventory Information
| Field | Type | Description |
|-------|------|-------------|
| stockQuantity | int | Available stock |
| lowStockThreshold | int | Low stock alert threshold |
| isInStock | boolean | Whether product is in stock |
| isLowStock | boolean | Whether stock is low |
| trackInventory | boolean | Whether inventory is tracked |

### Product Details
| Field | Type | Description |
|-------|------|-------------|
| brand | string | Product brand |
| sku | string | Stock keeping unit |
| condition | enum | NEW, USED, REFURBISHED |
| status | enum | ACTIVE, INACTIVE, DRAFT |

### Shop & Category
| Field | Type | Description |
|-------|------|-------------|
| shopId | UUID | Shop identifier |
| shopName | string | Shop name |
| shopSlug | string | Shop URL slug |
| categoryId | UUID | Category identifier |
| categoryName | string | Category name |

### Specifications
| Field | Type | Description |
|-------|------|-------------|
| specifications | object | Key-value pairs of product specs |
| hasSpecifications | boolean | Whether product has specs |
| specificationCount | int | Number of specifications |

### Colors
| Field | Type | Description |
|-------|------|-------------|
| colors | array | Available color options |
| colors[].name | string | Color name |
| colors[].hex | string | Hex color code |
| colors[].images | array | Color-specific images |
| colors[].priceAdjustment | decimal | Price adjustment for color |
| colors[].finalPrice | decimal | Final price with adjustment |
| colors[].hasExtraFee | boolean | Whether color has extra fee |
| hasMultipleColors | boolean | Whether multiple colors exist |
| colorCount | int | Number of color options |

### Price Range
| Field | Type | Description |
|-------|------|-------------|
| priceRange.minPrice | decimal | Minimum price across variants |
| priceRange.maxPrice | decimal | Maximum price across variants |
| priceRange.priceStartsFrom | decimal | Starting price |
| priceRange.hasPriceVariations | boolean | Whether prices vary |

### Ordering Limits
| Field | Type | Description |
|-------|------|-------------|
| orderingLimits.minOrderQuantity | int | Minimum order quantity |
| orderingLimits.maxOrderQuantity | int | Maximum order quantity |
| orderingLimits.canOrderQuantity | int | Quantity user can order |
| orderingLimits.hasOrderingLimits | boolean | Whether limits apply |

### Group Buying
| Field | Type | Description |
|-------|------|-------------|
| groupBuying.isEnabled | boolean | Whether group buying is enabled |
| groupBuying.maxGroupSize | int | Maximum group participants |
| groupBuying.groupPrice | decimal | Group purchase price |
| groupBuying.groupDiscount | decimal | Savings amount |
| groupBuying.groupDiscountPercentage | decimal | Savings percentage |
| groupBuying.timeLimitHours | int | Hours to fill group |
| groupBuying.canJoinGroup | boolean | Whether user can join |

### Installment Options
| Field | Type | Description |
|-------|------|-------------|
| installmentOptions.isEnabled | boolean | Whether installments enabled |
| installmentOptions.isAvailable | boolean | Whether available for product |
| installmentOptions.downPaymentRequired | boolean | Whether down payment needed |
| installmentOptions.minDownPaymentPercentage | decimal | Minimum down payment % |
| installmentOptions.plans | array | Available payment plans |
| installmentOptions.eligibilityStatus | string | User eligibility status |

### Purchase Options Summary
| Field | Type | Description |
|-------|------|-------------|
| purchaseOptions.canBuyNow | boolean | Can purchase immediately |
| purchaseOptions.canJoinGroup | boolean | Can join group purchase |
| purchaseOptions.canPayInstallment | boolean | Can use installments |
| purchaseOptions.recommendedOption | string | Best option for user |
| purchaseOptions.bestDeal.option | string | Best deal type |
| purchaseOptions.bestDeal.savings | decimal | Amount saved |
| purchaseOptions.bestDeal.finalPrice | decimal | Final price with deal |

**Error Response JSON Sample**:
```json
{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Product not found",
  "action_time": "2025-12-30T10:30:45",
  "data": null
}
```

**Standard Error Types**:
| Status | Message | Cause |
|--------|---------|-------|
| `404 NOT_FOUND` | Product not found | Invalid product ID |
| `400 BAD_REQUEST` | Invalid product ID format | Malformed UUID |

---

## Endpoints Summary (Updated)

| # | Method | Endpoint | Purpose |
|---|--------|----------|---------|
| 1 | GET | `/api/v1/e-commerce/search` | Search all types |
| 2 | GET | `/api/v1/e-commerce/search/shops` | Search shops only |
| 3 | GET | `/api/v1/e-commerce/search/products` | Search products only |
| 4 | GET | `/api/v1/e-commerce/search/groups` | Search purchase groups only |
| 5 | GET | `/api/v1/e-commerce/search/id/{productId}` | Get product details by ID |

---

## Frontend Usage Example

```javascript
// Get full product details after search result click
const getProductDetails = async (productId) => {
  const response = await fetch(
    `/api/v1/e-commerce/search/id/${productId}`
  );
  return response.json();
};

// Usage
const handleSearchResultClick = async (item) => {
  if (item.type === 'PRODUCT') {
    const productDetails = await getProductDetails(item.id);
    showProductModal(productDetails.data);
  }
};
```