# Repository Guidelines ## Project Structure & Layering - `components/platform/{include,internal,src}`: hardware/system abstraction only. - `components/domain/{include,internal,src}`: business-domain services. - `components/control_plane/{include,internal,src}`: lifecycle, policy, health, retry/backoff orchestration. - `components/app_composition/{include,internal,src}`: composition boundary; `app_main` only wires modules. - `dependency_whitelist.md`: approved exceptions for unavoidable lateral dependencies. - `components/domain/third_party/`, `components/domain/assets/fonts/`, `tools/`: vendored code, embedded assets, utility scripts. - `build/`: generated artifacts only (ignored). ## Mandatory Architecture Constraints 1. Dependencies are one-way only: `app_composition -> control_plane -> domain -> platform`. 2. Lateral direct dependencies are forbidden unless listed in `dependency_whitelist.md`. 3. Cross-domain communication must use events or Port interfaces; never include another domain's `internal/*.h`. 4. Each component keeps exactly one public facade header in `include/`; private headers stay in `internal/` via `PRIV_INCLUDE_DIRS`. - Long-term canonical facade headers in this repo: - `platform/include/platform.h` - `domain/include/domain.h` - `control_plane/include/control_plane.h` - `app_composition/include/app_composition.h` 5. Upper layers may include only immediate downstream public facade headers; leapfrog includes across multiple layers are forbidden. 6. Cross-cutting contracts must have a single declared owner layer and one public declaration point; duplicated declarations across layers are forbidden. 7. Runtime state must have a single source of truth (SSOT); orchestration layers should query/subscribe rather than duplicate lower-layer lifecycle or readiness state. 8. Blocking APIs must define timeout and idempotent semantics (no destructive background continuation after caller timeout). ## Build, Flash, and Validation Activate ESP-IDF v5.5.2 before running any `idf.py` command: ```bash export PATH=/opt/homebrew/bin:$PATH export IDF_PATH=/Users/moyyang/esp/v5.5.2/esp-idf source $IDF_PATH/export.sh ``` - `idf.py set-target esp32s3`: one-time target setup. - `idf.py build`: compile and validate. - `idf.py -p flash monitor`: flash and open serial monitor (`Ctrl+]` to exit). - `idf.py menuconfig`: adjust project options. - `idf.py fullclean && idf.py build`: clear stale artifacts. ## Coding Style & Naming Conventions - Use 4-space indentation and keep braces/function style consistent with existing `components/*/*.c`. - Prefer `lower_snake_case` for functions and variables; use module-prefixed public APIs. - Use `UPPER_SNAKE_CASE` for macros/constants (`CMD_SEND_DATA`, `WIFI_CONNECTED_BIT`). - Prefix file-local statics with `s_` (for example `s_server`, `s_jobs`) and keep per-file `TAG` logging constants. ## Testing Guidelines There is no dedicated unit-test directory currently. Minimum validation: - Build check: `idf.py build`. - Device smoke test after flash: `/v1/health`, printer connect/disconnect, and one print flow (text or image) via `curl`. - For Control Plane or REST changes, include one request/response or lifecycle scenario in PR notes. ## Commit & Pull Request Guidelines Use a clear conventional format: - Commit style: `feat(rest): add label offset endpoint`, `fix(wifi): handle STA timeout`. - Keep commits focused and atomic by layer/module (`platform`, `domain`, `control_plane`, `app_composition`). - PRs include purpose, affected layer(s), whitelist changes (if any), config changes, and validation evidence. ## Security & Configuration Tips - Never hardcode credentials or API keys in source files; configure through `menuconfig`. - Do not commit local `sdkconfig` variants, serial-port-specific commands, or generated `build/` artifacts.