public CloudBackend(Workspace workspace, IInfrastructureEnvironment environment)
        {
            System = workspace.Model.AddSoftwareSystem(
                Location.Internal,
                "Azure IoT system",
                "Azure cloud based backend for processing data created on sensors / devices");

            SecretStorage       = new SecretStorage(this, environment);
            CloudGateway        = new CloudGateway(this, environment);
            DeviceProvisioning  = new DeviceProvisioning(this, CloudGateway, environment);
            TelemetryStorage    = new TelemetryStorage(this, environment);
            ApplicationInsights = new ApplicationInsights(this, environment);
            MasterDataStorage   = new MasterDataStorage(this, new SqlServer(environment), environment);
            SanitizedMessages   = new SanitizedMessages(this, new EventHubNamespace(environment), environment);
            Ingress             = new Ingress(this, CloudGateway, TelemetryStorage, MasterDataStorage, SanitizedMessages, ApplicationInsights, environment);
            StreamAnalytics     = new StreamAnalytics(this, SanitizedMessages, TelemetryStorage, environment);
            RestApi             = new RestApi(this, TelemetryStorage, MasterDataStorage, ApplicationInsights, environment);
            UserInterface       = new UserInterface(this, RestApi, environment);

            Device = workspace.Model.AddSoftwareSystem(Location.External, "Device", "Sends data into the cloud");
            Device.Uses(CloudGateway, "Send telemetry data and failure events", "MQTT");
            Device.Uses(DeviceProvisioning, "Provision device", "HTTPS");

            User = workspace.Model.AddPerson("User", "Person using the system to view data and take action on it");
            User.Uses(UserInterface, "View devices and their raw and aggregated data");

            StoreSecretsInKeyVault();
        }
        public Ingress(CloudBackend cloudBackend, CloudGateway hub,
                       TelemetryStorage telemetryStorage,
                       MasterDataStorage masterDataStorage,
                       SanitizedMessages sanitizedMessages,
                       ApplicationInsights applicationInsights,
                       IInfrastructureEnvironment environment)
        {
            Container = cloudBackend.System.AddContainer(
                name: "Ingress",
                description: "Receives incoming data from the cloud gateway and saves it into master data and telemetry data storages",
                technology: "Azure Function");

            Infrastructure = new FunctionAppService
            {
                Name = "ref-ingress-" + environment.Name
            };

            Uses(hub)
            .Over <IoTHubSDK>()
            .InOrderTo("Subscribes to incoming messages");

            Uses(sanitizedMessages)
            .Over <EventHubSDK>()
            .InOrderTo("Publish sanitized messages");

            Uses(telemetryStorage)
            .Over(telemetryStorage.Infrastructure.TableEndpoint)
            .InOrderTo("Persist telemetry data");

            Uses(masterDataStorage).InOrderTo("Persist master data");

            Uses(applicationInsights).InOrderTo("Log metrics");
        }
        public StreamAnalytics(CloudBackend cloudBackend, SanitizedMessages sanitizedMessages, TelemetryStorage telemetryStorage, IInfrastructureEnvironment environment)
        {
            Container = cloudBackend.System.AddContainer(
                name: "Stream Analytics",
                description: "Analyzes the incoming event stream for anomalies",
                technology: "Azure Stream Analytics");

            Infrastructure = new Structurizr.InfrastructureAsCode.Azure.Model.StreamAnalytics
            {
                Name = "ref-sa-" + environment.Name
            };

            Uses(sanitizedMessages).Over(Infrastructure.EventHubInput("messages", sanitizedMessages.Infrastructure)).InOrderTo("Process incoming events");
            Uses(telemetryStorage).Over(Infrastructure.TableStorageOutput("out", telemetryStorage.Infrastructure, "aggregated", "partitionKey", "rowKey")).InOrderTo("Store aggregated data");

            Infrastructure.TransformationQuery = "SELECT\r\n    *\r\nINTO\r\n    out\r\nFROM\r\n    iothub";
        }