# Media Module Documentation

This document provides a detailed and comprehensive explanation of the `Media` module in the `newtouch-server` project. This module is responsible for managing all files and media (images, documents, videos) within the system, providing a secure and flexible mechanism for uploading, storing, processing, and linking files to various entities.

---

## 1. Concept & Philosophy

The Media module adopts a **"Staging Process"** methodology to ensure data cleanliness and system security.

### Traditional Problem:
In traditional systems, when a user uploads a file in a form (e.g., creating a "New Opportunity"), the file is either uploaded immediately and linked to a non-existent entity (since the opportunity hasn't been saved yet), or the upload is deferred until the opportunity is saved, causing a slow user experience. If the user cancels the operation, "Orphan Files" remain, consuming storage space.

### Solution in Media Module:
1.  **Staging Phase:** When a file is selected, it is uploaded immediately to a temporary area (Staging Area). It is not linked to any real entity yet, but to a dummy entity called `TemporaryMediaSubject`.
2.  **Upload Context:** A `context_uuid` is generated on the Frontend and sent with each file. This token groups files related to a single operation.
3.  **Claiming:** When the final opportunity is saved, the system sends the `context_uuid`. The Media module searches for all temporary files bearing this token and "transfer ownership" from the dummy entity to the real opportunity that was just created.
4.  **Auto Cleanup:** Any files remaining in Staging for a certain period (e.g., 24 hours) without being "Claimed" are considered abandoned and are automatically deleted by a scheduled job (Cron Job).

---

## 2. Database Schema

The module relies on one main table `media` (based on Spatie Media Library with customizations).

### `media` Table

| Field | Type | Detailed Description |
| :--- | :--- | :--- |
| `id` | `BigInteger` | The primary auto-increment key. |
| `model_type` | `string` | **Polymorphic Relation:** Class name of the entity owning the file (e.g., `Modules\Opportunity\Models\Opportunity`). In case of temporary storage, it is `Modules\Media\Models\TemporaryMediaSubject`. |
| `model_id` | `BigInteger` | **Polymorphic Relation:** ID of the owning entity. |
| `uuid` | `UUID` | Global unique identifier for the file. Used in APIs to handle the file instead of ID for increased security. |
| `collection_name` | `string` | Name of the collection the file belongs to (e.g., `profile_picture`, `contract_documents`, `staged_files`). Helps organize files for a single entity. |
| `name` | `string` | Human-readable name of the file (editable and does not affect the actual file name). |
| `file_name` | `string` | The actual name of the file on disk (Server or S3). It is sanitized and generated automatically to ensure security and uniqueness. |
| `mime_type` | `string` | Type of the file (e.g., `image/jpeg`, `application/pdf`). |
| `disk` | `string` | Name of the disk where it was stored (as defined in `config/filesystems.php`). E.g., `public`, `s3`, `local`. |
| `conversions_disk` | `string` | The disk where thumbnails or processed versions are stored. Often the same as `disk`. |
| `size` | `UnsignedBigInt` | File size in bytes. |
| `manipulations` | `JSON` | Stores any modifications done to images (crop, rotate) to be re-applied if necessary. |
| `custom_properties` | `JSON` | **Wildcard Field:** Stores any additional data. Staging data (`context_uuid`, `staged_by_user_uuid`) is stored here. |
| `generated_conversions` | `JSON` | Array storing names of thumbnails that have been generated and confirmed to exist. |
| `responsive_images` | `JSON` | Stores responsive images data to support different display screens. |
| `order_column` | `Integer` | To order files within the same Collection. |
| `created_at` | `DateTime` | Upload date. |
| `updated_at` | `DateTime` | Last modification date. |

---

## 3. Processes & Actions

### A. Phase Upload `StageMediaAction`
The file's journey starts here. This action is called when using the upload Endpoint.

**Execution Steps:**
1.  Receive files, user identifier (`user_uuid`), and upload context (`context_uuid`).
2.  Determine temporary storage disk (`stagedFilesDisk`).
3.  Call `mediaRepository->storeStagedFile` for each file:
    *   Create a dummy object `TemporaryMediaSubject` (with fixed ID = 1).
    *   Add the file to this object.
    *   **Most Importantly:** Inject the following data into `custom_properties`:
        *   `staged_by_user_uuid`: Who uploaded the file?
        *   `context_uuid`: Future binding key.
        *   `intended_collection_name`: Where should the file go later?
        *   `model_type_alias`: Future entity type.
4.  Fire `MediaStoredEvent`.

### B. File Claiming `claimStagedFile` (inside Repository)
This function is used by other modules (like Opportunity Module) when saving their data.

**Logic:**
1.  Search for the file in `media` table with conditions:
    *   File `uuid` matches.
    *   Collection is `staged_files`.
    *   Owner is `TemporaryMediaSubject`.
    *   `context_uuid` and `staged_by_user_uuid` match what was sent (for security).
2.  Perform a "move" operation:
    *   Change `model_type` and `model_id` to point to the new entity (the real Opportunity).
    *   Change `collection_name` to the final collection (e.g., `contract_documents`).
    *   Physically move the file from Temp folder to Permanent folder (if disk or path differs).
3.  Clear staging properties from `custom_properties` as they are no longer needed.

### C. Domain Entity: `MediaEntity`
It is an object representing the file in the Application Layer. Its feature is being `Immutable` and contains smart helper functions:
*   `getUrl()`: Returns public URL.
*   `getTemporaryUrl()`: Generates a signed URL for private files, valid for a specific duration.
*   `getCustomProperty('key')`: To retrieve custom properties easily.

---

## 4. API Reference

### 1. Upload Files (Staging)
**Endpoint:** `POST /api/v1/media/stage`

Uploads one or more files to the temporary area.

**Request (Multipart/Check-data):**
*   `files[]`: Files to be uploaded.
*   `context_uuid`: Upload session identifier (generated by Frontend).
*   `intended_collection_name`: Target collection name (e.g., `documents`).
*   `model_type_alias`: Shortcut for entity type (e.g., `opportunity`).

**Response Example:**
```json
{
    "data": [
        {
            "uuid": "550e8400-e29b-41d4-a716-446655440000",
            "name": "contract.pdf",
            "url": "http://api.domain.com/storage/temp/contract.pdf",
            "mime_type": "application/pdf",
            "size": 102400,
            "collection_name": "staged_files"
        }
    ],
    "message": "Files batch staging process completed."
}
```

### 2. Generate Temporary URL
**Endpoint:** `GET /api/v1/media/{mediaUuid}/temporary-url`

To access private files that cannot be accessed via a direct link.

**Request Query Params:**
*   `expires_in_minutes`: URL validity duration (optional, default 5 minutes).

**Response:**
```json
{
    "data": {
        "url": "https://s3.amazonaws.com/bucket/file.pdf?signature=xyz..."
    }
}
```

### 3. Delete File
**Endpoint:** `DELETE /api/v1/media/{mediaUuid}`

Deletes the file and its record from the database. User must be the owner or authorized.

### 4. Update Properties
**Endpoint:** `PUT /api/v1/media/{mediaUuid}`

Used to edit file name (Display Name) or custom properties.

**Request Body:**
```json
{
    "name": "Final Signed Contract",
    "custom_properties": {
        "is_reviewed": true
    }
}
```

---

## 5. Real Data Examples

### Example 1: File in Staging Phase
This is how the record looks in the database immediately after upload.

```json
{
  "id": 1050,
  "model_type": "Modules\\Media\\Infrastructure\\Persistence\\Eloquent\\Models\\TemporaryMediaSubject",
  "model_id": 1,
  "uuid": "a1b2c3d4-...",
  "collection_name": "staged_files",
  "name": "ID_Card.png",
  "file_name": "id-card-12345.png",
  "disk": "local_temp",
  "custom_properties": {
    "staged_by_user_uuid": "user-uuid-888",
    "context_uuid": "ctx-uuid-999",
    "intended_collection_name": "identity_proof",
    "original_client_name": "ID_Card.png",
    "staged_at": "2024-10-01T10:00:00"
  }
}
```

### Example 2: File after Claiming
This is how the record transforms after saving the opportunity and linking the file to it.

```json
{
  "id": 1050,
  "model_type": "Modules\\Opportunity\\Models\\Opportunity",
  "model_id": 500,  // <-- Owner changed to Opportunity #500
  "uuid": "a1b2c3d4-...",
  "collection_name": "identity_proof", // <-- Collection changed
  "name": "ID_Card.png",
  "disk": "s3_private", // <-- (Optional) might move to another disk
  "custom_properties": {
    "claimed_at": "2024-10-01T10:05:00",
    "original_client_name_at_staging": "ID_Card.png"
    // context_uuid removed as it served its purpose
  }
}
```

---

## Conclusion

The Media module in `Newtouch Server` provides a solid and secure infrastructure for file management. Using the **Staging** pattern solves a complex State Management problem between Frontend and Backend, and prevents the accumulation of unused files, ensuring high performance and a clean system in the long run.
