# Contract & Contract Types API Documentation

## Overview

The Contract API has been refactored to normalize `contract_type` from an ENUM into a separate
`contract_types` table. This allows for dynamic management of contract types without requiring
database schema changes.

**Key Change:** `contract_type` (string ENUM) → `contract_type_id` (UUID foreign key)

## Architecture

### Before (v1 - Deprecated)

```
contracts table:
  - contract_type: ENUM('residential_lease', 'room_rental', 'service_agreement', 'other')
```

### After (v2 - Current)

```
contracts table:
  - contract_type_id: UUID (FK → contract_types.id)

contract_types table:
  - id: UUID (Primary Key)
  - code: VARCHAR(50) - Code identifier (residential_lease, room_rental, etc.)
  - name_vi: VARCHAR(100) - Vietnamese name
  - name_en: VARCHAR(100) - English name
  - description: TEXT - Detailed description
  - created_at, updated_at, created_by, updated_by: Audit fields
  - deleted_at, deleted_by: Soft delete fields
```

## ContractType Schema

### Response Format

```json
{
	"id": "123e4567-e89b-12d3-a456-426614174000",
	"code": "residential_lease",
	"name_vi": "Thuê nhà/căn hộ",
	"name_en": "Residential Lease",
	"description": "Hợp đồng thuê toàn bộ nhà hoặc căn hộ",
	"created_at": "2024-01-15T08:30:00Z",
	"updated_at": "2024-01-15T08:30:00Z"
}
```

## Default Contract Types

The system auto-seeds 4 default contract types:

| Code                | Vietnamese       | English           | Description                           |
| ------------------- | ---------------- | ----------------- | ------------------------------------- |
| `residential_lease` | Thuê nhà/căn hộ  | Residential Lease | Hợp đồng thuê toàn bộ nhà hoặc căn hộ |
| `room_rental`       | Thuê phòng       | Room Rental       | Hợp đồng thuê phòng đơn lẻ            |
| `service_agreement` | Hợp đồng dịch vụ | Service Agreement | Hợp đồng cung cấp dịch vụ             |
| `other`             | Khác             | Other             | Các loại hợp đồng khác                |

## Contract API

### Create Contract

**Endpoint:** `POST /api/v1/contracts`

**Request Body:**

```json
{
	"resident_id": "456e7890-abcd-1234-efgh-567890123456",
	"contract_number": "HĐ-2024-001",
	"contract_name": "Hợp đồng thuê phòng A101",
	"contract_type_id": "123e4567-e89b-12d3-a456-426614174000",
	"description": "Hợp đồng thuê phòng tại tòa nhà A",
	"rent_amount": 5000000,
	"deposit_amount": 10000000,
	"payment_day": 15,
	"signed_date": "2024-01-15",
	"expiry_date": "2025-01-15"
}
```

**Response:**

```json
{
	"success": true,
	"data": {
		"id": "789abcde-f012-3456-ghij-789012345678",
		"resident_id": "456e7890-abcd-1234-efgh-567890123456",
		"contract_number": "HĐ-2024-001",
		"contract_name": "Hợp đồng thuê phòng A101",
		"contract_type_id": "123e4567-e89b-12d3-a456-426614174000",
		"description": "Hợp đồng thuê phòng tại tòa nhà A",
		"rent_amount": 5000000,
		"deposit_amount": 10000000,
		"payment_day": 15,
		"signed_date": "2024-01-15",
		"expiry_date": "2025-01-15",
		"created_by": "user-id-here",
		"updated_by": null,
		"created_at": "2024-01-15T10:30:00Z",
		"updated_at": "2024-01-15T10:30:00Z",
		"deleted_at": null
	}
}
```

### Update Contract

**Endpoint:** `PUT /api/v1/contracts/{id}`

**Request Body (all fields optional):**

```json
{
	"contract_number": "HĐ-2024-002",
	"contract_name": "Updated name",
	"contract_type_id": "different-uuid-here",
	"description": "Updated description",
	"rent_amount": 6000000,
	"deposit_amount": 12000000,
	"payment_day": 20,
	"signed_date": "2024-02-01",
	"expiry_date": "2025-02-01"
}
```

### Get Contract by ID

**Endpoint:** `GET /api/v1/contracts/{id}`

**Response:**

```json
{
  "success": true,
  "data": {
    "id": "789abcde-f012-3456-ghij-789012345678",
    "resident_id": "456e7890-abcd-1234-efgh-567890123456",
    "contract_number": "HĐ-2024-001",
    "contract_name": "Hợp đồng thuê phòng A101",
    "contract_type_id": "123e4567-e89b-12d3-a456-426614174000",
    ...
  }
}
```

### List Contracts

**Endpoint:** `GET /api/v1/contracts`

**Query Parameters:**

```
?page=1&limit=20&orderBy=created_at&orderDir=DESC
```

**Response:**

```json
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "789abcde-f012-3456-ghij-789012345678",
        "resident_id": "456e7890-abcd-1234-efgh-567890123456",
        "contract_number": "HĐ-2024-001",
        "contract_type_id": "123e4567-e89b-12d3-a456-426614174000",
        ...
      }
    ],
    "total": 42,
    "page": 1,
    "limit": 20
  }
}
```

## Frontend Implementation Guide

### 1. Fetch Contract Types (on page load)

```typescript
// API Call to get all contract types
async function fetchContractTypes() {
	const response = await fetch('/api/v1/contract-types', {
		headers: {
			Authorization: `Bearer ${token}`,
			'Content-Type': 'application/json',
		},
	});

	if (!response.ok) {
		throw new Error('Failed to fetch contract types');
	}

	const data = await response.json();
	return data.data; // Array of contract types
}

// Store in state/context
const [contractTypes, setContractTypes] = useState([]);

useEffect(() => {
	fetchContractTypes().then(setContractTypes);
}, []);
```

### 2. Display Contract Type Dropdown

```tsx
<select
	name="contract_type_id"
	required
	onChange={(e) => setFormData({ ...formData, contract_type_id: e.target.value })}
	value={formData.contract_type_id}
>
	<option value="">-- Chọn loại hợp đồng --</option>
	{contractTypes.map((type) => (
		<option key={type.id} value={type.id}>
			{type.name_vi} ({type.code})
		</option>
	))}
</select>
```

### 3. Create Contract

```typescript
async function createContract(contractData) {
	const response = await fetch('/api/v1/contracts', {
		method: 'POST',
		headers: {
			Authorization: `Bearer ${token}`,
			'Content-Type': 'application/json',
		},
		body: JSON.stringify({
			resident_id: contractData.resident_id,
			contract_number: contractData.contract_number,
			contract_name: contractData.contract_name,
			contract_type_id: contractData.contract_type_id, // UUID
			description: contractData.description,
			rent_amount: contractData.rent_amount,
			deposit_amount: contractData.deposit_amount,
			payment_day: contractData.payment_day,
			signed_date: contractData.signed_date,
			expiry_date: contractData.expiry_date,
		}),
	});

	if (!response.ok) {
		const error = await response.json();
		throw new Error(error.message);
	}

	return await response.json();
}
```

### 4. Display Contract with Type Name

```tsx
// After fetching contract and contract types
function ContractCard({ contract, contractTypes }) {
	const contractType = contractTypes.find((t) => t.id === contract.contract_type_id);

	return (
		<div>
			<h3>{contract.contract_name}</h3>
			<p>
				Loại HĐ: <strong>{contractType?.name_vi}</strong>
			</p>
			<p>Số HĐ: {contract.contract_number}</p>
			<p>Giá thuê: {contract.rent_amount?.toLocaleString()} đ</p>
			<p>Ngày hết hạn: {new Date(contract.expiry_date).toLocaleDateString('vi-VN')}</p>
		</div>
	);
}
```

### 5. Update Contract

```typescript
async function updateContract(contractId, updates) {
	// Updates can include contract_type_id
	const response = await fetch(`/api/v1/contracts/${contractId}`, {
		method: 'PUT',
		headers: {
			Authorization: `Bearer ${token}`,
			'Content-Type': 'application/json',
		},
		body: JSON.stringify(updates),
	});

	if (!response.ok) {
		throw new Error('Failed to update contract');
	}

	return await response.json();
}
```

## Important Notes

### ✅ What Changed

- Request/Response now uses `contract_type_id` (UUID) instead of `contract_type` (string)
- `contract_type_id` is a **required field** when creating contracts
- You must select an ID from the `contract_types` table

### ⚠️ Migration Checklist for Frontend

- [ ] Update form inputs to use `contract_type_id` instead of `contract_type`
- [ ] Fetch contract types on app initialization
- [ ] Store contract types in state/context for reuse
- [ ] Update dropdowns/selects to show `name_vi` but send `id`
- [ ] Update display logic to lookup type name from contract types array
- [ ] Update validation - ensure `contract_type_id` is UUID format
- [ ] Test create/update/read flows

### 🔍 Debugging Tips

**To see all available contract types:**

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" \
  http://localhost:3000/api/v1/contract-types
```

**To verify contract_type_id in a contract:**

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" \
  http://localhost:3000/api/v1/contracts/{contractId}
```

Look for the `contract_type_id` field - it should be a UUID.

## Error Handling

### Invalid contract_type_id

```json
{
	"success": false,
	"error": {
		"code": "VALIDATION_ERROR",
		"message": "Invalid contract_type_id",
		"details": {
			"field": "contract_type_id",
			"reason": "Contract type not found"
		}
	}
}
```

### Missing contract_type_id

```json
{
	"success": false,
	"error": {
		"code": "VALIDATION_ERROR",
		"message": "contract_type_id is required"
	}
}
```

## Related API Endpoints

- `GET /api/v1/contract-types` - List all contract types
- `POST /api/v1/contracts` - Create contract
- `GET /api/v1/contracts` - List contracts
- `GET /api/v1/contracts/{id}` - Get contract by ID
- `PUT /api/v1/contracts/{id}` - Update contract
- `DELETE /api/v1/contracts/{id}` - Delete contract (soft delete)

## Support

For questions or issues with the API, please refer to:

- [API Development Guide](./api-development.md)
- Backend team documentation
- Database schema: [Migration 016](../sql/migrations/016-add-contract-types-table.sql)
