coding guidelines, agents and gemini.md

This commit is contained in:
2026-03-09 22:07:48 -04:00
parent 9d3a277f45
commit 75d88f441c
4 changed files with 316 additions and 1 deletions

View File

@@ -0,0 +1,124 @@
# Calendink Coding Guidelines
These rules apply to all code in this workspace.
---
## Backend — C++ / ESP-IDF
### Philosophy: C-with-Utilities
Write **C-style code** using C++ convenience features. No classes, no methods, no RAII, no exceptions.
**Use freely:** `template`, `auto`, `constexpr`, `enum class`, type aliases from `types.hpp`
**Avoid:** classes, constructors/destructors, `std::` containers, inheritance, virtual functions, RAII wrappers
`goto` for cleanup/shutdown paths in `app_main` is acceptable.
### Unity Build
All `.cpp` files are `#include`-ed into `main.cpp` as a single translation unit. **Do not register new source files in CMakeLists.txt.**
- Use `unity.cpp` aggregators per API group (e.g., `api/tasks/unity.cpp`)
- Mark all file-scoped symbols with `internal` (defined as `static` in `types.hpp`)
- Use `.hpp` for declarations shared across included files only
### API Handler Pattern
```cpp
// METHOD /api/path — What it does
// Body: { "field": value } (if applicable)
internal esp_err_t api_foo_post_handler(httpd_req_t *req) {
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
// 1. Parse request
// 2. Call store function
// 3. Build cJSON response
// Always cJSON_Delete() objects and free() printed strings — no leaks
}
internal const httpd_uri_t api_foo_post_uri = { .uri = "/api/foo", .method = HTTP_POST, .handler = api_foo_post_handler, .user_ctx = NULL };
```
### Store / Handler Separation
Data operations in `store.cpp` / `store.hpp`. HTTP parsing in endpoint files. Never mix them.
### Logging
**Always use `ESP_LOGI` / `ESP_LOGW` / `ESP_LOGE`** — never `printf()`.
Since this is a Unity Build (single translation unit), the log tag must be unique per file to avoid redefinition. Name it after the module, not a generic `TAG`:
```cpp
// In each file, use a unique local name:
internal const char *kTagHttpServer = "HTTP_SERVER";
internal const char *kTagMain = "MAIN";
internal const char *kTagMDNS = "MDNS";
```
### Type Aliases
Use `types.hpp` aliases: `uint8`, `uint16`, `uint32`, `uint64`, `int8``int64`, `internal`
### Seed Data
`seed_users()` and `seed_tasks()` must be guarded:
```cpp
#ifndef NDEBUG
seed_users();
seed_tasks();
#endif
```
### Data Persistence
All task/user data is currently **in-RAM only** (intentional — NVS/LittleFS persistence is a future milestone). Do not add persistence without a TDD.
---
## Frontend — Svelte 5 + TailwindCSS v4
### Styling: Tailwind Only
Use TailwindCSS exclusively. **No `<style>` blocks in components.**
- All design tokens are in `app.css` via `@theme`: `bg-bg-card`, `text-text-primary`, `border-border`, `text-accent`, `text-success`, `text-danger`, etc.
- If a utility is missing, add a token to `@theme` — don't add inline CSS
### Reactivity: Svelte 5 Runes Only
| Do ✅ | Don't ❌ |
|---|---|
| `$state()` | `writable()`, `readable()` |
| `$derived()` / `$derived.by()` | `$:` reactive statements |
| `$effect()` | `onMount()`, `onDestroy()`, `.subscribe()` |
| `$props()` / `$bindable()` | `export let` |
### `$state()` vs Plain `let`
- **`$state()`** — values the template reads, or that changes should cause a re-render
- **Plain `let`** — script-only internals (mutex flags, interval handles, etc.) the template never reads
### `$effect()` for Initialization
When an effect has no reactive dependencies and runs once on mount, add a comment:
```js
// Load initial data on mount
$effect(() => { fetchData(); });
```
### Shared Utilities
- Date/time helpers, formatters → `lib/utils.js`
- Cross-component reactive state → `lib/stores.js`
- API calls → `lib/api.js` (always via `trackedFetch()`)
**Never duplicate functions across components.**
### Component Structure
```svelte
<script>
// 1. Imports
// 2. $props()
// 3. $state()
// 4. $derived()
// 5. Functions
// 6. $effect()
</script>
<!-- Template — Tailwind classes only -->
```
---
## General
- **Don't commit build artifacts**: `dist/`, `bundles/`, `temp_*`, `*.gz` — update `.gitignore` accordingly
- **Version** is managed through `version.json`, injected as `__APP_VERSION__` at build time

View File

@@ -10,3 +10,4 @@ Pleaes add the date.
The TDD should starts with the What, then the Why and finally the how. The TDD should starts with the What, then the Why and finally the how.
Everytime you write a document you can read other tdd in the folder for inspiration. Everytime you write a document you can read other tdd in the folder for inspiration.
When implementation is finished, the user can add to edit the TDD to add more informations (implementation details that are important, benchmarks, any change of plan during development) When implementation is finished, the user can add to edit the TDD to add more informations (implementation details that are important, benchmarks, any change of plan during development)
When you add a tdd, please update Gemini.md to add the tdd.

85
Provider/AGENTS.md Normal file
View File

@@ -0,0 +1,85 @@
# AGENTS.md
Calendink Provider — ESP32-S3 firmware + Svelte 5 web dashboard.
Uses **ESP-IDF** (not Arduino). Serves UI from LittleFS flash partitions over Ethernet/WiFi.
---
## Build Commands
```powershell
# Backend (from project root)
idf.py build
idf.py flash monitor
# Frontend (from frontend/)
npm run dev # Dev server — calls real ESP32 API (set VITE_API_BASE in .env.development)
npm run build # Production build → dist/index.html
npm run build:esp32 # Build + gzip → dist/index.html.gz
npm run ota:deploy # OTA deploy frontend to device
```
There are no automated tests. Verify by building and inspecting on-device.
---
## Project Layout
```
main/ C++ firmware (Unity Build — one translation unit)
main/api/<domain>/ HTTP endpoint files, one per verb
main/http_server.cpp Server setup, static file serving, scratch buffer pool
main/connect.cpp Ethernet + WiFi management
frontend/src/ Svelte 5 components + api.js
frontend/src/app.css TailwindCSS v4 @theme design tokens
tdd/ Technical Design Documents — read before major changes
.agents/rules/ Coding guidelines
```
---
## Backend Rules (C++ / ESP-IDF)
- **Unity Build**: `main.cpp` `#include`s all `.cpp` files. Do NOT add files to `CMakeLists.txt`.
- **C-style only**: no classes, no `std::`, no RAII, no exceptions. `template`, `auto`, `constexpr` are fine.
- **`internal`** (= `static`) on all file-scoped symbols — defined in `main/types.hpp`.
- **Logging**: use `ESP_LOGI` / `ESP_LOGW` / `ESP_LOGE` only — never `printf()`.
- Because of Unity Build, tag variables must have unique names per file: `kTagHttpServer`, `kTagMain`, etc. — never use a shared `TAG`.
- **Seed data**: `seed_users()` / `seed_tasks()` must be inside `#ifndef NDEBUG` guards.
- **API handler pattern**: set CORS header + response type → parse request → call store function → build cJSON response → `free()` strings, `cJSON_Delete()` objects.
- **Data is in-RAM only** (`g_Users[8]`, `g_Tasks[32]`). This is intentional — persistence is a future milestone. Don't add it without a TDD.
---
## Frontend Rules (Svelte 5 + TailwindCSS v4)
- **Tailwind only** — no `<style>` blocks in components. Design tokens are in `frontend/src/app.css` (`@theme`).
- **Svelte 5 runes only** — `$state`, `$derived`, `$effect`, `$props`, `$bindable`. No `export let`, `onMount`, `onDestroy`, `writable`, or `.subscribe()`.
- **`$state()`** for values the template reads. **Plain `let`** for script-only handles/flags the template never reads.
- **`$effect()` with no reactive deps** runs once on mount — add a comment saying so.
- All API calls through `lib/api.js` via `trackedFetch()` — never raw `fetch()`.
- Shared utilities (formatters, helpers) in `lib/utils.js`. Never duplicate functions across components.
---
## Technical Design Documents
Read the relevant TDD before any major architectural change:
| TDD | Read when |
|---|---|
| `tdd/backend_architecture.md` | Changing server setup, adding API groups |
| `tdd/frontend_technology_choices.md` | Changing build tools or dependencies |
| `tdd/todo_list.md` | Changing task/user data model or API contracts |
| `tdd/firmware_ota.md` | Touching OTA partition logic |
| `tdd/frontend_ota.md` | Touching frontend OTA upload or versioning |
| `tdd/concurrent_requests.md` | Changing HTTP server socket/connection config |
---
## Working with the User
- After finishing a task: explain what changed, what you recommend next, and wait for approval.
- Never make changes beyond the agreed scope without asking first.
- Write a TDD (see `.agents/rules/how-to-write-tdd.md`) before major architectural changes.
- **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.

105
Provider/GEMINI.md Normal file
View File

@@ -0,0 +1,105 @@
# 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 |
---
## 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
```