@startuml SoftwareArchitecture skinparam componentStyle rectangle skinparam defaultTextAlignment center skinparam component { BackgroundColor<> LightYellow BackgroundColor<> LightGray BackgroundColor<> LightCyan BackgroundColor<> #E8E8F8 BorderStyle<> dashed BackgroundColor<> #EEEEEE BorderStyle<> dashed } title Leahi Real-time CDT — Component Architecture node "Leahi Device" { node "CloudConnect (process)" { component "CloudConnectController" as CC component "Can::CanInterface" as CAN component "MqttClient\n(QMqttClient, TLS/mTLS)" as MQTT component "MessageSpool + SpoolDrain\n(durability on publish failure)" as SPOOL <> } node "Comms (lib)" { component "CloudConnectServer\n(local-socket server)" as RS <> component "Can::MessageDispatcher\n(per-CAN-id reassembly)" as MDISP component "Can::MessageBuilder\n(frame ↔ message)" as MB component "CloudConnectFrame\n(framing + CRC)" as AM <> } node "MsgUtils (lib)" { component "LeahiMsgDefs\n(generated C++ + protobuf stubs)" as MD <> } interface "CAN Bus\n(SocketCAN)" as CANBUS interface "Unix Domain Socket\n(/tmp/cloudconnect.sock)" as APPUDS <> } node "Test tools" { component "CANDumpPlayer\n(replays candump log → SocketCAN)" as CDP <> component "DCSsim\n(local MQTT broker, TLS/mTLS)" as DCS <> } cloud "AWS Cloud" as CLOUD <> { component "AWS IoT Core\n(MQTT broker, port 8883)" as IOTCORE <> component "Amazon S3\n(log bundles)" as S3 <> } node "Build-time (scripts)" { component "MsgUtils Python\n(msgutils)" as PYUTILS <> component "Jinja2 Templates\n(MsgDefs_*.jinja, CanRoutingIni.jinja)" as JINJA <> component "protoc" as PROTOC <> component "LeahiMsgDefs.proto\n(generated)" as PROTO <> component "LeahiMsgDefs.h/.cpp\n(generated)" as GENCPP <> component "Protobuf stubs\n(.pb.h/.pb.cc)" as PBSTUBS <> component "LeahiCanRouting.ini\n(generated, hand-edits preserved)" as CANINI <> } ' --- runtime data flow --- CDP --> CANBUS : writeFrame (replay) CANBUS --> CAN CAN --> CC : didFrameReceive CC --> MDISP : onFrameReceive(canId, payload) MDISP --> MB : buildMessage() MB --> MDISP : Can::Message MDISP --> CC : didActionReceive(Can::Message) CC --> MD : canMessageToProtobufByteArray() MD --> CC : protobuf bytes CC --> MQTT : publish(topic, payload, qos = 1) MQTT --> IOTCORE : PUBLISH / SUBSCRIBE (mTLS 8883) IOTCORE --> MQTT : PUBACK + echo PUBLISH MQTT --> DCS : same client, broker swapped\nvia Cloud/ServerAddress in the INI ' --- present but idle --- CC ..> RS : listen() only; send() has no call site RS ..> AM : build() RS ..> APPUDS : (no traffic) ' --- planned --- CC ..> SPOOL : spool on publish failure (planned) SPOOL ..> MQTT : replay on reconnect (planned) CC ..> S3 : log bundle upload, HTTPS (planned) ' --- build-time flow --- PYUTILS --> JINJA : renders JINJA --> PROTO : generates JINJA --> GENCPP : generates JINJA --> CANINI : generates PROTO --> PROTOC : input PROTOC --> PBSTUBS : generates GENCPP ..> MD : compiled into PBSTUBS ..> MD : compiled into CANINI ..> CC : loadCanRouting() at startup @enduml