Skip to Content
API v2ModulesProperties Module

Properties Module

Overview

The Properties module powers the house search, map, likes, enquiries, and city features for both the mobile app and web app. It is the largest module by code surface and makes extensive use of Spatie Query Builder for filterable, sortable, paginated endpoints.

Routes

Routes are prefixed with /properties (configured in RouteServiceProvider).

# Legacy routes (web app / search) GET /properties/ List properties (legacy, uses PropertyService) GET /properties/cities List cities GET /properties/{id} Show property GET /properties/agent-bookable/{house} Check if agent has bookable viewings GET /properties/bills-price Get bills price for bedrooms/city POST /properties/enquiry Submit property enquiry GET /properties/similar/{house} Get similar properties GET /properties/map-highlights/{house} Get nearby map highlights # Authenticated legacy GET /properties/cities/demo Demo cities (requires JWT) # v1 Explore routes (mobile app, uses Spatie Query Builder) GET /properties/v1/houses/search Search terms/autocomplete GET /properties/v1/houses List houses (filterable, sortable, paginated) GET /properties/v1/houses/{house} Show house detail GET /properties/v1/map-markers Map marker data # Authenticated v1 routes PATCH /properties/v1/user/city Update user's city POST /properties/v1/houses/{house}/like Toggle house like

The /properties/v1/ routes use the OptionalJWTAuth middleware, which resolves the user if a token is present but allows anonymous access. Authenticated users get extra data (likes, viewing requests, group likes).

Controllers

HouseController (Spatie Query Builder)

The primary search controller for the mobile app explore screen.

index(Request) — Returns paginated, filtered, sorted houses:

Allowed Filters:

FilterTypeDescription
cityExactFilter by city name
boundaryCustom (BoundaryFilter)Geographic boundary (bounding box or radius)
is_likedCustomOnly liked houses (requires auth)
is_group_likedCustomOnly group-liked houses (requires auth)
price_minCustomMinimum total price (rent + bills)
price_maxCustomMaximum total price (rent + bills)
bedroomsExactNumber of bedrooms
bathroomsExactNumber of bathrooms
crm_block_idCustomCRM block ID (US only)
property_operatorExactProperty operator ID
agent_idExactAgent ID
uob_approvedCustomUniversity-approved agents only
academic_yearCustomAcademic year (US lease terms)

Allowed Sorts:

SortClassDescription
popularPopularitySortBy tap count
recommendedRecommendedSortBy tier, priority, random (default)
newestNewestSortBy creation date
highest_priceHighestPriceSortTotal price descending
lowest_priceLowestPriceSortTotal price ascending
most_likedMostLikedSortBy like count

Allowed Includes:

  • viewingRequest — User’s viewing request for each house
  • videoTour — Video tour link

Example request:

GET /properties/v1/houses?filter[city]=London&filter[bedrooms]=3&filter[price_min]=100&filter[boundary]=51.52,51.50,-0.15,-0.10&sort=lowest_price&page=2

show(House) — Returns a single house with all relations loaded.

PropertiesController (Legacy)

Serves the web app search. Uses PropertyService directly (not Spatie Query Builder).

  • index(PropertyRequest) — Legacy search with query params for city, price range, bedrooms, bathrooms, coordinates, sort, pagination
  • show(int $id) — Legacy single property view
  • similar(House) — Similar properties by price range and bedrooms
  • nearbyHighlights(NearbyHighlightRequest) — Map highlights near a property
  • getBillsPrice(BillsPriceRequest) — Bills price calculation
  • getAgentBookable(House) — Check if agent supports online booking

MapMarkerController

  • index() — Returns lightweight map marker data for all visible houses

HouseLikeController

  • store(House) — Toggle like/unlike for authenticated user

CitiesController

  • index() — List all active cities
  • demoCities() — Demo cities (authenticated)
  • update() — Update user’s selected city

HouseSearchTermsController

  • __invoke() — Returns search terms/autocomplete data

EnquiryController

  • enquiry(EnquiryRequest) — Submit a property enquiry. Creates WebsiteEnquiry record, sends confirmation email to user, notification email to landlord.

Models

House

The core model. Lives in the main database (houses table), shared with v1.

Key features:

  • scopeWithBillsPrice() — Cross-database join to calculate bills_price and total_price from the bills database pricing tables
  • scopeWithinCoordinates() — Spatial query using mapped_houses table (UK only, MySQL 8)
  • scopeWithinLatLngRadius() — Radius-based spatial query (UK only)
  • Soft deletes enabled
  • Uses HousePolicy for authorisation
  • Relations: agent, likedHouses, viewingRequest, videoTour, buildingDetail (US), leaseTerms (US), propertyOperator, billsIncludedAgent

MappedHouse

Spatial data for houses. Contains a POINT geometry column for efficient spatial queries. Populated via database triggers when houses are created/updated. UK only (MySQL 8 spatial features).

LikedHouse

User house likes. Fields: house_id, tenant_id, status, match_preference.

HouseLeaseTerm

US-only. Lease terms per academic year with rent, deposit, start/end dates, and apply now links.

City

City data with coordinates.

SearchArea

Search area boundaries for city-based filtering.

WebsiteEnquiry

Property enquiry records.

BookableViewing

Agent bookable viewing slot data.

BillsPrice / BillsPricesSelectable / BillsIncludedAgent

Bills pricing configuration. These models bridge the main DB and bills DB for the withBillsPrice scope.

BuildingDetail

US-only. Building-level details (title, logo, cover image) linked via crm_block_id.

VideoTour

Video tour links for houses.

HousemateGroup

Housemate groups for group likes and group enquiry features.

ViewingRequest

Viewing/enquiry requests from the Rental module (cross-module relation).

Services

PropertyService

Legacy search service with manual query building. Supports filtering by city, price range, bedrooms, bathrooms, coordinates, and sorting. Also handles CRUD operations for properties (used by external API clients).

BillsPriceService

Calculates bills price for a given bedrooms/city/agent combination. Accounts for bills-included agents.

MapService

Handles map highlight data (nearby points of interest).

EnquiryService

Processes property enquiries, sends emails.

Custom Filters (Spatie)

FilterDescription
BoundaryFilterGeographic filtering. Accepts bounding box (4 values: N,S,W,E) or radius (3 values: lat,lng,km)
IsLikedFilterFilter to user’s liked houses
IsGroupLikedFilterFilter to houses liked by group members
PriceMinFilterMinimum total price
PriceMaxFilterMaximum total price
CrmBlockIdFilterCRM block ID filter (US)
UobApprovedFilterUniversity-approved agents
AcademicYearFilterAcademic year for lease terms (US)

Custom Sorts (Spatie)

SortLogic
RecommendedSorttier ASC, house_priority DESC, RAND()
PopularitySortBy tap count
NewestSortBy created_at
HighestPriceSortBy total_price DESC
LowestPriceSortBy total_price ASC
MostLikedSortBy like count

Queries

HouseAvailabilityScopes

Applies global availability constraints to house queries (status filtering, CRM group deduplication).

MapMarkersQuery

Optimised query for map marker data (lightweight projection of house locations).

Actions

FormatHouseAddressAction

Static action that formats a house address for display. Has a dedicated unit test.

Resource

HouseResource

Transforms House model to JSON. Key fields:

  • Price fields: price_pw, price_pm, deposit, bills_price, total_price
  • Location: city, address, lat, lng
  • Media: images (resized via ServerlessImageHandler), first_image, floorplan, video_tour
  • Social: is_liked, liked_at, group_likes, group_enquiries, is_popular
  • US-specific: squareFootage, crm_name, crm_block_id, building_title, building_logo_image
  • Conditional: viewing_request_status, viewing_request_created_at (only when loaded)

Images from the Housr S3 bucket are automatically resized to 800x640 via the Serverless Image Handler (sabatino/serverless-image-handler package).

Traits

  • HasGroupMemberLikes — Adds group member like relations and helpers
  • HasGroupMemberEnquired — Adds group member enquiry relations and helpers

Policies

  • HousePolicy — Authorisation rules for house operations

Tests

  • Modules/Properties/tests/Unit/Actions/FormatHouseAddressActionTest.php — Unit test for address formatting
Last updated on