docs: Add guidelines for writing technical design documents and a detailed design for the new in-memory todo list system.

This commit is contained in:
2026-03-07 18:50:02 -05:00
parent 0ec7f7f08a
commit 8ab1efcca7
2 changed files with 164 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
---
trigger: model_decision
description: When working on a TDD (technical design document)
---
TDD Should be added to the /tdd folder.
When writing a TDD, please write it so that it can be read by human or agent ai.
Please start by writing that it was authored by an ai agent and write your actual agent name.
Pleaes add the date.
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.
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)

152
Provider/tdd/todo_list.md Normal file
View File

@@ -0,0 +1,152 @@
# Todo List System for ESP32-S3 Provider
**Authored by Antigravity (Claude Opus)**
**Date:** 2026-03-07
---
## 1. Goal
Add a user-managed todo list system to the Calendink Provider. The system must:
- Allow creating, modifying, and deleting **users** via a REST API.
- Allow creating, modifying, and deleting **tasks** per user, each with a due date.
- Display the **top 3 upcoming tasks** per user on the Dashboard home page.
- Introduce a **collapsible sidebar** to navigate between Dashboard and a detailed Task Manager view.
- Store everything **in RAM only** — all data is lost on reboot. Persistent storage (SQLite on SD card) is planned as a future phase.
- Pre-populate **seed data** on boot so the UI is immediately usable during development without manual setup after every reboot.
## 2. Chosen Approach
### 2.1. Backend: Static Arrays in BSS
Users and tasks are stored as **fixed-size static arrays** at file scope (BSS segment). This means:
- No `malloc` / `free` — zero fragmentation risk on a constrained device.
- Deterministic memory footprint: the arrays consume a fixed amount of RAM regardless of usage.
- Simple slot-based allocation: each entry has an `active` flag; adding an item finds the first inactive slot, deleting clears the flag.
Limits: `MAX_USERS = 8`, `MAX_TASKS = 32` (total across all users). At ~80 bytes per task and ~40 bytes per user, this uses <3KB of RAM — negligible against the ~247KB free heap the system typically has. These limits will become irrelevant when we migrate to SQLite.
### 2.2. Frontend: Sidebar + View Routing
The existing single-page dashboard is extended with a collapsible left sidebar. The `App.svelte` component gains a view state (`'dashboard' | 'tasks'`) and conditionally renders either the existing Dashboard content or a new `TodoManager` component. This avoids introducing a full client-side router for what is currently a two-view app.
### 2.3. API Style: RESTful with DELETE
We use standard REST conventions: `GET` for reads, `POST` for creates/updates, `DELETE` for removals. This requires updating the existing CORS handler to allow the `DELETE` method. We chose REST purity over the simpler "POST everything" approach because the API surface is small enough that the CORS overhead is negligible, and it sets the right pattern for future endpoint growth.
## 3. Design Decisions & Trade-offs
### 3.1. Why Static Arrays Over Heap Allocation?
| | Static Arrays (BSS) | Dynamic (malloc/vector) |
|---|---|---|
| **Fragmentation** | ✅ Impossible | ⚠️ Risk on long-running device |
| **Memory footprint** | Fixed, predictable | Grows/shrinks at runtime |
| **Complexity** | Trivial — array index + active flag | Requires careful lifetime management |
| **Scalability** | Hard limit (32 tasks) | Flexible |
| **Migration path** | Replace array access with SQLite queries | Same |
For a temporary in-memory store that will be replaced by SQLite, static arrays are the simpler and safer choice. The hard limits are acceptable given the short-lived nature of this storage layer.
### 3.2. Why a Dedicated `/api/tasks/upcoming` Endpoint?
The Dashboard needs to show the top 3 tasks per user, sorted by due date. Two options were considered:
1. **Client-side**: Fetch all tasks for all users, sort and slice on the frontend.
2. **Server-side**: Dedicated endpoint that returns pre-sorted, pre-sliced data.
We chose option 2 because:
- It reduces the number of API calls (1 instead of N per user).
- Sorting and filtering on the ESP32 is trivial for 32 items.
- The response payload is smaller — only the data the Dashboard actually needs.
### 3.3. Seed Data Strategy
Since all data is lost on reboot, manually re-creating users and tasks after every firmware flash would slow down development. Both `user.hpp` and `todo.hpp` expose `seed_users()` / `seed_tasks()` functions called at server startup. The seed tasks use **relative time offsets** from the current system time (e.g., "now + 1 day", "now + 3 days"), so due dates always appear realistic regardless of when the device boots.
### 3.4. Frontend Navigation: Sidebar vs. Tabs vs. Router
| | Sidebar | Tabs | Client-side Router |
|---|---|---|---|
| **Scalability** | ✅ Easily add more views | Limited horizontal space | Best for many routes |
| **Discoverability** | Always visible (or icon-only when collapsed) | Always visible | Requires URL navigation |
| **Complexity** | Low — simple boolean state | Low | Higher — routing library needed |
| **Mobile** | Collapsible — works well | Good | Good |
A sidebar is the best fit: it scales to future views (Calendar, Settings, etc.), gives a clear navigation model, and the collapsible behavior keeps it unobtrusive on smaller screens.
### 3.5. `max_uri_handlers` Increase
The ESP-IDF HTTP server has a compile-time limit on registered URI handlers (default: 8, currently set to 10). Adding 7 new endpoints (3 user + 4 task) brings the total to ~17. We increase the limit to 20 to accommodate the new routes with room for growth. Each handler slot costs minimal memory (~40 bytes).
## 4. Architecture
### 4.1. Data Models
```
user.hpp todo.hpp
┌─────────────────────┐ ┌──────────────────────────┐
│ user_t │ │ task_t │
│ id: uint8 │◄─────── │ user_id: uint8 │
│ name: char[32] │ │ id: uint16 │
│ active: bool │ │ title: char[64] │
└─────────────────────┘ │ due_date: int64 (epoch)│
g_Users[MAX_USERS=8] │ completed: bool │
│ active: bool │
└──────────────────────────┘
g_Tasks[MAX_TASKS=32]
```
### 4.2. API Endpoints
| Method | URI | Purpose |
|--------|-----|---------|
| `GET` | `/api/users` | List all active users |
| `POST` | `/api/users` | Create a user |
| `DELETE` | `/api/users?id=N` | Delete a user + cascade-delete their tasks |
| `GET` | `/api/tasks?user_id=N` | List tasks for a user |
| `GET` | `/api/tasks/upcoming` | Top 3 upcoming tasks per user (Dashboard) |
| `POST` | `/api/tasks` | Create a task |
| `POST` | `/api/tasks/update` | Modify a task (title, due date, completion) |
| `DELETE` | `/api/tasks?id=N` | Delete a task |
### 4.3. Backend File Structure
```
Provider/main/
├── user.hpp # user_t struct, g_Users[], seed_users()
├── todo.hpp # task_t struct, g_Tasks[], seed_tasks()
├── api/
│ ├── users/
│ │ └── manage.cpp # User CRUD handlers
│ ├── tasks/
│ │ └── manage.cpp # Task CRUD + upcoming handlers
│ ├── system/
│ │ ├── info.cpp
│ │ └── reboot.cpp
│ └── ota/
│ └── ...
├── http_server.cpp # +includes, +handlers, +CORS update
└── main.cpp # Entry point (unchanged)
```
### 4.4. Frontend Component Structure
```
frontend/src/
├── App.svelte # Layout with Sidebar + view routing
├── lib/
│ ├── Sidebar.svelte # Collapsible left nav
│ ├── UserManager.svelte # User selection & management
│ ├── TaskManager.svelte # Full task management UI (embeds UserManager)
│ ├── OTAUpdate.svelte # Existing OTA component
│ └── api.js # +user/task API functions
└── app.css # +sidebar theme tokens
```
## 5. Summary
We implement a **temporary in-memory todo list** using **static BSS arrays** on the ESP32 backend, exposed via a **RESTful API** with 8 new endpoints. The frontend gains a **collapsible sidebar** for navigation between the existing Dashboard and a new **Task Manager** view. **Seed data** is populated on every boot for fast development iteration. The architecture is designed to make the eventual migration to **SQLite on SD card** straightforward — the API contracts and frontend components remain unchanged; only the storage layer swaps out.
---
*Created by Antigravity (Claude Opus) - Last Updated: 2026-03-07*