# 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.3 before running any `idf.py` command: ```bash export PATH=/opt/homebrew/bin:$PATH export IDF_PATH=/Users/moyyang/.espressif/v5.5.3/esp-idf source $IDF_PATH/export.sh ``` - `idf.py set-target esp32s3`: one-time target setup. - `idf.py build`: compile and validate; generated flash maps and binaries stay under `build/`. - Secured/provisioned boards with Secure Boot and Flash Encryption enabled must use encrypted app-only flashing: ```bash idf.py -p encrypted-app-flash idf.py -p monitor ``` This updates only the encrypted app partition at `0x30000` via `build/encrypted_app-flash_args`; it must not rewrite the bootloader, partition table, or OTA data on secured boards. - Do not use `idf.py flash` on secured boards. It attempts to write low flash regions such as the bootloader at `0x0`, which Secure Boot blocks to protect the device. - Do not use plain `idf.py app-flash` on Flash Encryption boards. It writes a plaintext app image and can boot-fail with invalid app magic or no bootable app partition. - `idf.py -p flash monitor` is only for fresh development boards without Secure Boot/Flash Encryption, or for initial factory provisioning handled by `tools/esptool-factory`. - `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`. - Secured-board flash check: `idf.py -p encrypted-app-flash`, then `idf.py -p monitor`. - Monitor boot logs should show Secure Boot signature verification, app ESP-IDF version, Wi-Fi connection/IP when configured, printer protocol initialization, `MIC_KEY` readiness, control-plane lifecycle start, and `TQ printer runtime started`. - If STA connects, confirm host reachability with `ping `. - For unprovisioned devices, validate the SoftAP provisioning flow at `http://192.168.4.1` and the provisioning endpoints `/`, `/scan`, and `/provision`. - Physical smoke tests should cover `MIC_KEY` press/release, POWER key long press, and one normal product print flow when the required printer hardware/workflow is available. - For Control Plane or protocol changes, include one lifecycle or request/response 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.