# Places API

Manage buildings, complexes, and property sites. Places are the top-level containers in the property hierarchy — every apartment, office, or commercial unit belongs to a place.

## Quick Example

```bash
curl -X POST https://api.faireplace.com/api/places \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Residence Les Jardins",
    "type_id": "<place_type_uuid>",
    "country_id": "<zone_uuid>",
    "owner_id": "<owner_uuid>",
    "country": "France",
    "street_number": "24",
    "street_name": "rue du Faubourg Saint-Antoine",
    "postal_code": "75012",
    "city": "Paris",
    "place_category": "Collective",
    "legal_regime": "Copropriete"
  }'
```

## Common Workflows

### Set up a new apartment building
1. `POST /api/places` — Create the building
2. `POST /api/places/{id}/estates` — Add each apartment ([Estates API](/properties/estates))
3. `POST /api/places/{id}/estates/{id}/rooms` — Define room layouts ([Rooms API](/properties/rooms))
4. `POST /api/places/{id}/services` — Configure building services

### Add rent control to a property
1. `GET /api/legislative-zones` — Get the country reference ([Rent Regulation & Rent Control API](/compliance/legislative-zones))
2. `POST /api/places` — Create place with `country_id`
3. Rent control rules are automatically applied to leases in this place

---

## Overview

Places represent physical buildings or property complexes and serve as containers for:
- **Estates**: Individual rental units within the place
- **Services**: Building-wide services and amenities
- **Energy Diagnostics**: Building-level energy assessments
- **Ownership**: Current and historical ownership tracking
- **Legal Information**: Legal regime and administrative details
- **Location Data**: Address, coordinates, and access information

## Authentication

All endpoints require authentication with the following permissions:
- **PropertiesRead**: For GET operations
- **PropertiesWrite**: For POST and PUT operations
- **PropertiesDelete**: For DELETE operations

## Base URL

All place endpoints are prefixed with `/api/places`

---

## Core Place Operations

### List Places
**GET** `/api/places`

Retrieve all places for the tenant.

**Response:**
```json
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Résidence Les Jardins",
    "country": "France",
    "street_number": "123",
    "street_name": "Avenue de la République",
    "address_complement": "Bâtiment A",
    "locality": null,
    "postal_code": "75011",
    "city": "Paris",
    "postal_box": null,
    "latitude": 48.8566,
    "longitude": 2.3522,
    "description": "Modern residential complex with garden views",
    "type_id": "550e8400-e29b-41d4-a716-446655440010",
    "country_id": "550e8400-e29b-41d4-a716-446655440020",
    "digicode": "A1234B",
    "number_of_floor": 8,
    "owner_id": "550e8400-e29b-41d4-a716-446655440030",
    "previous_owner_id": null,
    "construction_date": "2010-09-15T00:00:00",
    "renovation_date": "2020-05-20T00:00:00",
    "place_category": "Collective",
    "legal_regime": "Copropriete",
    "created_at": "2024-01-15T10:30:00",
    "updated_at": "2024-01-15T10:30:00"
  }
]
```

### Create Place
**POST** `/api/places`

Create a new place (building or complex).

**Request Body:**
```json
{
  "name": "Villa Moderne",
  "type_id": "550e8400-e29b-41d4-a716-446655440010",
  "country_id": "550e8400-e29b-41d4-a716-446655440020",
  "owner_id": "550e8400-e29b-41d4-a716-446655440030",
  "country": "France",
  "street_number": "456",
  "street_name": "Rue de la Paix",
  "address_complement": "Entrée B",
  "postal_code": "75002",
  "city": "Paris",
  "latitude": 48.8654,
  "longitude": 2.3347,
  "description": "Luxury villa",
  "digicode": "B5678C",
  "number_of_floor": 3,
  "place_category": "Individual",
  "legal_regime": "MonoPropriete",
  "construction_date": "2015-03-10T00:00:00",
  "renovation_date": "2022-08-15T00:00:00"
}
```

**Response:** `201 Created`
Returns the created place object with generated ID and timestamps.

### Get Place
**GET** `/api/places/{id}`

Retrieve a specific place by ID.

**Path Parameters:**
- `id` (UUID): The place ID

**Response:** `200 OK`
Returns the place object.

### Update Place
**PUT** `/api/places/{id}`

Update an existing place. All fields are optional in update requests.

**Update behavior for optional fields:**
- **Field absent**: the existing value is preserved (no modification)
- **Field present with `null`**: the value is removed (set to NULL in the database)
- **Field present with a value**: the value is updated

**Path Parameters:**
- `id` (UUID): The place ID

**Request Body:**
```json
{
  "name": "Résidence Les Jardins - Rénovée",
  "description": "Fully renovated residential complex with garden views",
  "renovation_date": "2024-01-15T00:00:00",
  "digicode": "A9999B"
}
```

**Response:** `200 OK`
Returns the updated place object.

### Delete Place
**DELETE** `/api/places/{id}`

Delete a place (only possible if no estates are associated).

**Path Parameters:**
- `id` (UUID): The place ID

**Response:** `204 No Content`

---

## Nested Resources

### Estates Management
**See [Estates API](/properties/estates)** for detailed estate operations within places.

Places can contain multiple estates accessed through:
- **GET** `/api/places/{id}/estates`
- **POST** `/api/places/{id}/estates`
- And other estate-specific endpoints

### Services Management

### List Place Services
**GET** `/api/places/{id}/services`

Retrieve all services associated with a place.

**Path Parameters:**
- `id` (UUID): The place ID

**Response:** `200 OK`
```json
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440050",
    "place_id": "550e8400-e29b-41d4-a716-446655440000",
    "service_id": "550e8400-e29b-41d4-a716-446655440001",
    "name": "Building Maintenance",
    "description": "Monthly building upkeep",
    "is_chargeable": true,
    "category_id": "550e8400-e29b-41d4-a716-446655440060",
    "space_type": "INDOOR_COMMON",
    "default_distribution_key_id": "550e8400-e29b-41d4-a716-446655440070",
    "created_at": "2024-01-15T10:30:00Z"
  }
]
```

### Add Service to Place
**POST** `/api/places/{id}/services`

Add a service to a place.

**Path Parameters:**
- `id` (UUID): The place ID

**Request Body:**
```json
{
  "name": "Elevator Maintenance",
  "is_chargeable": true,
  "space_type": "TECHNICAL",
  "category_id": "550e8400-e29b-41d4-a716-446655440060",
  "default_distribution_key_id": "550e8400-e29b-41d4-a716-446655440070"
}
```

> If `is_chargeable = true`, both `category_id` and `default_distribution_key_id` are **required**.

**Response:** `201 Created`
Returns the created service association.

### Remove Service from Place
**DELETE** `/api/places/{id}/services/{service_id}`

Remove a service from a place.

**Path Parameters:**
- `id` (UUID): The place ID
- `service_id` (UUID): The service ID

**Response:** `204 No Content`

### Energy Diagnostics
**See [Energy Diagnosis API](/compliance/energy-diagnosis)** for energy assessments.

Energy diagnostics for places accessed through:
- **GET** `/api/places/{id}/energy-diagnoses`

---

## Data Types and Structures

### Place Object

| Field | Type | Description |
|-------|------|-------------|
| `id` | UUID | Generated place ID |
| `name` | string | Place name/title |
| `country` | string | Country name (e.g. "France") |
| `street_number` | string | Street number |
| `street_name` | string | Street name |
| `address_complement` | string | Additional address info (building, staircase, etc.) |
| `locality` | string | Locality/neighborhood |
| `postal_code` | string | Postal/ZIP code |
| `city` | string | City name |
| `postal_box` | string | Postal box |
| `latitude` | number | GPS latitude |
| `longitude` | number | GPS longitude |
| `description` | string | Place description |
| `type_id` | UUID | Reference to place type |
| `country_id` | UUID | Reference to country/legislative zone |
| `digicode` | string | Building access code |
| `number_of_floor` | integer | Number of floors |
| `owner_id` | UUID | Current owner ID |
| `previous_owner_id` | UUID | Previous owner ID |
| `construction_date` | datetime | Construction date |
| `renovation_date` | datetime | Last renovation date |
| `place_category` | PlaceCategory | Individual or Collective |
| `legal_regime` | PlaceLegalRegime | Legal ownership structure |
| `created_at` | datetime | Creation timestamp |
| `updated_at` | datetime | Last update timestamp |

### Required Fields for Creation

`name`, `type_id`, `country_id`, `owner_id`, `country`, `street_name`, `postal_code`, `city`, `place_category`, `legal_regime`

---

## Enums and Categories

### PlaceCategory
- `Individual` - Single-family property or individual building
- `Collective` - Multi-unit building or apartment complex

### PlaceLegalRegime
- `MonoPropriete` - Single ownership (one owner for entire building)
- `Copropriete` - Co-ownership/Condominium (multiple owners in building)

---

## Address Structure

Places use a structured address format with separate fields:
- **street_number**: House/building number (e.g. "24")
- **street_name**: Street name (required, e.g. "rue du Faubourg Saint-Antoine")
- **address_complement**: Building, staircase, floor details (e.g. "Bâtiment A")
- **locality**: Locality or neighborhood
- **postal_code**: Postal code (required, e.g. "75012")
- **city**: City (required, e.g. "Paris")
- **postal_box**: Postal box number
- **country**: Country name (required, e.g. "France")

### GPS Coordinates
Optional latitude/longitude coordinates for mapping:
- **latitude**: Decimal degrees (-90.0 to 90.0)
- **longitude**: Decimal degrees (-180.0 to 180.0)

### Building Access
- **digicode**: Entry code or access information
- **number_of_floor**: Total floors in building

---

## Error Responses

### Validation Errors
**400 Bad Request**
```json
{
  "error": "ValidationError",
  "message": "Invalid place data"
}
```

### Not Found
**404 Not Found**
```json
{
  "error": "NotFound",
  "message": "Place not found"
}
```

### Dependency Constraint
**409 Conflict**
```json
{
  "error": "Conflict",
  "message": "Cannot delete place with associated estates"
}
```

---

## Common Use Cases

### Creating a New Apartment Building
1. Create place with `POST /api/places`
2. Set `place_category` to "Collective" and `legal_regime` to "Copropriete"
3. Include building access information (digicode, number of floors)
4. Add individual apartments as estates
5. Configure building-wide services

### Managing Single-Family Properties
1. Create place with `place_category` set to "Individual"
2. Set `legal_regime` to "MonoPropriete"
3. Create single estate representing the entire property
4. Associate with individual owner

### Ownership Transfer
1. Update `previous_owner_id` with current `owner_id`
2. Set new `owner_id`
3. Update associated estates if needed

---

## Business Rules

- **Required Relationships**: Places must have valid type, country, and owner
- **Address**: `country`, `street_name`, `postal_code`, and `city` are mandatory
- **Ownership Consistency**: All estates in a place should reflect place ownership
- **Legal Regime**: Must match the actual legal structure of the property
- **Deletion Constraints**: Cannot delete places with associated estates or services
- **Coordinate Validation**: GPS coordinates must be within valid ranges

---

## Integration Notes

- **Place Types**: Reference to the [Types API](/api) for place categorization
- **Countries**: Integration with [Rent Regulation & Rent Control API](/compliance/legislative-zones)
- **Owners**: Reference to [Owners API](/people/owners) for ownership management
- **Estates**: Places contain multiple estates through nested routes
- **Services**: Building-level services affect all estates
- **Energy Diagnostics**: Building-level assessments complement estate-level diagnostics
