HomePro Backend API (1.0.0)

Download OpenAPI specification:

HomePro API Support: support@homepro.com License: MIT

HomePro Backend API for managing homes, home items, photos, support requests, and users.

Architecture

  • Scala 3.5.0 backend with Akka HTTP
  • PostgreSQL database with direct SQL queries
  • Firebase Admin SDK for authentication
  • AWS S3 for photo storage with context-based organization
  • HikariCP connection pooling

Authentication

All protected endpoints require Firebase JWT token in Authorization header: Authorization: Bearer <firebase-jwt-token>

S3 Storage Structure

Photos are organized in S3 with context-based paths:

  • Home Item Photos: {home_item_id}/{filename}
  • Home Photos: {home_id}/{filename}
  • User Photos: {user_id}/{filename}

Key Features Implemented

  • ✅ Home creation with one-home restriction per user
  • ✅ Home item creation with type validation
  • ✅ Photo upload with S3 integration and database linking
  • ✅ Context-based S3 organization for efficient access
  • ✅ Firebase authentication and authorization
  • ✅ Comprehensive error handling and logging
  • ✅ Support request management
  • ✅ User and home management with JSONB metadata support
  • ✅ CORS support with origin restrictions for security
  • ✅ Delete operations with cascading deletes and proper authorization
  • ✅ S3 cleanup for deleted photos and comprehensive data removal
  • ✅ Photo primary status management with automatic constraint enforcement
  • ✅ Notes API for observations, todos, and questions on homes and home items

CORS Configuration

All endpoints support CORS (Cross-Origin Resource Sharing) to enable requests from web browsers.

Supported CORS Headers:

  • Access-Control-Allow-Origin: Restricted to http://localhost:3000 and https://home-owners.tech
  • Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS
  • Access-Control-Allow-Headers: Authorization, Content-Type, X-Requested-With
  • Access-Control-Max-Age: 86400 (24 hours preflight cache)
  • Access-Control-Allow-Credentials: true (for authenticated requests)

Preflight Requests:

  • Browser will send OPTIONS request for complex requests
  • Server responds with appropriate CORS headers
  • Actual request follows if preflight succeeds

Authentication

User authentication and session management

User login and profile retrieval

Validates Firebase JWT token and returns user profile with roles. Creates user session and returns user details.

Authorizations:
FirebaseAuth

Responses

Response samples

Content type
application/json
{
  • "id": "550e8400-e29b-41d4-a716-446655440000",
  • "name": "John Doe",
  • "roles": "homeowner, admin"
}

Homes

Home management, statistics, and deletion operations. Includes cascading delete functionality with proper authorization.

Get homes for a user

Retrieves all homes that the authenticated user has access to, along with comprehensive statistics including item counts, photo counts, note counts, and emergency item counts.

Authorizations:
FirebaseAuth
query Parameters
userId
required
string <uuid>
Example: userId=550e8400-e29b-41d4-a716-446655440000

UUID of the user whose homes to retrieve

Responses

Response samples

Content type
application/json
[
  • {
    }
]

CORS preflight for homes endpoint

Handles CORS preflight requests for the homes endpoint. Browsers automatically send this request before actual GET/POST requests.

Authorizations:
FirebaseAuth

Responses

Create a new home

Creates a new home for the authenticated user. Important: Users are currently restricted to owning only ONE home. If a user already has a home, this endpoint will return a 409 Conflict error.

Business Rules:

  • One home per user restriction (will be relaxed in future versions)
  • First home is automatically set as primary (isPrimary: true)
  • Creating user is automatically assigned "owner" role
  • Metadata field supports flexible JSONB data for home attributes

Home Ownership:

  • Creates both home record and home_owners relationship
  • Assigns "owner" role to creating user
  • Enables full access to home management features
Authorizations:
FirebaseAuth
Request Body schema: application/json
required
name
required
string [ 1 .. 255 ] characters

Name/title for the home

address
string or null <= 500 characters

Physical address of the home

object or null

Flexible metadata for home attributes stored as JSONB. Can include any key-value pairs for home characteristics.

Responses

Request samples

Content type
application/json
Example

Minimal home creation with just name

{
  • "name": "My Beautiful Home"
}

Response samples

Content type
application/json
{
  • "id": "550e8400-e29b-41d4-a716-446655440000",
  • "name": "My Beautiful Home",
  • "address": "123 Main Street, Anytown, ST 12345",
  • "isPrimary": true,
  • "createdAt": "2025-08-11T21:30:00",
  • "message": "Home created successfully"
}

Delete a home with cascading deletes

Permanently deletes a home and all associated data including:

  • All photos associated with the home and its items
  • All home items belonging to the home
  • Home ownership records
  • The home itself

Important:

  • This operation is irreversible
  • Only the home owner can delete the home
  • All data will be removed from both database and S3 storage
  • Authorization is strictly enforced

Cascading Delete Order:

  1. Photos (from S3 and database)
  2. Home items
  3. Home ownership records
  4. Home record
Authorizations:
FirebaseAuth
path Parameters
homeId
required
string <uuid>
Example: ace55e40-b56d-43c1-b738-5eee8f1ccdf1

UUID of the home to delete

Responses

Response samples

Content type
application/json
{
  • "error": "Missing or invalid Authorization header",
  • "code": "UNAUTHORIZED"
}

Home Items

Home inventory item management with CORS support and delete operations. All endpoints support cross-origin requests from web browsers. Delete operations include cascading photo deletion.

Get items for a specific home

Retrieves all items within a home with optional filtering by type and emergency status. Includes photo counts, note counts, and pre-signed URLs for primary photos. Supports pagination for large inventories.

Authorizations:
FirebaseAuth
path Parameters
homeId
required
string <uuid>
Example: ace55e40-b56d-43c1-b738-5eee8f1ccdf1

UUID of the home

query Parameters
type
string (HomeItemType)
Enum: "room" "utility_control" "appliance" "structural" "observation" "wiring" "sensor" "other"
Example: type=utility_control

Filter by item type

emergency
boolean
Example: emergency=true

Filter by emergency status

limit
integer [ 1 .. 100 ]
Default: 50
Example: limit=25

Maximum number of items to return

offset
integer >= 0
Default: 0

Number of items to skip (for pagination)

Responses

Response samples

Content type
application/json
[
  • {
    }
]

CORS preflight for home items

Handles CORS preflight requests for the home items endpoint. Browsers automatically send this request before actual POST requests.

Authorizations:
FirebaseAuth
path Parameters
homeId
required
string <uuid>
Example: ace55e40-b56d-43c1-b738-5eee8f1ccdf1

UUID of the home

Responses

Create a new home item

Creates a new item for a specific home. The item will be associated with the home and can store flexible JSONB data for item-specific information.

Supported Item Types:

  • room - Living spaces (bedroom, kitchen, etc.)
  • utility_control - Valves, switches, breakers
  • appliance - Household appliances
  • structural - Structural elements (beams, foundation)
  • observation - Notes and observations
  • wiring - Electrical wiring and components
  • sensor - Smart sensors and monitoring devices
  • other - Uncategorized items
Authorizations:
FirebaseAuth
path Parameters
homeId
required
string <uuid>
Example: ace55e40-b56d-43c1-b738-5eee8f1ccdf1

UUID of the home to add the item to

Request Body schema: application/json
required
name
required
string [ 1 .. 255 ] characters

Name/title of the home item

itemType
required
string (HomeItemType)
Enum: "room" "utility_control" "appliance" "structural" "observation" "wiring" "sensor" "other"

Category of home item:

  • room: Living spaces (bedroom, kitchen, etc.)
  • utility_control: Valves, switches, breakers
  • appliance: Household appliances
  • structural: Structural elements (beams, foundation)
  • observation: Notes and observations
  • wiring: Electrical wiring and components
  • sensor: Smart sensors and monitoring devices
  • other: Uncategorized items
isEmergency
boolean
Default: false

Whether this item requires emergency attention

data
string or null

Additional item data as JSON string (stored as JSONB in database)

Responses

Request samples

Content type
application/json
Example

Example of adding a kitchen refrigerator

{
  • "name": "Kitchen Refrigerator",
  • "itemType": "appliance",
  • "isEmergency": false,
  • "data": "{\"brand\": \"Samsung\", \"model\": \"RF28T5001SG\", \"purchaseDate\": \"2023-01-15\", \"warranty\": \"2 years\"}"
}

Response samples

Content type
application/json
{
  • "id": "d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94",
  • "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
  • "name": "Kitchen Refrigerator",
  • "type": "appliance",
  • "isEmergency": false,
  • "createdAt": "2025-08-11T12:00:00",
  • "message": "Home item created successfully"
}

Delete a home item with associated photos

Permanently deletes a home item and all its associated photos.

Delete Process:

  1. Deletes all photos associated with the home item (from S3 and database)
  2. Deletes the home item record

Authorization:

  • User must own the home that contains this item
  • Item must belong to the specified home
  • Firebase JWT token required

Important:

  • This operation is irreversible
  • All photos associated with this item will be permanently deleted
  • Photos are removed from both database and S3 storage
Authorizations:
FirebaseAuth
path Parameters
homeId
required
string <uuid>
Example: ace55e40-b56d-43c1-b738-5eee8f1ccdf1

UUID of the home containing the item

itemId
required
string <uuid>
Example: d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94

UUID of the home item to delete

Responses

Response samples

Content type
application/json
{
  • "error": "Missing or invalid Authorization header",
  • "code": "UNAUTHORIZED"
}

Photos

Photo management with S3 integration, CORS support, and deletion capabilities. File uploads via multipart/form-data with automatic preflight handling. Delete operations remove photos from both database and S3 storage.

Get photos with metadata and pre-signed URLs

Retrieves photos for a specific home or home item with complete metadata and secure pre-signed S3 URLs for image access (valid for 24 hours by default).

Requirements:

  • Exactly one of homeId or homeItemId must be provided
  • User must have access to the specified home/item
Authorizations:
FirebaseAuth
query Parameters
homeId
string <uuid>
Example: homeId=ace55e40-b56d-43c1-b738-5eee8f1ccdf1

UUID of the home (mutually exclusive with homeItemId)

homeItemId
string <uuid>
Example: homeItemId=d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94

UUID of the home item (mutually exclusive with homeId)

Responses

Response samples

Content type
application/json
[]

CORS preflight for photo operations

Handles CORS preflight requests for photo endpoints. Browsers automatically send this request before actual GET/POST requests.

Authorizations:
FirebaseAuth
query Parameters
homeId
string <uuid>

UUID of the home (for preflight validation)

homeItemId
string <uuid>

UUID of the home item (for preflight validation)

Responses

Upload photo for home or home item

Upload a photo and associate it with either a home or a specific home item.

Upload Flow:

  1. Client uploads photo via multipart/form-data with form field name photo
  2. Photo is uploaded to S3 with context-based path: {homeId}/{filename} or {homeItemId}/{filename}
  3. Photo metadata is stored in database with either homeId or homeItemId association
  4. Returns presigned URL for immediate photo access

Requirements:

  • Exactly one of homeId or homeItemId must be provided (mutually exclusive)
  • User must have access to the specified home/item

File Requirements:

  • Form field name must be: photo
  • Supported formats: JPEG, PNG, GIF, WebP
  • Recommended max file size: 10MB (configurable on server)

S3 Storage:

  • Bucket: homepro-photos (configurable)
  • Home photos path: {homeId}/{original-filename}
  • Home item photos path: {homeItemId}/{original-filename}
  • Database stores only filename (context-based architecture)

Database Constraint:

  • Photos must have exactly ONE of: home_id, home_item_id, or user_id set
  • For home photos, only home_id is set
  • For home item photos, only home_item_id is set

Use Cases:

  • Home Photos: Exterior shots, property photos, general home documentation
  • Home Item Photos: Specific appliances, rooms, utility controls, etc.
Authorizations:
FirebaseAuth
query Parameters
homeItemId
string <uuid>
Example: homeItemId=d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94

UUID of the home item to associate photo with (mutually exclusive with homeId)

homeId
string <uuid>
Example: homeId=ace55e40-b56d-43c1-b738-5eee8f1ccdf1

UUID of the home to associate photo with (mutually exclusive with homeItemId)

Request Body schema: multipart/form-data
required
photo
required
string <binary>

Photo file to upload

Responses

Request samples

Content type
multipart/form-data

Example of uploading a photo file

{
  "photo": "[binary file data - IMG_3372.JPG]"
}

Response samples

Content type
application/json
Example
{}

Delete an individual photo

Permanently deletes a specific photo from both the database and S3 storage.

Authorization Rules:

  • For home item photos: User must own the home containing the item
  • For home photos: User must own the home
  • For user photos: Must be the same user
  • For orphaned photos: Must be the photo creator

Delete Process:

  1. Validates photo exists and user has permission
  2. Deletes photo from S3 storage (using context-based path)
  3. Removes photo record from database
  4. Continues with database deletion even if S3 deletion fails

Context-Based S3 Paths:

  • Home item photos: {home_item_id}/{filename}
  • Home photos: {home_id}/{filename}
  • User photos: {user_id}/{filename}
  • Legacy photos: Direct S3 key path

Important:

  • This operation is irreversible
  • Photo will be removed from both database and S3
  • Authorization is strictly enforced based on photo context
Authorizations:
FirebaseAuth
path Parameters
photoId
required
string <uuid>
Example: photo-uuid-1

UUID of the photo to delete

Responses

Response samples

Content type
application/json
{
  • "error": "Missing or invalid Authorization header",
  • "code": "UNAUTHORIZED"
}

Set photo as primary for its context

Updates a photo's primary status for its associated context (home item, home, or user). Only one photo per context can be marked as primary at any given time.

Business Rules:

  • When setting isPrimary: true, all other photos in the same context are automatically unmarked
  • When setting isPrimary: false, only this photo's primary status is removed
  • Context is determined by photo's association: homeItemId > homeId > userId
  • Authorization follows same rules as photo deletion

Context Types:

  • Home Item Photos: One primary photo per home item (photos with homeItemId)
  • Home Photos: One primary photo per home (photos with homeId but no homeItemId)
  • User Photos: One primary photo per user (photos with userId but no homeId/homeItemId)

Authorization Rules:

  • For home item photos: User must own the home containing the item
  • For home photos: User must own the home
  • For user photos: Must be the same user
  • For orphaned photos: Must be the photo creator

Important:

  • Primary photos are typically displayed first in photo galleries
  • Used to represent home items visually in lists and summaries
  • The "one primary per context" constraint is enforced automatically
Authorizations:
FirebaseAuth
path Parameters
photoId
required
string <uuid>
Example: 550e8400-e29b-41d4-a716-446655440000

UUID of the photo to update

Request Body schema: application/json
required
isPrimary
required
boolean

Set to true to mark this photo as primary (automatically unmarking other photos in same context). Set to false to remove primary status from this photo.

Responses

Request samples

Content type
application/json
Example

Mark this photo as primary (clears other primary photos in same context)

{
  • "isPrimary": true
}

Response samples

Content type
application/json
{
  • "id": "550e8400-e29b-41d4-a716-446655440000",
  • "homeItemId": "d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94",
  • "fileName": "IMG_3372.JPG",
  • "isPrimary": true,
  • "message": "Photo primary status updated successfully"
}

Notes

Note management for homes and home items. Supports observations, todos, questions, and general notes. Features include pinning, soft deletion, and role-based authorization (homeowners and experts). All operations support Firebase authentication and comprehensive audit trails.

Get notes for a home or home item

Retrieves all notes for a specific home or home item.

Requirements:

  • Exactly one of homeId or homeItemId must be provided
  • User must be a homeowner OR have expert role
  • Results ordered by created_at DESC
  • Soft-deleted notes are excluded
Authorizations:
FirebaseAuth
query Parameters
homeId
string <uuid>
Example: homeId=ace55e40-b56d-43c1-b738-5eee8f1ccdf1

UUID of the home (mutually exclusive with homeItemId)

homeItemId
string <uuid>
Example: homeItemId=d26d981c-0c6e-41ae-b9f9-8a9ad6e66c94

UUID of the home item (mutually exclusive with homeId)

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create a new note

Creates a new note for a home or home item.

Authorization:

  • User must be a homeowner of the home OR have expert role

Requirements:

  • Exactly one of homeId or homeItemId must be provided
  • body is required
  • isPinned is always false at creation
  • authorId and createdBy are set to authenticated user

Note Types:

  • general - General notes and comments
  • observation - Observations and findings
  • todo - Action items and tasks
  • question - Questions that need answers
Authorizations:
FirebaseAuth
Request Body schema: application/json
required
homeId
string or null <uuid>

UUID of the home (mutually exclusive with homeItemId)

homeItemId
string or null <uuid>

UUID of the home item (mutually exclusive with homeId)

title
string or null <= 255 characters

Optional title for the note

body
required
string non-empty

Main content of the note (required)

noteType
string
Default: "general"
Enum: "general" "observation" "todo" "question"

Type of note (defaults to 'general' if not provided)

Responses

Request samples

Content type
application/json
Example
{
  • "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
  • "title": "Kitchen Remodel Ideas",
  • "body": "Consider replacing the countertops with quartz. Also check cabinet hinges.",
  • "noteType": "observation"
}

Response samples

Content type
application/json
{
  • "id": "note-uuid-generated",
  • "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
  • "homeItemId": null,
  • "title": "Kitchen Remodel Ideas",
  • "body": "Consider replacing the countertops with quartz",
  • "noteType": "observation",
  • "isPinned": false,
  • "authorId": "user-uuid-1",
  • "createdBy": "user-uuid-1",
  • "createdAt": "2025-08-11T15:30:00",
  • "updatedBy": null,
  • "updatedAt": "2025-08-11T15:30:00"
}

Update a note

Updates an existing note's title, body, and/or noteType.

Authorization:

  • User must be a homeowner of the home OR have expert role

Allowed Updates:

  • title (optional)
  • body (optional)
  • noteType (optional)

Forbidden Updates:

  • Cannot change homeId or homeItemId
  • Cannot change authorId or createdBy
  • Cannot modify isPinned (use pin/unpin endpoints)
Authorizations:
FirebaseAuth
path Parameters
noteId
required
string <uuid>
Example: note-uuid-1

UUID of the note to update

Request Body schema: application/json
required
title
string or null <= 255 characters

Updated title for the note

body
string or null non-empty

Updated content of the note

noteType
string or null
Enum: "general" "observation" "todo" "question"

Updated note type

Responses

Request samples

Content type
application/json
Example
{
  • "body": "Updated note content with more details"
}

Response samples

Content type
application/json
{
  • "id": "note-uuid-1",
  • "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
  • "homeItemId": null,
  • "title": "Updated Title",
  • "body": "Updated body content",
  • "noteType": "todo",
  • "isPinned": false,
  • "authorId": "user-uuid-1",
  • "createdBy": "user-uuid-1",
  • "createdAt": "2025-08-11T10:30:00",
  • "updatedBy": "user-uuid-2",
  • "updatedAt": "2025-08-11T16:45:00"
}

Soft delete a note

Soft deletes a note by setting the deleted_at timestamp.

Authorization:

  • User must be a homeowner of the home OR have expert role

Behavior:

  • Sets deleted_at to current timestamp
  • Deleted notes will not appear in any read APIs
  • Operation is irreversible (no undelete functionality)
Authorizations:
FirebaseAuth
path Parameters
noteId
required
string <uuid>
Example: note-uuid-1

UUID of the note to delete

Responses

Response samples

Content type
application/json
{
  • "error": "Missing or invalid Authorization header",
  • "code": "UNAUTHORIZED"
}

Pin a note

Marks a note as pinned. Multiple notes can be pinned per home/home item.

Authorization:

  • User must be a homeowner of the home OR have expert role

Idempotency:

  • Re-pinning an already pinned note is a no-op
  • Safe to retry
Authorizations:
FirebaseAuth
path Parameters
noteId
required
string <uuid>
Example: note-uuid-1

UUID of the note to pin

Responses

Response samples

Content type
application/json
{
  • "id": "note-uuid-1",
  • "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
  • "homeItemId": null,
  • "title": "Important Note",
  • "body": "This is an important note",
  • "noteType": "general",
  • "isPinned": true,
  • "authorId": "user-uuid-1",
  • "createdBy": "user-uuid-1",
  • "createdAt": "2025-08-11T10:30:00",
  • "updatedBy": "user-uuid-2",
  • "updatedAt": "2025-08-11T17:00:00"
}

Unpin a note

Removes the pinned status from a note.

Authorization:

  • User must be a homeowner of the home OR have expert role

Idempotency:

  • Re-unpinning an already unpinned note is a no-op
  • Safe to retry
Authorizations:
FirebaseAuth
path Parameters
noteId
required
string <uuid>
Example: note-uuid-1

UUID of the note to unpin

Responses

Response samples

Content type
application/json
{
  • "id": "note-uuid-1",
  • "homeId": "ace55e40-b56d-43c1-b738-5eee8f1ccdf1",
  • "homeItemId": null,
  • "title": "Important Note",
  • "body": "This is an important note",
  • "noteType": "general",
  • "isPinned": false,
  • "authorId": "user-uuid-1",
  • "createdBy": "user-uuid-1",
  • "createdAt": "2025-08-11T10:30:00",
  • "updatedBy": "user-uuid-2",
  • "updatedAt": "2025-08-11T17:15:00"
}

Support Requests

Service request lifecycle management

Get support requests

Retrieves support requests based on user permissions and filters. Includes full request lifecycle information and assigned expert details.

Authorizations:
FirebaseAuth
query Parameters
status
string (SupportRequestStatus)
Enum: "open" "in_progress" "resolved" "closed" "cancelled"
Example: status=open

Filter by request status

homeId
string <uuid>

Filter by home ID

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create a new support request

Creates a new support request for home services. Automatically assigns to appropriate experts based on request type and location.

Authorizations:
FirebaseAuth
Request Body schema: application/json
required
homeId
string or null <uuid>

Associated home ID

title
required
string [ 1 .. 200 ] characters

Brief title of the support request

description
required
string [ 1 .. 2000 ] characters

Detailed description of the issue

priority
string (SupportRequestPriority)
Enum: "low" "medium" "high" "urgent"

Priority level of the support request

Responses

Request samples

Content type
application/json
{
  • "homeId": "home-uuid-1",
  • "title": "Kitchen Sink Leak Repair",
  • "description": "Main shutoff valve under kitchen sink is leaking. Need urgent repair.",
  • "priority": "high"
}

Response samples

Content type
application/json
{
  • "id": "support-uuid-1",
  • "title": "Kitchen Sink Leak Repair",
  • "status": "open",
  • "created_at": "2025-08-08T09:00:00"
}