115 lines
5.4 KiB
Markdown
115 lines
5.4 KiB
Markdown
# 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 |
|
|
|
|
---
|
|
|
|
## 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)]"
|
|
```
|