# Lease Amendments (Avenants)

Lease amendments allow you to formally modify the terms of an active lease. Every modification to a lease — rent changes, duration extensions, tenant replacements, early terminations — must go through an amendment to maintain a complete legal audit trail.

## Legal Framework

The amendment system is built to comply with French real estate law:

| Law | Article | Requirement |
|-----|---------|-------------|
| Loi 89-462 | Art. 12 | Owner approval required for tenant/guarantor modifications |
| Loi 89-462 | Art. 15 | Minimum 90-day notice for early termination |
| Loi 89-462 | Art. 17-1 | Rent revision rules (index-based) |
| Loi 89-462 | Art. 17-2 | Rent cap in zone tendue (reference rent) |
| ALUR | Decret 2015-587 | Reference rent enforcement |
| Code Civil | Art. 1367 | Electronic signature validity |

## Amendment Types

| Type | Description | Sub-resource |
|------|-------------|--------------|
| `RENT_MODIFICATION` | Change the monthly rent amount | Rent Detail (1:1) |
| `DURATION_MODIFICATION` | Extend or reduce the lease duration | Duration Detail (1:1) |
| `RENEWAL` | Renew the lease for a new term | Duration Detail (1:1) |
| `TENANT_MODIFICATION` | Replace or add a tenant | Lease Lessee API |
| `GUARANTOR_MODIFICATION` | Replace or add a guarantor | Lease Lessee API |
| `CHARGE_MODIFICATION` | Modify service charges | Charge module |
| `CONDITION_MODIFICATION` | Update lease special conditions | — |
| `EARLY_TERMINATION` | Terminate the lease before end date | — |
| `OTHER` | Generic amendment | — |

## Status Lifecycle

```
DRAFT ──> PENDING_SIGNATURE ──> SIGNED ──> ACTIVE (terminal)
  │              │
  ├──> REJECTED  ├──> REJECTED
  │              │
  └──> CANCELLED └──> CANCELLED

                                          EXPIRED (terminal, set by system)
```

### Allowed transitions

| From | To | Trigger |
|------|----|---------|
| `DRAFT` | `PENDING_SIGNATURE` | Initiate signature |
| `DRAFT` | `REJECTED` | Reject amendment |
| `DRAFT` | `CANCELLED` | Cancel amendment |
| `PENDING_SIGNATURE` | `SIGNED` | All parties signed |
| `PENDING_SIGNATURE` | `REJECTED` | Reject during signature |
| `PENDING_SIGNATURE` | `CANCELLED` | Cancel during signature |
| `SIGNED` | `ACTIVE` | Activate (applies changes to lease) |

### Activation requirements

When transitioning from `SIGNED` to `ACTIVE`, the system:

1. **Checks all mandatory validations** are `APPROVED` (blocks if `PENDING` or `REJECTED`)
2. **Verifies the lease** is in `ACTIVE` status
3. **Applies the amendment changes** to the lease (type-specific logic)
4. **Validates business rules** (e.g., rent cap in zone tendue)
5. Transitions the amendment status
6. Fires notifications to relevant parties

### Conflict detection

Only one amendment of the same type can be in a non-terminal status (`DRAFT`, `PENDING_SIGNATURE`, or `SIGNED`) per lease at any time. Creating a second amendment of the same type while one is in progress returns a `400` error.

---

## Core CRUD Operations

### Create an amendment

```
POST /leases/{lease_id}/amendments
```

**Request body:**

Required fields: `amendment_type`, `effective_date`, `created_by`. All other fields are optional.

```json
{
  "amendment_type": "RENT_MODIFICATION",
  "effective_date": "2025-07-01",
  "description": "Annual rent revision based on IRL Q1 2025",
  "legal_reference": "Art. 17-1 Loi 89-462",
  "created_by": "550e8400-e29b-41d4-a716-446655440000"
}
```

**Auto-created validations:** For `TENANT_MODIFICATION`, `GUARANTOR_MODIFICATION`, and `EARLY_TERMINATION`, a mandatory `OWNER` validation is automatically created (Art. 12 & 15 Loi 89-462).

### List amendments

```
GET /leases/{lease_id}/amendments
```

Returns all amendments for the lease, ordered by creation date.

### Get a specific amendment

```
GET /leases/{lease_id}/amendments/{amendment_id}
```

### Update an amendment

```
PUT /leases/{lease_id}/amendments/{amendment_id}
```

Only allowed while the amendment is in `DRAFT` status.

### Delete an amendment

```
DELETE /leases/{lease_id}/amendments/{amendment_id}
```

### Change status

```
PUT /leases/{lease_id}/amendments/{amendment_id}/status
```

```json
{
  "status": "ACTIVE",
  "reason": "All parties signed, validation approved"
}
```

---

## Sub-Resources

### Rent Detail

One-to-one with `RENT_MODIFICATION` amendments. Stores the previous and new rent amounts, calculation method, and optional index references.

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/{amendment_id}/rent-detail` | `POST` | Create rent detail |
| `/{amendment_id}/rent-detail` | `GET` | Get rent detail |
| `/{amendment_id}/rent-detail` | `PUT` | Update rent detail |
| `/{amendment_id}/rent-detail` | `DELETE` | Delete rent detail |

**Rent cap validation (zone tendue):** At activation, if the lease has `is_subject_to_reference_rent_cap = true`, the system validates:

```
new_amount <= reference_rent_increased_per_m2 x estate.area
```

If exceeded, activation is blocked with a detailed error citing Art. 17-2.

**Example:**

```json
{
  "previous_amount": 850.00,
  "new_amount": 875.50,
  "increase_percentage": 3.0,
  "calculation_method": "INDEX_BASED",
  "calculation_details": {
    "index_name": "IRL",
    "quarter": "Q1 2025",
    "value": 143.46
  }
}
```

### Duration Detail

One-to-one with `DURATION_MODIFICATION` and `RENEWAL` amendments. Stores the previous and new end dates with the extension type.

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/{amendment_id}/duration-detail` | `POST` | Create duration detail |
| `/{amendment_id}/duration-detail` | `GET` | Get duration detail |
| `/{amendment_id}/duration-detail` | `PUT` | Update duration detail |
| `/{amendment_id}/duration-detail` | `DELETE` | Delete duration detail |

**Validation:** For `RENEWAL` and `EXTENSION` types, `new_end_date` must be after `previous_end_date`. For `REDUCTION` and `EARLY_TERMINATION`, an earlier date is allowed.

**Example:**

```json
{
  "previous_end_date": "2025-12-31",
  "new_end_date": "2028-12-31",
  "extension_type": "RENEWAL",
  "reason_code": "TACIT_RENEWAL",
  "reason_details": "Lease renewed by tacit agreement"
}
```

### Validations

Multi-role validation workflow. Each amendment can have multiple validation entries (one per role). Mandatory validations must all be `APPROVED` before the amendment can be activated.

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/{amendment_id}/validations` | `POST` | Create validation entry |
| `/{amendment_id}/validations` | `GET` | List all validations |
| `/{amendment_id}/validations/status` | `GET` | Compute aggregate status |
| `/{amendment_id}/validations/{id}` | `GET` | Get validation entry |
| `/{amendment_id}/validations/{id}` | `PUT` | Approve/reject |
| `/{amendment_id}/validations/{id}` | `DELETE` | Delete validation entry |

**Aggregate status computation:**

| Condition | Result |
|-----------|--------|
| No mandatory validations | `FULLY_VALIDATED` |
| Any mandatory = `REJECTED` | `REJECTED` |
| All mandatory = `APPROVED` | `FULLY_VALIDATED` |
| Otherwise | `PENDING` |

**Validator roles:** `LEGAL`, `FINANCIAL`, `PROPERTY_MANAGER`, `OWNER`, `TENANT`

**Approve a validation:**

```json
PUT /{amendment_id}/validations/{validation_id}
{
  "status": "APPROVED",
  "validated_by": "550e8400-e29b-41d4-a716-446655440000",
  "comments": "Approved after review"
}
```

### Documents

Documents attached to an amendment (unsigned drafts, signed copies, supporting documents).

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/{amendment_id}/documents` | `POST` | Attach a document |
| `/{amendment_id}/documents` | `GET` | List documents |
| `/{amendment_id}/documents/{id}` | `GET` | Get document |
| `/{amendment_id}/documents/{id}` | `PUT` | Update a document |
| `/{amendment_id}/documents/{id}` | `DELETE` | Delete document |
| `/{amendment_id}/documents/{id}/validate` | `PUT` | Validate a document |

**Document types:** `DRAFT`, `SIGNED_COPY`, `SUPPORTING_DOCUMENT`, `NOTICE`, `CALCULATION_DETAILS`, `LEGAL_NOTICE`

### History

Read-only audit trail. Entries are automatically created by the system when changes occur.

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/{amendment_id}/history` | `GET` | List all history entries |
| `/{amendment_id}/history/{id}` | `GET` | Get a specific entry |

**Change types:** `STATUS_CHANGE`, `CONTENT_MODIFICATION`, `VALIDATION_CHANGE`, `SIGNATURE_UPDATE`, `DOCUMENT_ADDITION`

### Notifications

Notifications are auto-created on status transitions and published as events for email delivery.

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/{amendment_id}/notifications` | `GET` | List notifications |
| `/{amendment_id}/notifications/{id}` | `GET` | Get notification |
| `/{amendment_id}/notifications/{id}` | `PUT` | Update status (mark read/actioned) |
| `/{amendment_id}/notifications/{id}` | `DELETE` | Delete notification |

**Auto-generated notifications:**

| Transition | Notification Type | Recipients |
|------------|-------------------|------------|
| Any -> `PENDING_SIGNATURE` | `SIGNATURE_REQUIRED` | All lessees + owner |
| Any -> `REJECTED` | `AMENDMENT_REJECTED` | Creator (owner) |
| Any -> `ACTIVE` | `AMENDMENT_ACTIVATED` | All lessees |
| Any -> `EXPIRED` | `AMENDMENT_EXPIRING` | Creator (owner) |

**Notification statuses:** `DRAFT` -> `SENT` -> `READ` -> `ACTIONED` (or `EXPIRED`)

**Recipient types:** `OWNER`, `LESSEE`, `VALIDATOR`, `CREATOR`

---

## PDF Generation

```
POST /leases/{lease_id}/amendments/{amendment_id}/generate-pdf
```

Generates a legal PDF document using Typst templates. The template is auto-selected based on `amendment_type`:

| Amendment Type | Template |
|---------------|----------|
| `RENT_MODIFICATION` | Rent revision template (Art. 17-1) |
| `DURATION_MODIFICATION` | Duration modification template |
| `TENANT_MODIFICATION` | Tenant modification template (3 signature zones) |
| Other types | Generic amendment template |

Returns `application/pdf` binary content.

---

## Electronic Signature

Two-step process using the shared signature infrastructure (Scaleway Topics + DO Global).

### Step 1 — Initiate

```
POST /{amendment_id}/initiate-signature
```

```json
{
  "initiator_id": "550e8400-e29b-41d4-a716-446655440000",
  "initiator_signer_type": "PROPRIETAIRE"
}
```

**What happens:**
1. Generates the amendment PDF (Typst)
2. Uploads to encrypted storage (SSE-C)
3. Creates `DocumentSignature` with `document_type: AMENDMENT`
4. Creates `SignatureRequest` per signer (owner + all lessees)
5. Publishes signature events to external queue
6. Transitions amendment to `PENDING_SIGNATURE`
7. Creates `DRAFT` document record

### Step 2 — Finalize

```
POST /{amendment_id}/finalize-signature
```

```json
{
  "document_signature_id": "...",
  "signed_pdf_url": "https://storage.example.com/signed/amendment_123.pdf"
}
```

**What happens:**
1. Updates `DocumentSignature` to `COMPLETED`
2. Stores signed PDF URL
3. Transitions amendment to `SIGNED`
4. Creates `SIGNED_COPY` document record

---

## Complete Workflow Example

Here's the full lifecycle for a rent modification amendment:

```
1. POST /leases/{id}/amendments
   → Creates amendment (DRAFT), returns amendment_id

2. POST /leases/{id}/amendments/{aid}/rent-detail
   → Attach rent detail (previous_amount, new_amount, calculation_method)

3. POST /leases/{id}/amendments/{aid}/validations
   → Add validation entries if needed (auto-created for some types)

4. PUT /leases/{id}/amendments/{aid}/validations/{vid}
   → Approve/reject each validation

5. GET /leases/{id}/amendments/{aid}/validations/status
   → Check aggregate status is FULLY_VALIDATED

6. POST /leases/{id}/amendments/{aid}/initiate-signature
   → Generates PDF, creates signature requests (DRAFT → PENDING_SIGNATURE)

7. POST /leases/{id}/amendments/{aid}/finalize-signature
   → After all parties sign (PENDING_SIGNATURE → SIGNED)

8. PUT /leases/{id}/amendments/{aid}/status
   { "status": "ACTIVE" }
   → Validates all validations approved
   → Checks rent cap in zone tendue
   → Updates lease rent_amount
   → SIGNED → ACTIVE
   → Sends AMENDMENT_ACTIVATED notifications to lessees
```

---

## Endpoints Summary

All endpoints are prefixed with `/leases/{lease_id}`.

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/amendments` | Create amendment |
| `GET` | `/amendments` | List amendments |
| `GET` | `/amendments/{id}` | Get amendment |
| `PUT` | `/amendments/{id}` | Update amendment |
| `DELETE` | `/amendments/{id}` | Delete amendment |
| `PUT` | `/amendments/{id}/status` | Change status |
| `POST` | `/amendments/{id}/generate-pdf` | Generate PDF |
| `POST` | `/amendments/{id}/initiate-signature` | Start signature |
| `POST` | `/amendments/{id}/finalize-signature` | Complete signature |
| `POST` | `/amendments/{id}/rent-detail` | Create rent detail |
| `GET` | `/amendments/{id}/rent-detail` | Get rent detail |
| `PUT` | `/amendments/{id}/rent-detail` | Update rent detail |
| `DELETE` | `/amendments/{id}/rent-detail` | Delete rent detail |
| `POST` | `/amendments/{id}/duration-detail` | Create duration detail |
| `GET` | `/amendments/{id}/duration-detail` | Get duration detail |
| `PUT` | `/amendments/{id}/duration-detail` | Update duration detail |
| `DELETE` | `/amendments/{id}/duration-detail` | Delete duration detail |
| `POST` | `/amendments/{id}/validations` | Create validation |
| `GET` | `/amendments/{id}/validations` | List validations |
| `GET` | `/amendments/{id}/validations/status` | Aggregate status |
| `GET` | `/amendments/{id}/validations/{vid}` | Get validation |
| `PUT` | `/amendments/{id}/validations/{vid}` | Approve/reject |
| `DELETE` | `/amendments/{id}/validations/{vid}` | Delete validation |
| `POST` | `/amendments/{id}/documents` | Attach document |
| `GET` | `/amendments/{id}/documents` | List documents |
| `GET` | `/amendments/{id}/documents/{did}` | Get document |
| `PUT` | `/amendments/{id}/documents/{did}` | Update document |
| `DELETE` | `/amendments/{id}/documents/{did}` | Delete document |
| `PUT` | `/amendments/{id}/documents/{did}/validate` | Validate document |
| `GET` | `/amendments/{id}/history` | List history |
| `GET` | `/amendments/{id}/history/{eid}` | Get history entry |
| `GET` | `/amendments/{id}/notifications` | List notifications |
| `GET` | `/amendments/{id}/notifications/{nid}` | Get notification |
| `PUT` | `/amendments/{id}/notifications/{nid}` | Update notification |
| `DELETE` | `/amendments/{id}/notifications/{nid}` | Delete notification |

**Total: 36 endpoints**
