73 lines
5.2 KiB
Markdown
73 lines
5.2 KiB
Markdown
# 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 <PORT> encrypted-app-flash
|
|
idf.py -p <PORT> 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 <PORT> 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 <PORT> encrypted-app-flash`, then `idf.py -p <PORT> 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 <DEVICE_IP>`.
|
|
- 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.
|