# Calendink Provider — Agent Context

This is an **ESP32-S3 IoT device** firmware + web dashboard project.
It uses **ESP-IDF** (native, not Arduino) and serves a **Svelte 5 web UI** from flash.

---

## Project Summary

Calendink Provider is a connected desk device that serves a local web dashboard over Ethernet/WiFi.
The firmware manages network connections, serves a Svelte SPA from LittleFS flash partitions, and exposes a REST API for system control (reboot, OTA, tasks, users).

### Key Paths

| Path | Purpose |
|---|---|
| `main/` | C++ firmware (Unity Build) |
| `main/api/` | REST API handlers, one file per endpoint |
| `main/http_server.cpp` | HTTP server setup, static file serving |
| `main/connect.cpp` | Ethernet + WiFi connection management |
| `frontend/src/` | Svelte 5 frontend source |
| `frontend/src/lib/api.js` | All API calls (always use `trackedFetch`) |
| `frontend/src/app.css` | TailwindCSS v4 design tokens (`@theme`) |
| `tdd/` | Technical Design Documents (read before major changes) |
| `.agents/rules/` | Coding guidelines (always follow) |

---

## Architecture

### Backend

- **Unity Build**: `main.cpp` `#include`s all `.cpp` files. Do NOT add files to CMakeLists.txt. Everything is one translation unit.
- **API handlers**: Each endpoint is its own `.cpp` file in `main/api/<domain>/`. A `unity.cpp` aggregates them.
- **HTTP server**: `esp_http_server` + `cJSON`. CORS is always on (`*`).
- **Data storage**: Users and tasks are in static BSS arrays (`g_Users[8]`, `g_Tasks[32]`). In-RAM only, intentionally — persistence is a future feature.
- **OTA**: A/B partition scheme — `www_0` / `www_1` for frontend, `ota_0` / `ota_1` for firmware. NVS tracks which slot is active.
- **Connections**: Ethernet first, WiFi fallback. Connection state managed with FreeRTOS semaphores.

### Frontend

- **Svelte 5** with runes (`$state`, `$derived`, `$effect`, `$props`). No legacy Svelte 4 APIs.
- **TailwindCSS v4** (utility classes only — no `<style>` blocks in components).
- **Single-file build**: `vite-plugin-singlefile` inlines all JS+CSS into one `index.html`.
- **Version**: Tracked in `version.json`, injected as `__APP_VERSION__` at build time.
- **Dev mode**: Set `VITE_API_BASE=http://<ESP32_IP>` in `.env.development` — the frontend runs on PC and calls the real ESP32 API.

---

## Coding Rules (summary — full rules in `.agents/rules/coding-guidelines.md`)

### Backend
- C-style code: no classes, no `std::`, no RAII, no exceptions. Use `template`, `auto`, `constexpr` freely.
- Use `internal` (= `static`) for all file-scoped symbols.
- Log with `ESP_LOGI/W/E` only — never `printf()`. Name log tags per-module with unique variable names (e.g., `kTagHttpServer`), not a shared `TAG`, to avoid Unity Build redefinition.
- Seed data (`seed_users`, `seed_tasks`) must be `#ifndef NDEBUG` guarded.

### Frontend
- Svelte 5 runes only. No `onMount`, `onDestroy`, `writable`, `.subscribe`.
- Tailwind only. No `<style>` blocks.
- Shared logic goes in `lib/utils.js`. Never duplicate functions across components.
- API calls go through `lib/api.js` via `trackedFetch()` — never raw `fetch()`.
- `$state()` for values the template reads. Plain `let` for script-only flags/handles.

---

## Technical Design Documents

Always read the relevant TDD before making major architectural changes:

| TDD | When to read |
|---|---|
| [backend_architecture.md](tdd/backend_architecture.md) | Changing server setup, adding new API groups |
| [frontend_technology_choices.md](tdd/frontend_technology_choices.md) | Changing build tools, adding dependencies |
| [todo_list.md](tdd/todo_list.md) | Changing task/user data models or API contracts |
| [firmware_ota.md](tdd/firmware_ota.md) | Touching OTA partition logic |
| [frontend_ota.md](tdd/frontend_ota.md) | Touching frontend OTA upload or versioning |
| [concurrent_requests.md](tdd/concurrent_requests.md) | Changing HTTP server socket/connection config |
| [lvgl_image_generation.md](tdd/lvgl_image_generation.md) | Touching LVGL headless display or image gen |
| [device_screens.md](tdd/device_screens.md) | Changing device registration, MAC routing, or XML layout logic |

---

## How to Work With the User

- After finishing any task: tell the user what you did, what you think the next step should be, and ask for approval before proceeding.
- Never go rogue — propose changes, wait for confirmation.
- Write a TDD before major architectural changes. See `.agents/rules/how-to-write-tdd.md`.
- **Keep `AGENTS.md` and `GEMINI.md` up to date.** If a task changes the architecture, adds new rules, introduces new build commands, or modifies the project layout — update both files before closing the task.

---

## Build Commands

```powershell
# Backend — from project root
idf.py build
idf.py flash monitor

# Frontend — from frontend/
npm run dev                # Dev server (PC, calls real ESP32 API)
npm run build              # Production build → dist/index.html
npm run build:esp32        # Build + gzip → dist/index.html.gz
npm run ota:package        # Package as versioned .bin
npm run ota:bundle         # Package FW + frontend as .bundle
npm run ota:deploy         # Deploy frontend OTA to device
```

## Logging on Ethernet

When the device is connected to Ethernet, logs are broadcast over UDP to port 514. Use `ncat -ul 514` on your PC to view them live.
*(If `ncat` throws a `WSAEMSGSIZE` error on Windows, use this Python command instead:)*
```powershell
python -c "import socket; s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM); s.bind(('', 514)); [print(m[0].decode(errors='ignore'), end='') for m in iter(lambda:s.recvfrom(4096), None)]"
```
