5.5 KiB
5.5 KiB
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#includes all.cppfiles. Do NOT add files to CMakeLists.txt. Everything is one translation unit. - API handlers: Each endpoint is its own
.cppfile inmain/api/<domain>/. Aunity.cppaggregates 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_1for frontend,ota_0/ota_1for 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-singlefileinlines all JS+CSS into oneindex.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. Usetemplate,auto,constexprfreely. - Use
internal(=static) for all file-scoped symbols. - Log with
ESP_LOGI/W/Eonly — neverprintf(). Name log tags per-module with unique variable names (e.g.,kTagHttpServer), not a sharedTAG, to avoid Unity Build redefinition. - Seed data (
seed_users,seed_tasks) must be#ifndef NDEBUGguarded.
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.jsviatrackedFetch()— never rawfetch(). $state()for values the template reads. Plainletfor script-only flags/handles.
Technical Design Documents
Always read the relevant TDD before making major architectural changes:
| TDD | When to read |
|---|---|
| backend_architecture.md | Changing server setup, adding new API groups |
| frontend_technology_choices.md | Changing build tools, adding dependencies |
| todo_list.md | Changing task/user data models or API contracts |
| firmware_ota.md | Touching OTA partition logic |
| frontend_ota.md | Touching frontend OTA upload or versioning |
| concurrent_requests.md | Changing HTTP server socket/connection config |
| lvgl_image_generation.md | Touching LVGL headless display or image gen |
| 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.mdandGEMINI.mdup 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
# 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:)
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)]"