github.com/simpleiot/simpleiot@v0.18.3/docs/ref/architecture-app.md (about) 1 # Application Architecture 2 3 **Contents** 4 5 <!-- toc --> 6 7 The Simple IoT Go application is a single binary with embedded assets. The 8 database and NATS server are also embedded by default for easy deployment. There 9 are five main parts to a Simple IoT application: 10 11 1. **NATS Message Bus**: all data goes through this making it very easy to 12 observe the system. 13 2. **Store**: persists the data for the system, merges incoming data, maintains 14 node hash values for synchronization, rules engine, etc. (the rules engine 15 may eventually move to a client) 16 3. **Clients**: interact with other devices/systems such as Modbus, 1-wire, etc. 17 This is where most of the functionality in a SIOT system lives, and where you 18 add your custom functionality. Clients can exist inside the Simple IoT 19 application or as external processes written in any language that connect via 20 NATS. Clients are represented by a node (and optionally child nodes) in the 21 SIOT store. When a node is updated, its respective clients are updated with 22 the new information. Likewise, when a client has new information, it sends 23 that out to be stored and used by other nodes/instances as needed. 24 4. **HTTP API**: provides a way for HTTP clients to interact with the system. 25 5. **Web UI**: Provides a user interface for users to interact with the system. 26 Currently it uses the HTTP API, but will eventually connect directly to NATS. 27 28 The simplicity of this architecture makes it easy to extend with new 29 functionality by writing a new client. Following the constraints of 30 [storing data](data.md) as nodes and points ensures all data is visible and 31 readable by other clients, as well as being automatically synchronized to 32 upstream instances. 33 34  35 36 ## Application Lifecycle 37 38 Simple IoT uses the 39 [`Run()/Stop()`](https://community.tmpdir.org/t/structuring-go-apps-for-testing-and-lifecycle-management-the-start-stop-pattern/550) 40 pattern for any long running processes. With any long running process, it is 41 important to not only Start it, but also to be able to cleanly Stop it. This is 42 important for testing, but is also good practice. Nothing runs forever so we 43 should never operate under this illusion. The 44 [oklog/run](https://github.com/oklog/run) packaged is used to start and shutdown 45 these processes concurrently. Dependencies between processes should be minimized 46 where possible through retries. If there are hard dependencies, these can be 47 managed with `WaitStart()/WaitStop()` functions. See 48 [`server.go`](https://github.com/simpleiot/simpleiot/blob/master/server/server.go) 49 for an example. 50 51 NATS lends itself very well to a decoupled application architecture because the 52 NATS clients will buffer messages for some time until the server is available. 53 Thus we can start all the processes that use a NATS client without waiting for 54 the server to be available first. 55 56 Long term, a NATS API that indicates the status of various parts (rules engine, 57 etc.) of the system would be beneficial. If there are dependencies between 58 processes, this can be managed inside the process instead of in the code that 59 starts/stops the processes. 60 61 ## NATS Integration 62 63 The [NATS API](api.md#nats) details the NATS subjects used by the system. 64 65 ### Echo concerns 66 67 Any time you potentially have two sources modifying the same resource (a node), 68 you need to be concerned with echo'd messages. This is a common occurance in 69 Simple IoT. Because another resource may modify a node, typically a client needs 70 to subscribe to the node messages as well. This means when it sends a message, 71 it will typically be echo'd back. See the 72 [client documentation](client.md#message-echo) for ideas on how to handle the 73 echo problem. 74 75 The 76 [server.NewServer](https://pkg.go.dev/github.com/simpleiot/simpleiot/server#NewServer) 77 function returns a nats connection. This connection is used throughout the 78 application and does not have the NoEcho option set. 79 80 ## User Interface 81 82 Currently, the User Interface is implemented using a Single Page Architecture 83 (SPA) Web Application. This keeps the backend and frontend implementations 84 mostly independent. See [User Interface](../user/ui.md) and 85 [Frontend](frontend.md) for more information. 86 87 There are many web architectures to chose from and web technology is advancing 88 at a rapid pace. SPAs are not in vogue right now and more complex architectures 89 are promoted such as Next.js, SveltKit, Deno Fresh, etc. Concerns with SPAs 90 include large initial load and stability (if frontend code crashes, everything 91 quits working). These concerns are valid if using Javascript, but with Elm these 92 concerns are minimal as Elm compiles to very small bundles, and run time 93 exceptions are extremely rare. This allows us to use a simple web architecture 94 with minimal coupling to the backend and minimal build complexity. And it will 95 be a long time until we write enough Elm code that bundle size matters. 96 97 A decoupled SPA UI architecture is also very natural in Simple IoT as IoT 98 systems are inherently distributed. The frontend is just another client, much 99 the same as a separate machine learning process, a downstream instance, a 100 scripting process, etc.