# Off-Plan Listing Page API - Complete Documentation

## Overview

The Off-Plan Listing Page API provides a complete, unified endpoint that returns all necessary data for building a property listing page with filters, search results, pagination, and CMS-managed sections.

**Status:** ✅ Ready for Implementation  
**Last Updated:** 2026-08-13  
**API Version:** v1

---

## Endpoints

### 1. Main Listing Endpoint (Recommended)
```
GET /api/v1/off-plan/projects
```

**Returns:** Complete listing page with filters, properties, pagination, explore by city, and FAQ sections

**Query Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `page` | int | 1 | Page number for pagination |
| `per_page` | int | 15 | Items per page (max: 100) |
| `sort` | string | name_asc | Sort option (see sort options below) |
| `project_name` | string | - | Filter by project name (partial match) |
| `developer_id` | int | - | Filter by developer ID |
| `completion_year` | string | - | Filter by completion year (e.g., "2025") |
| `state_id` | string | - | Filter by emirate (Dubai, Abu Dhabi, etc.) |
| `min_price` | numeric | - | Minimum price filter |
| `max_price` | numeric | - | Maximum price filter |

**Sort Options:**
```
name_asc → "Newest First" (default)
name_desc → "Name (Z-A)"
price_asc → "Price: Low to High"
price_desc → "Price: High to Low"
completion_asc → "Completion (Earliest)"
completion_desc → "Completion (Latest)"
```

### 2. Filter Options Endpoint
```
GET /api/v1/off-plan/projects/filters
```

**Returns:** Available filter options (developers, years, states, price range, sort options)

### 3. Single Project Details
```
GET /api/v1/off-plan/projects/{projectId}
```

**Returns:** Detailed project information including apartments, facilities, coordinates, etc.

---

## Complete Response Structure

### Main Listing Endpoint Response

```json
{
  "data": {
    "listing_header": {
      "title": "Dubai off-plan projects – buy off-plan property in Dubai",
      "results_text": "Showing 1 - 16 of 1,444 properties"
    },
    
    "filters": {
      "location_placeholder": "Location",
      "property_type": {
        "label": "Property Type",
        "options": ["Apartment", "Villa", "Townhouse", "Penthouse"]
      },
      "bedrooms": {
        "label": "Bedrooms",
        "options": ["Studio", "1", "2", "3", "4", "5+"]
      },
      "price_range": {
        "label": "Price Range",
        "min": 500000,
        "max": 10000000
      },
      "more_filters": {
        "label": "More Filters",
        "options": {
          "amenities": ["Pool", "Gym", "Parking", "Security", "Garden", "Balcony"],
          "area": ["Studio", "1BR", "2BR", "3BR", "4BR+"],
          "developer": [
            { "id": 1, "name": "EMAAR" },
            { "id": 2, "name": "Damac" }
          ],
          "completion_year": [
            { "value": "2025", "label": "2025" },
            { "value": "2026", "label": "2026" }
          ]
        }
      },
      "currency": {
        "default": "AED",
        "options": ["AED", "GBP", "USD"]
      },
      "sort_by": {
        "default": "name_asc",
        "options": [
          { "value": "name_asc", "label": "Newest First" },
          { "value": "name_desc", "label": "Name (Z-A)" },
          { "value": "price_asc", "label": "Price: Low to High" },
          { "value": "price_desc", "label": "Price: High to Low" },
          { "value": "completion_asc", "label": "Completion (Earliest)" },
          { "value": "completion_desc", "label": "Completion (Latest)" }
        ]
      }
    },
    
    "properties": {
      "total": 1444,
      "per_page": 16,
      "current_page": 1,
      "total_pages": 99,
      "data": [
        {
          "id": "JW001",
          "ref_no": "REF123456",
          "name": "JW Marriott Marqui Building",
          "location": "Downtown Dubai, Dubai",
          "developer": {
            "id": 1,
            "name": "EMAAR",
            "slug": "emaar",
            "logo": "https://example.com/emaar-logo.png"
          },
          "bedrooms": {
            "label": "1,2,3 BR Apartments",
            "types": ["1", "2", "3"]
          },
          "price": {
            "starting_from": 850000,
            "formatted": "AED 0.8M",
            "currency": "AED"
          },
          "completion": {
            "date": "Q4 2026",
            "year": "2026"
          },
          "image": "https://images.unsplash.com/photo-1512917774080-9991f1c4c750?auto=format&fit=crop&w=1200&q=80",
          "images": ["url1", "url2", "url3"],
          "state_id": "DXB",
          "state_name": "Dubai",
          "city": "Dubai",
          "community": "Downtown Dubai",
          "community_id": "DT001",
          "sub_community": "",
          "category": "Apartment",
          "status": "Off-Plan",
          "agent": {
            "name": "John Doe",
            "phone": "+971501234567"
          }
        }
        // ... more properties
      ]
    },
    
    "pagination": {
      "current_page": 1,
      "per_page": 16,
      "total": 1444,
      "last_page": 99,
      "total_unfiltered": 1444
    },
    
    "explore_by_city": {
      "title": "Explore properties for sale by city",
      "columns": [
        {
          "links": [
            { "label": "Property for sale in Dubai", "url": "/properties/dubai" },
            { "label": "Property for sale in Abu Dhabi", "url": "/properties/abu-dhabi" }
          ]
        },
        {
          "links": [
            { "label": "Property for sale in Sharjah", "url": "/properties/sharjah" },
            { "label": "Property for sale in Ajman", "url": "/properties/ajman" }
          ]
        },
        {
          "links": [
            { "label": "Property for sale in Ras Al Khaimah", "url": "/properties/rak" },
            { "label": "Property for sale in Umm Al Quwain", "url": "/properties/uaq" }
          ]
        },
        {
          "links": [
            { "label": "Property for sale in Fujairah", "url": "/properties/fujairah" },
            { "label": "Property for sale in Al Ain", "url": "/properties/al-ain" }
          ]
        }
      ],
      "recommended_searches": {
        "title": "Recommended searches",
        "links": [
          { "label": "2BR Apartments in Dubai", "url": "/properties?bedrooms=2" },
          { "label": "Villas in Dubai Marina", "url": "/properties?community=dubai-marina" }
        ]
      },
      "other_property_types": {
        "title": "Other property types",
        "links": [
          { "label": "Townhouses for sale in Dubai", "url": "/properties?type=townhouse" },
          { "label": "Penthouses for sale in Dubai", "url": "/properties?type=penthouse" }
        ]
      },
      "useful_links": {
        "title": "Useful links",
        "links": [
          { "label": "How to buy property in UAE", "url": "/guides/buying-property" },
          { "label": "Mortgage calculators", "url": "/tools/mortgage-calculator" }
        ]
      }
    },
    
    "faq": {
      "title": "Frequently Asked Questions about Buying a Property in Dubai and the UAE",
      "subtitle": "Everything you need to know about mortgage services.",
      "items": [
        {
          "question": "Can foreigners buy property in the UAE?",
          "answer": "Yes, foreigners can buy property in UAE freehold zones, owning outright in areas like Dubai Marina or Yas Island. Leasehold options (50–99 years) apply outside these zones. No UAE visa is required, though investments over AED 750,000 may grant residency."
        },
        {
          "question": "Can you own 100% of the property in the UAE?",
          "answer": ""
        },
        {
          "question": "What is the best way to buy property in the UAE?",
          "answer": ""
        },
        {
          "question": "Can I get UAE residency by buying a property?",
          "answer": ""
        },
        {
          "question": "Is it a good idea to buy property in the UAE?",
          "answer": ""
        },
        {
          "question": "Tortor nisl pellentesque sit quis orci dolor?",
          "answer": ""
        },
        {
          "question": "Vestibulum mauris mauris elementum proin amet auctor ipsum nibh sollicitudin?",
          "answer": ""
        }
      ]
    },
    
    "applied_filters": {
      "state_id": "DXB",
      "min_price": 500000
    },
    
    "counts_by_state": [
      {
        "state_id": "DXB",
        "state_name": "Dubai",
        "count": 1200
      },
      {
        "state_id": "AUH",
        "state_name": "Abu Dhabi",
        "count": 244
      }
    ],
    
    "sort": "name_asc"
  },
  "success": true,
  "message": "Off-plan projects retrieved successfully"
}
```

---

## Filter Options Response

### GET /api/v1/off-plan/projects/filters

```json
{
  "data": {
    "developers": [
      {
        "id": 1,
        "name": "EMAAR",
        "slug": "emaar",
        "logo": "https://example.com/emaar-logo.png"
      },
      {
        "id": 2,
        "name": "Damac",
        "slug": "damac",
        "logo": "https://example.com/damac-logo.png"
      }
    ],
    "completion_years": [
      { "value": "2025", "label": "2025" },
      { "value": "2026", "label": "2026" },
      { "value": "2027", "label": "2027" }
    ],
    "states": [
      { "id": "DXB", "name": "Dubai" },
      { "id": "AUH", "name": "Abu Dhabi" },
      { "id": "SHJ", "name": "Sharjah" }
    ],
    "price_range": {
      "min": 500000,
      "max": 10000000
    },
    "counts_by_state": [
      { "state_id": "DXB", "state_name": "Dubai", "count": 1200 },
      { "state_id": "AUH", "state_name": "Abu Dhabi", "count": 244 }
    ],
    "total_projects": 1444,
    "sort_options": [
      { "value": "name_asc", "label": "Newest First" },
      { "value": "name_desc", "label": "Name (Z-A)" },
      { "value": "price_asc", "label": "Price: Low to High" },
      { "value": "price_desc", "label": "Price: High to Low" },
      { "value": "completion_asc", "label": "Completion (Earliest)" },
      { "value": "completion_desc", "label": "Completion (Latest)" }
    ]
  },
  "success": true
}
```

---

## Testing URLs

### Example Requests

**1. Basic Listing (First Page)**
```
GET http://127.0.0.1:8000/api/v1/off-plan/projects
```

**2. With Pagination**
```
GET http://127.0.0.1:8000/api/v1/off-plan/projects?page=2&per_page=20
```

**3. Sorted by Price**
```
GET http://127.0.0.1:8000/api/v1/off-plan/projects?sort=price_asc
```

**4. Filtered by State and Price Range**
```
GET http://127.0.0.1:8000/api/v1/off-plan/projects?state_id=DXB&min_price=1000000&max_price=5000000
```

**5. Filter by Developer**
```
GET http://127.0.0.1:8000/api/v1/off-plan/projects?developer_id=1
```

**6. Filter by Completion Year**
```
GET http://127.0.0.1:8000/api/v1/off-plan/projects?completion_year=2026
```

**7. Get Available Filters**
```
GET http://127.0.0.1:8000/api/v1/off-plan/projects/filters
```

**8. Get Single Project Details**
```
GET http://127.0.0.1:8000/api/v1/off-plan/projects/JW001
```

### Using cURL
```bash
# Get first page
curl -X GET "http://127.0.0.1:8000/api/v1/off-plan/projects" \
  -H "Accept: application/json"

# Get with filters
curl -X GET "http://127.0.0.1:8000/api/v1/off-plan/projects?state_id=DXB&sort=price_asc" \
  -H "Accept: application/json"

# Get filter options
curl -X GET "http://127.0.0.1:8000/api/v1/off-plan/projects/filters" \
  -H "Accept: application/json"
```

### Using Postman
1. Import the provided Postman collection
2. Set `base_url` = `http://127.0.0.1:8000/api/v1`
3. Use the pre-configured requests

---

## Managing Content in Filament Admin

### URL
```
http://127.0.0.1:8000/admin/off-plan
```

### Editable Sections

#### 1. Listing Header
- **listing_page_title**: Main page title (e.g., "Dubai off-plan projects – buy off-plan property in Dubai")

#### 2. Explore by City Section
- **explore_by_city_title**: Section title
- **explore_by_city_data**: JSON structure containing:
  - `columns`: Array of 4 columns, each with `links` array [{label, url}]
  - `recommended_searches`: Links array
  - `other_property_types`: Links array
  - `useful_links`: Links array

#### 3. FAQ Section
- **faq_title**: Section title
- **faq_subtitle**: Section subtitle
- **faq_items**: Repeating items with {question, answer}

All sections have default values that are used if not populated in the admin panel.

---

## Frontend Implementation Notes

### Property Card Display
Each property in the `properties.data` array includes:
- `badge`: Label (e.g., "Exclusive")
- `price.formatted`: Display price (e.g., "AED 0.8M")
- `developer.name`: Developer name
- `developer.logo`: Developer logo URL
- `name`: Project name
- `location`: Full location string
- `bedrooms.label`: Bedroom info
- `image`: Featured image URL

### Pagination
The response includes both old and new pagination formats:
- **Legacy**: `pagination` object (for backward compatibility)
- **New**: `properties.total_pages`, `properties.current_page`, etc.

### Dynamic Results Text
Replace `{from}`, `{to}`, and `{total}` in `listing_header.results_text` with actual values:
```javascript
const resultsText = `Showing ${from} - ${to} of ${total} properties`;
```

### Filter Building
Use `filters` object to build filter UI:
- Generate dropdowns from options arrays
- Use `price_range.min/max` for range slider
- Map `more_filters.options` to expandable section

### FAQ Accordion
Use `faq.items` array with question/answer pairs:
- First item shows expanded by default (if it has an answer)
- Others collapsed by default
- Toggle on click

---

## Caching Strategy

- **Project Cache**: 1 hour (Goyzer data)
- **Developer Cache**: 1 hour
- **States Cache**: Forever (rarely changes)
- **Listing Page Cache**: Forever (clears on save in Filament admin)

Clear caches manually:
```bash
php artisan cache:clear
php artisan route:clear
php artisan config:clear
```

---

## Architecture Summary

| Component | File | Purpose |
|-----------|------|---------|
| Controller | `app/Http/Controllers/Api/OffPlanProjectsController.php` | Main endpoint handler |
| Model | `app/Models/OffPlanPage.php` | Database model for CMS content |
| Resource | `app/Http/Resources/OffPlanResource.php` | Legacy endpoint (GET /api/v1/off-plan) |
| Filament Admin | `app/Filament/Resources/OffPlan/` | CMS interface for content management |
| Migration | `database/migrations/2026_08_13_133000_*.php` | Database schema |

---

## Files Modified

- ✅ `database/migrations/2026_08_13_133000_add_listing_page_fields_to_off_plan_pages.php` (Created)
- ✅ `app/Models/OffPlanPage.php` (Updated)
- ✅ `app/Http/Resources/OffPlanResource.php` (Updated)
- ✅ `app/Filament/Resources/OffPlan/Schemas/OffPlanForm.php` (Updated)
- ✅ `app/Http/Controllers/Api/OffPlanProjectsController.php` (Updated)
- ✅ Database migration executed (129.89ms)
- ✅ Caches cleared

---

## Next Steps

1. **Test the API** - Call endpoints and verify response structure
2. **Populate Content** - Use Filament admin to add listing page data
3. **Frontend Integration** - Implement UI using the response structure
4. **Form Submission** - For form fields, connect to respective APIs
5. **Add is_favorited** - (Future) Implement wishlist tracking for authenticated users

---

## Status Summary

- ✅ Database migration complete
- ✅ Model updated with new fields
- ✅ Filament admin forms configured
- ✅ Complete response structure implemented
- ✅ Filter options endpoint ready
- ✅ Single project details endpoint ready
- ✅ Caches cleared and ready for testing

**Ready for Frontend Testing: YES ✅**

