# Universal OTA Bundle

The Universal OTA Bundle allows you to update both the **Firmware** and the **Frontend** of the Calendink Provider in a single operation. This ensures that your UI and backend logic are always in sync.

## 1. How it Works

The bundle is a custom `.bundle` file that contains:
1. A **12-byte header** (Magic `BNDL`, FW size, UI size).
2. The **Firmware binary** (`Provider.bin`).
3. The **Frontend LittleFS binary** (`www_v*.bin`).

The ESP32 backend streams this file, writing the firmware to the next OTA slot and the frontend to the inactive `www` partition. It only commits the update if both parts are written successfully.

## 2. Prerequisites

- You have a working [Frontend Build Environment](build_frontend.md).
- You have the [ESP-IDF SDK](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) installed for firmware compilation.

## 3. Creating a Bundle

To create a new bundle, follow these steps in order:

### Step A: Build the Frontend
Inside the `frontend/` directory:
```bash
npm run build:esp32
```

### Step B: Build the Firmware
From the project **root** directory:
```bash
idf.py build
```

### Step C: Generate the Bundle
Inside the `frontend/` directory:
```bash
npm run ota:bundle
```
> [!NOTE]
> `npm run ota:bundle` now automatically runs `npm run ota:package` first to ensure the latest Svelte build is turned into a LittleFS image before bundling.

The output will be saved in `frontend/bundles/` with a name like `universal_v0.1.11.bundle`.

## 4. Flashing the Bundle

1. Open the Calendink Provider Dashboard in your browser.
2. Navigate to the **System Updates** section.
3. Click the **Universal Bundle** button.
4. Drag and drop your `.bundle` file into the upload area.
5. Click **Update**.

The device will reboot once the upload is complete. You can verify the update by checking the version numbers and the UI changes (like the number of rockets in the header!).

## 5. Troubleshooting

- **"Invalid bundle magic"**: Ensure you are uploading a `.bundle` file, not a `.bin`.
- **"Firmware part is corrupted"**: The bundle was likely created while the firmware build was incomplete or failed.
- **Old UI appearing**: Ensure you ran `npm run build:esp32` *before* `npm run ota:bundle`.
