Files
lucky-cat/docs/architecture-and-flow-mermaid.md
T

329 lines
10 KiB
Markdown

# Architecture And Flow Diagrams
This document captures the current project architecture and major runtime flows
in Mermaid format. The diagrams reflect the implementation in the repository,
not older planning notes.
## Layered Architecture
```mermaid
flowchart TB
Main["main/app_main"]
App["app_composition\nstartup sequencing and wiring"]
CP["control_plane\npolicy, lifecycle, workers, retry/backoff"]
Domain["domain\nbusiness contracts, adapters, semantic mapping"]
Platform["platform\nhardware, transport, storage, display, audio"]
HW["ESP32-S3 hardware\nLCD, audio codec, GPIO, Wi-Fi, flash"]
Main --> App
App --> CP
CP --> Domain
Domain --> Platform
Platform --> HW
```
## Component Responsibility Map
```mermaid
flowchart LR
subgraph AppComposition["app_composition"]
Boot["Plan A boot sequence"]
Wire["Runtime wiring"]
end
subgraph ControlPlane["control_plane"]
Connectivity["Connectivity bootstrap and Wi-Fi policy"]
Workers["Runtime worker ownership"]
Events["System event dispatch"]
MultimodalPolicy["Multimodal session policy"]
Fortune["Daily fortune policy"]
RemoteLog["Remote log service"]
FactoryCli["Factory CLI diagnostics"]
end
subgraph Domain["domain"]
ExpressionMap["LCD expression semantic mapping"]
RuntimeAdapters["Runtime facade adapters"]
Direction["Direction and calibration model"]
FortuneDomain["Birth profile and fortune contracts"]
UserConfig["LAN user config routes"]
end
subgraph Platform["platform"]
LCD["ST7789 direct LCD backend"]
Audio["ES8311 audio pipeline"]
Network["Wi-Fi, BLE provisioning, HTTP, WebSocket"]
Storage["NVS, LittleFS, LogFS"]
GPIO["GPIO, stepper, console UART"]
end
Boot --> Connectivity
Boot --> Workers
Wire --> Workers
Connectivity --> RuntimeAdapters
Workers --> Events
Workers --> RemoteLog
MultimodalPolicy --> RuntimeAdapters
Fortune --> FortuneDomain
Events --> ExpressionMap
FactoryCli --> RemoteLog
RuntimeAdapters --> LCD
RuntimeAdapters --> Audio
RuntimeAdapters --> Network
RuntimeAdapters --> Storage
RuntimeAdapters --> GPIO
```
## Current Boot Sequence
```mermaid
sequenceDiagram
participant Main as app_main
participant App as app_composition
participant CP as control_plane
participant Domain as domain
participant Platform as platform
Main->>App: app_composition_start_default_runtime()
App->>CP: control_plane_prepare_runtime_storage()
CP->>Domain: prepare storage through runtime adapters
Domain->>Platform: NVS / storage initialization
App->>CP: control_plane_play_boot_sound(timeout)
CP->>Domain: domain_runtime_multimodal_audio_init()
Domain->>Platform: ES8311 / I2S / I2C audio init
CP->>Domain: domain_runtime_behavior_play_prompt_file()
Domain->>Platform: play prompt file
App->>CP: control_plane_init_lcd_device()
CP->>Domain: domain_runtime_init_lcd_device()
Domain->>Platform: LCD GPIO/SPI/ST7789 init
App->>CP: control_plane_start_lcd_render_worker()
CP->>CP: create cp_lcd_render task
CP->>Domain: domain_runtime_start_lcd_render_loop()
Domain->>Platform: lcd_direct_start_render_loop()
App->>CP: control_plane_init()
CP->>Domain: platform/domain runtime initialization
Domain->>Platform: stepper, storage, behavior adapters
App->>CP: control_plane_request_boot_expression()
CP->>Domain: request DOMAIN_EXPRESSION_IDLE
Domain->>Platform: queue LCD idle asset sequence
opt boot turntable calibration enabled
App->>CP: control_plane_calibrate()
CP->>Domain: direction calibration policy
Domain->>Platform: stepper + calibration switch
end
App->>CP: control_plane_bootstrap_connectivity()
CP->>Domain: Wi-Fi init / STA connect / BLE provisioning fallback
Domain->>Platform: Wi-Fi and provisioning primitives
App->>CP: control_plane_start_runtime_workers()
CP->>CP: start model, websocket wait, LCD, Wi-Fi state, events, keys, remote log, fortune
```
## Runtime Worker Topology
```mermaid
flowchart TB
Start["control_plane_start_runtime_workers()"]
Start --> ModelQueue["ensure model command queue"]
Start --> ModelTask["cp_model_cmd"]
Start --> WsWait["WebSocket wait task"]
Start --> LcdTask["cp_lcd_render"]
Start --> WifiTask["cp_wifi_state"]
Start --> EventTask["cp_system_event"]
Start --> KeyTask["cp_key_input"]
Start --> RemoteLogTask["cp_remote_log"]
Start --> FortuneTask["cp_fortune\nif FORTUNE_ENABLE"]
KeyTask --> EventTask
EventTask --> LcdTask
WsWait --> Multimodal["multimodal client/runtime"]
Multimodal --> ModelTask
Multimodal --> Audio["audio capture/playback"]
WifiTask --> LcdTask
RemoteLogTask --> LogServer["remote log server"]
FortuneTask --> FortuneApi["daily fortune API"]
```
## Connectivity Bootstrap Flow
```mermaid
flowchart TD
Start["control_plane_bootstrap_connectivity"]
InitWiFi["domain_runtime_network_wifi_init(seed credentials)"]
HasCreds{"saved Wi-Fi credentials?"}
StaConnect["connect STA with feedback"]
StaOk{"STA connected?"}
KeepCreds{"error keeps credentials?"}
ClearCreds["clear saved Wi-Fi credentials"]
ResolvePop["resolve provisioning PoP\nserial number preferred"]
HasPop{"PoP available?"}
BleProv["start BLE provisioning"]
Done["return ESP_OK"]
Error["return error"]
Start --> InitWiFi --> HasCreds
HasCreds -- yes --> StaConnect --> StaOk
StaOk -- yes --> Done
StaOk -- no --> KeepCreds
KeepCreds -- yes --> Done
KeepCreds -- no --> ClearCreds --> ResolvePop
HasCreds -- no --> ResolvePop
ResolvePop --> HasPop
HasPop -- yes --> BleProv --> Done
HasPop -- no --> Error
```
## LCD Expression Flow
```mermaid
flowchart LR
CP["control_plane policy/event"]
DomainReq["domain_runtime_request_expression()"]
Resolve["domain_resolve_expression_platform_request()"]
Catalog["domain expression catalog\nIDLE, WIFI_DISCONNECTED,\nSERVER_ERROR, MUYU, CHOUQIAN, WUXING"]
PlatformReq["platform_lcd_request_presentation()"]
Pending["lcd_direct pending request"]
Render["cp_lcd_render loop"]
Draw["draw RLE asset frame\nfrom /littlefs/lcd"]
Panel["ST7789 panel"]
CP --> DomainReq --> Resolve --> Catalog --> PlatformReq --> Pending --> Render --> Draw --> Panel
Draw --> Delay["vTaskDelay(frame_ms)"]
Delay --> Render
```
## Key And Local Event Flow
```mermaid
flowchart TD
GPIO["GPIO edge interrupt\nPTT GPIO15 / SW2 GPIO45"]
IsrQueue["key IRQ queue"]
KeyTask["cp_key_input\ndebounce and click state machine"]
SystemQueue["system event queue"]
EventTask["cp_system_event"]
PttState["PTT active state"]
Chouqian["SW2 short press\nDOMAIN_EXPRESSION_CHOUQIAN"]
Wuxing["SW2 double click\nDOMAIN_EXPRESSION_WUXING"]
Muyu["PTT double click\nDOMAIN_EXPRESSION_MUYU"]
GPIO --> IsrQueue --> KeyTask --> SystemQueue --> EventTask
EventTask --> PttState
EventTask --> Chouqian
EventTask --> Wuxing
EventTask --> Muyu
```
## Multimodal Runtime Flow
```mermaid
sequenceDiagram
participant CP as control_plane
participant Domain as domain
participant Platform as platform
participant WS as WebSocket server
participant Audio as ES8311 audio path
participant LCD as LCD expression
CP->>Domain: prepare multimodal start
CP->>Domain: register event callback
CP->>Domain: register downstream audio callback
CP->>CP: start multimodal watchdog task
CP->>Domain: control_plane_multimodal_start()
Domain->>Platform: open WebSocket transport
Platform->>WS: connect and send Start directive
WS-->>Platform: connected / task events
Platform-->>Domain: multimodal events
Domain-->>CP: event callback
WS-->>Platform: downstream audio binary
Platform-->>Domain: downstream audio callback
Domain-->>CP: control_plane_downstream_audio_bridge()
CP->>Audio: play downstream audio
alt transport/task/output error while STA connected
CP->>LCD: request DOMAIN_EXPRESSION_SERVER_ERROR
end
alt server responding starts
CP->>Audio: stop uplink if running
end
```
## Remote Logging Flow
```mermaid
flowchart TD
EspLog["ESP_LOGx / printf log"]
Hook["esp_log_set_vprintf hook"]
Filter["filter by CONFIG_TQ_REMOTE_LOG_MIN_LEVEL"]
RamQueue["RAM queue\nCONFIG_TQ_REMOTE_LOG_QUEUE_LEN"]
FlushTimer["periodic flush\nCONFIG_TQ_REMOTE_LOG_FLUSH_INTERVAL_MS"]
LogFS["/logfs/remote_logs\nLittleFS persistent queue"]
StaReady{"STA connected\nand realtime path idle?"}
Upload["HTTP POST JSON batch\nCONFIG_TQ_REMOTE_LOG_ENDPOINT"]
Server["remote_log_receiver.py\n/opt/logTools/logs"]
Backoff["exponential retry backoff"]
DropOld["trim old files\nCONFIG_TQ_REMOTE_LOG_MAX_FILES"]
CoreDump["detect flash coredump\nupload metadata report"]
EspLog --> Hook --> Filter --> RamQueue
RamQueue --> FlushTimer --> LogFS --> DropOld
LogFS --> StaReady
CoreDump --> StaReady
StaReady -- yes --> Upload --> Server
StaReady -- no --> Backoff --> StaReady
Upload -- fail --> Backoff
Upload -- success --> Delete["delete uploaded local file"]
```
## Daily Fortune Flow
```mermaid
flowchart TD
Task["cp_fortune task"]
WaitTime["wait for local time / next midnight / refresh request"]
WaitNetwork["wait for STA and multimodal readiness"]
Date["resolve local date"]
Fetch["control_plane_refresh_daily_fortune(date)"]
DomainFortune["domain fortune APIs\nbirth profile + fortune result"]
Http["HTTPS fortune API"]
Persist["persist fortune result"]
Notify["notify observers / UI configuration server"]
Retry["retry delay on failure"]
Task --> WaitTime --> WaitNetwork --> Date --> Fetch
Fetch --> DomainFortune --> Http
Http -- success --> Persist --> Notify --> WaitTime
Http -- failure --> Retry --> WaitTime
```
## Factory CLI Diagnostics Flow
```mermaid
flowchart LR
UART["UART0 serial input"]
CLI["factory CLI parser"]
Identity["identity / auth commands"]
LogStatus["log status"]
LogFlush["log flush"]
LogClear["log clear"]
RemoteLog["control_plane_remote_log_*"]
UARTOut["UART0 JSON/OK/ERROR output"]
UART --> CLI
CLI --> Identity --> UARTOut
CLI --> LogStatus --> RemoteLog --> UARTOut
CLI --> LogFlush --> RemoteLog --> UARTOut
CLI --> LogClear --> RemoteLog --> UARTOut
```