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  ![application architecture](images/arch-app.png)
    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.