diff --git a/Provider/tdd/frontend_ota.md b/Provider/tdd/frontend_ota.md new file mode 100644 index 0000000..f460401 --- /dev/null +++ b/Provider/tdd/frontend_ota.md @@ -0,0 +1,71 @@ +# Frontend OTA Strategy for ESP32-S3 Provider + +**Authored by Antigravity** +**Date:** 2026-03-03 + +--- + +## 1. Goal + +Implement a robust Over-The-Air (OTA) update mechanism specifically for the Svelte frontend assets served by the ESP32-S3. The update must: +- Update the frontend code without requiring a full firmware re-flash. +- Provide a reliable fallback if an update fails (Rollback capability). +- Handle updates gracefully within the ESP32's available RAM limitations. +- Provide a dedicated UI for the user to upload new frontend binaries. + +## 2. Chosen Approach + +We have opted for a **Dual-Partition Image Flash (A/B slots)** strategy using **LittleFS**. + +Instead of updating individual files (HTML, JS, CSS) over HTTP, the build process will generate a single, pre-packaged `.bin` image of the entire `www` directory. This image will be streamed directly to an inactive flash partition, mimicking the safety of standard firmware OTA. + +## 3. Why Dual-Partition Image Flash? + +### Image Flash vs. Individual File Uploads +| | Image Flash (LittleFS .bin) | Individual File Uploads | +|---|---|---| +| **Integrity** | High (Flash whole partition, verify, switch) | Low (A failure mid-upload leaves a broken site) | +| **Simplicity (Backend)** | Easy: Stream bytes to raw flash partition | Hard: Manage file creation, deletion, truncation | +| **Speed** | Faster (One contiguous flash write) | Slower (Multiple HTTP requests, VFS overhead) | + +### Dual-Partition (A/B) vs. Single Partition +| | Dual-Partition (A/B) | Single Partition | +|---|---|---| +| **Rollback** | ✅ Yes: Revert to previous slot if new one fails | ❌ No: Broken update bricks the UI | +| **Flash Usage** | Higher (Requires 2x space) | Lower | + +**Decision**: Because we have a 16MB flash chip, allocating two 1MB partitions for the frontend (`www_0` and `www_1`) is trivial and provides crucial safety guarantees. + +## 4. Architecture & Workflow + +### 4.1. The Partition Table +The `partitions.csv` will be modified to include two 1MB data partitions for LittleFS: +- `www_0` +- `www_1` + +### 4.2. State Management (NVS) +The active partition index (0 or 1) will be stored in Non-Volatile Storage (NVS). +- On factory flash via serial, `www_0` is populated. +- During boot (`app_main`), the ESP32 reads the NVS key. If the key is empty, it defaults to `0` and mounts `www_0` to the `/www` VFS path. + +### 4.3. The Update Process (Backend) +1. **Identify Slot**: The ESP32 determines which slot is currently *inactive*. +2. **Stream Upload**: The new LittleFS image (.bin) is `POST`ed to `/api/ota/frontend`. +3. **Write to Flash**: The HTTP handler streams the payload directly to the raw, unmounted inactive partition using `esp_partition_erase_range` and `esp_partition_write`, bypassing LittleFS entirely to save RAM and CPU. +4. **Switch**: Once the upload completes successfully, the NVS pointer is updated to point to the newly flashed partition. +5. **Reboot**: The ESP32 reboots. The bootloader reads the new NVS value, mounts the updated partition, and the new frontend is served. + +*Design Note: We chose an explicit reboot over a hot-swap (unmounting and remounting at runtime) because a reboot is very fast (~2-3 seconds) and guarantees a clean state, closing any open file handles.* + +### 4.4. Security Decisions +Authentication and security for the `/api/ota/frontend` endpoint are deferred. The device operates exclusively on a local, trusted network, making immediate authentication overhead unnecessary for this iteration. + +## 5. Implementation Steps + +1. **Partition Table**: Update `partitions.csv` with `www_0` and `www_1` (1MB each). +2. **Boot Logic**: Update `main.cpp` and `http_server.cpp` to read the active partition from NVS and mount the correct label. +3. **API Endpoints**: + - Add `GET /api/ota/status` to report the current active slot. + - Add `POST /api/ota/frontend` to handle the binary stream. +4. **Frontend UI**: Create a standalone "Update" page in the Svelte app that fetches the status and provides a file picker and progress bar for the upload. +5. **Build Automation**: Add `mklittlefs` to the Node.js build pipeline to generate `www.bin` alongside the standard `dist` output.