static void Main(string[] args) { // a Structurizr workspace is the wrapper for a software architecture model, views and documentation Workspace workspace = new Workspace("Supply Chain Planning", "Model of software systems used by Supply Chain Planning."); #region Model Model model = workspace.Model; #region Users Person scpUser = model.AddPerson(Location.Internal, "SCP User", "Modeller, Data Analyst or other users."); Person adminUser = model.AddPerson(Location.Internal, "Administrator", "SCP Administrators."); Person externalUser = model.AddPerson(Location.External, "External User", "Other users outside of SCP"); #endregion #region Software systems SoftwareSystem amsSoftwareSystem = model.AddSoftwareSystem( Location.Internal, "AMS", "Assumption Management System\n\nStores and allows user to manage model versions and model inputs (assumptions)"); SoftwareSystem runsControllerSoftwareSystem = model.AddSoftwareSystem( Location.Internal, "Runs Controller", "Executes model submissions and post-processing tasks and allows user to monitor and manage submissions"); SoftwareSystem modelOutputsStorageSoftwareSystem = model.AddSoftwareSystem( Location.Internal, "Model Outputs Storage", "Databases and shared file system that stores outputs of model runs"); SoftwareSystem hangfireSoftwareSystem = model.AddSoftwareSystem( Location.Internal, "Hangfire", "Recurring and background jobs processing\n\n" + "Executes long-running background tasks (like submission creation in Runs Controller) " + "and recurring tasks (like model outputs registration and retention policy)"); SoftwareSystem analyticalDataStoreSoftwareSystem = model.AddSoftwareSystem( Location.Internal, "Analytical Data Store", "This includes all databases and other data stores that can be used as data sources for Spotfire or AMS"); SoftwareSystem spotfireSoftwareSystem = model.AddSoftwareSystem( Location.Internal, "Spotfire", "TIBCO Spotfire dashboards visualize data (model outputs and other available data)"); SoftwareSystem externalDataSourcesSoftwareSystem = model.AddSoftwareSystem( Location.External, "External Data Source", "All other source of data external to SCP from which import data"); SoftwareSystem controlFrameworkSoftwareSystem = model.AddSoftwareSystem( Location.Internal, "Control Framework", "Collection of configurable SSIS packages running as SQL jobs perfroming data-centric background and reccuring tasks"); SoftwareSystem p2cModelDevelopmentSoftwareSystem = model.AddSoftwareSystem( Location.Internal, "P2C Model Development", "Toolset for development and testing of P2C model"); #endregion #region Containers #region AMS Containers var amsLightswitchWebApplicationContainer = amsSoftwareSystem.AddContainer("LightSwitch Web Application", "Main navigation, browse and edit screens, shell for some custom JavaScript controls", "LightSwitch HTML Client (SPA), Knockout JS"); var amsAspNetMvcWebApplicationContainer = amsSoftwareSystem.AddContainer("MVC Web Application", "Dashboard, Type system versions, State Validation, Key Inputs, State Merging, Submission Progress", "ASP.NET MVC, Kendo UI, Knockout JS"); var amsApiApplicationContainer = amsSoftwareSystem.AddContainer("AMS API Application", "AMS back-end", "ASP.NET Web API, Entity Framework, LightSwitch Server"); var amsDatabaseContainer = amsSoftwareSystem.AddContainer("AMS Database", "Stores project hierarchy, assumptions, type system definition and other data managed by AMS", "MS SQL Server 2016"); var amsCacheContainer = amsSoftwareSystem.AddContainer("AMS Distributed Cache", "In-memory cache for frequently accessed and hard-to-read data; also used for messaging between Hangfire and AMS", "Redis, Windows Service"); #endregion #region Hangfire Containers var hangfireDashboardContainer = hangfireSoftwareSystem.AddContainer("Hangfire Dashboard", "User interface for Hangfire monitoring and management", "Web Application"); var hangfireServiceContainer = hangfireSoftwareSystem.AddContainer("Hangfire Windows Service", "Executes background tasks and recurrent jobs", ".Net Framework Windows Application, Shares code base with AMS API Application"); var hangfireDatabaseContainer = hangfireSoftwareSystem.AddContainer("Hangfire Database", "Stores hangfire jobs, results and other Hangfire data", "MS SQL Server 2016"); var hangfireMessageQueuesContainer = hangfireSoftwareSystem.AddContainer("Message Queues", "Queues for jobs to be executed by Hangfire", "Microsoft Message Queues"); #endregion #region Control Framework Containers var controlFrameworkDatabaseContainer = controlFrameworkSoftwareSystem.AddContainer("ControlFrameworkDB", "Control Framework database", "MS SQL Server 2016 database"); //var controlFrameworkJobs = #endregion #region Runs Controller Containers var rcDistributorContainer = runsControllerSoftwareSystem.AddContainer("Runs Controller Distributor", "Maintains package queue; distributes packages to clients; implements APIs for submission creation and portal", ".Net, C#, Windows Service"); var rcClientContainer = runsControllerSoftwareSystem.AddContainer("Runs Controller Client", "Executes packages", ".Net, C#, Windows Service"); var rcDatabaseContainer = runsControllerSoftwareSystem.AddContainer("Runs Controller Database", "Stores Runs Controller data", "SQL Server 2016 database"); var rcReportingAPIServiceContainer = runsControllerSoftwareSystem.AddContainer("RunsController Reporting API Service", "Provides APIs for reporting on Runs Controller data", "ASP.NET Core, Windows Service"); var rcCommandLineToolContainer = runsControllerSoftwareSystem.AddContainer("Runs Controller Command Line Tool", "Command Line interface to Runs Controller Distributor; allows for creation of Arena packages", ".Net, C#, console application"); var rcSubmissionToolContainer = runsControllerSoftwareSystem.AddContainer("Runs Controller Submission Tool", "The tools for creation of Arena submissions", "C# Windows Forms application, ClickOnce deployment"); var rcNotificationClientContainer = runsControllerSoftwareSystem.AddContainer("Runs Controller Notification Client", "Monitors user's submissions and displays notification when submission is finished", "C# Windows Forms application"); var rcPortalContainer = runsControllerSoftwareSystem.AddContainer("Runs Controller Portal", "Runs Controller user interface", "ASP.NET MVC web application"); #endregion #region Analytical Data Store Containers var adsDatabaseContainer = analyticalDataStoreSoftwareSystem.AddContainer("AnalyticalDataStore", "ADS database", "MS SQL Server 2016 database"); var actualsTimeSeriesDatabaseContainer = analyticalDataStoreSoftwareSystem.AddContainer("Actuals_TimeSeries", "Actuals Time Series database", "MS SQL Server 2016 database"); var projectDatabaseContainer = analyticalDataStoreSoftwareSystem.AddContainer("Project", "Project database", "MS SQL Server 2016 database"); var sckbDatabaseContainer = analyticalDataStoreSoftwareSystem.AddContainer("SCKBDatabase", "SCKB database", "MS SQL Server 2016 database"); var sckbReportingDatabaseContainer = analyticalDataStoreSoftwareSystem.AddContainer("SCKBReportingDB", "SCKB Reporting database", "MS SQL Server 2016 database"); #endregion #region Model Outputs Storage Containers var modelOutputsFileSharesContainer = modelOutputsStorageSoftwareSystem.AddContainer("Model Outputs File Shares", "Store model output files and post-processed data", "File Share"); var modelOutputsKpiDatabaseContainer = modelOutputsStorageSoftwareSystem.AddContainer("ModelOutputs_KPI", "Model Outputs KPI database", "MS SQL Server 2016 database"); var modelOutputsTimeSeriesDatabaseContainer = modelOutputsStorageSoftwareSystem.AddContainer("ModelOutputs_TimeSeries", "Model Outputs Time Series database", "MS SQL Server 2016 database"); var modelOutputsProcessDatabaseContainer = modelOutputsStorageSoftwareSystem.AddContainer("ModelOutputsProcess", "Model Outputs Process database", "MS SQL Server 2016 database"); #endregion #region Deployment Nodes var amsWebServer = model.AddDeploymentNode("IORPER-WEB01", "AMS Web Server", "Windows Server 2012 R2"); amsWebServer.Add(hangfireServiceContainer); amsWebServer.Add(hangfireMessageQueuesContainer); amsWebServer.Add(amsCacheContainer); var amsIis = amsWebServer.AddDeploymentNode("IIS", "Internet Information Services", "IIS 8.5"); amsIis.Add(amsApiApplicationContainer); amsIis.Add(amsLightswitchWebApplicationContainer); amsIis.Add(amsAspNetMvcWebApplicationContainer); amsIis.Add(hangfireDashboardContainer); var clusterNode1 = model.AddDeploymentNode("IORPER-C02SQ01", "Node 1 of the failover cluster", "Windows Server 2012 R2"); var node1databaseServer = clusterNode1.AddDeploymentNode("SQ2014SCAP01", "Database Server for Analytical Data Store", "SQL Server 2016"); node1databaseServer.Add(adsDatabaseContainer); node1databaseServer.Add(controlFrameworkDatabaseContainer); node1databaseServer.Add(actualsTimeSeriesDatabaseContainer); node1databaseServer.Add(modelOutputsKpiDatabaseContainer); node1databaseServer.Add(modelOutputsTimeSeriesDatabaseContainer); node1databaseServer.Add(modelOutputsProcessDatabaseContainer); node1databaseServer.Add(projectDatabaseContainer); node1databaseServer.Add(sckbDatabaseContainer); node1databaseServer.Add(sckbReportingDatabaseContainer); var clusterNode2 = model.AddDeploymentNode("IORPER-C02SQ02", "Node 2 of the failover cluster", "Windows Server 2012 R2"); var node2databaseServer = clusterNode2.AddDeploymentNode("SQ2014SCAP02", "Database Server for operational databases", "SQL Server 2016"); var amsDatabase = node2databaseServer.AddDeploymentNode("AMS", "AMS database - the dbo schema contains AMS tables and vies, hangfire schema contains Hangfire tables", "SQL Server Database"); amsDatabase.Add(amsDatabaseContainer); amsDatabase.Add(hangfireDatabaseContainer); var runsControllerDistributorServer = model.AddDeploymentNode("IOPL-S0044", "Runs Controller Distributor Server (alias UnityServer)", "Windows Server 2008 R2"); runsControllerDistributorServer.Add(rcDistributorContainer); node2databaseServer.Add(rcDatabaseContainer); var gen8processingClients = model.AddDeploymentNode("Gen8 Runs Controller clients servers (Arena and AnyLogic)", "Gen8 Runs Controller client servers (16 processing slots)", "Windows Server 2012 R2", 31); var gen8postProcessingClients = model.AddDeploymentNode("Gen8 Runs Controller clients server (post-processing)", "Gen8 Runs Controller client servers (1 processing slot)", "Windows Server 2012 R2", 1); var gen9processingClients = model.AddDeploymentNode("Gen9 Runs Controller clients servers (Arena and AnyLogic)", "Gen8 Runs Controller client servers (24 processing slots)", "Windows Server 2012 R2", 24); var gen9postProcessingClients = model.AddDeploymentNode("Gen9 Runs Controller clients server (post-processing)", "Gen8 Runs Controller client servers (2 processing slot)", "Windows Server 2012 R2", 2); gen8processingClients.Add(rcClientContainer); gen8postProcessingClients.Add(rcClientContainer); gen9processingClients.Add(rcClientContainer); gen9postProcessingClients.Add(rcClientContainer); #endregion #endregion #region Relationships (what uses what) scpUser.Uses(amsSoftwareSystem, "Manages model versions, model inputs and creates submissions"); scpUser.Uses(amsLightswitchWebApplicationContainer, "Manages model versions, model inputs and creates submissions"); scpUser.Uses(amsAspNetMvcWebApplicationContainer, "Uses specialized AMS screens"); scpUser.Uses(runsControllerSoftwareSystem, "Monitors and manages submissions"); scpUser.Uses(spotfireSoftwareSystem, "Uses dashboards to visualize and analyze data"); adminUser.Uses(amsSoftwareSystem, "Manages system settings and other protected data"); adminUser.Uses(amsLightswitchWebApplicationContainer, "Manages system settings and other protected data"); adminUser.Uses(runsControllerSoftwareSystem, "Manages Runs Controller setting (e.g. which clients are active)"); adminUser.Uses(hangfireSoftwareSystem, "Manages Hangfire settings; can restart failed jobs etc."); adminUser.Uses(hangfireDashboardContainer, "Manages Hangfire settings; can restart failed jobs etc."); externalUser.Uses(spotfireSoftwareSystem, "Uses public dashboards or outputs produced by project teams using Spotfire"); amsSoftwareSystem.Uses(runsControllerSoftwareSystem, "Fetches submission status"); amsSoftwareSystem.Uses(hangfireSoftwareSystem, "Triggers submission creation in Runs Controller"); amsSoftwareSystem.Uses(analyticalDataStoreSoftwareSystem, "Imports data from analytical data store that are used as model inputs (e.g. actual supply chain data)"); amsSoftwareSystem.Uses(controlFrameworkSoftwareSystem, "Provides user interface for Control Framework configuration; references Control Framework messages as model inputs"); controlFrameworkSoftwareSystem.Uses(analyticalDataStoreSoftwareSystem, "Imports (into) and transforms data"); controlFrameworkSoftwareSystem.Uses(externalDataSourcesSoftwareSystem, "Imports data (from)"); controlFrameworkSoftwareSystem.Uses(modelOutputsStorageSoftwareSystem, "Loads data to models outputs databases"); runsControllerSoftwareSystem.Uses(modelOutputsStorageSoftwareSystem, "Generates model outputs"); hangfireSoftwareSystem.Uses(modelOutputsStorageSoftwareSystem, "Registers created model outputs, applies retention policy"); hangfireSoftwareSystem.Uses(runsControllerSoftwareSystem, "Creates model submissions and post-processing submissions"); analyticalDataStoreSoftwareSystem.Uses(amsSoftwareSystem, "Has read-only access to AMS data (project hierarchy, object model, reference data and objects)"); analyticalDataStoreSoftwareSystem.Uses(externalDataSourcesSoftwareSystem, "Imports data from external systems."); spotfireSoftwareSystem.Uses(modelOutputsStorageSoftwareSystem, "Visualizes model outputs"); spotfireSoftwareSystem.Uses(analyticalDataStoreSoftwareSystem, "Visualizes other available data"); spotfireSoftwareSystem.Uses(runsControllerSoftwareSystem, "Reads submission details for environment performance dashboard"); p2cModelDevelopmentSoftwareSystem.Uses(amsSoftwareSystem, "Exports model versions"); amsLightswitchWebApplicationContainer.Uses(amsApiApplicationContainer, "Uses", "JSON/HTTP"); amsAspNetMvcWebApplicationContainer.Uses(amsApiApplicationContainer, "Uses", "JSON/HTTP"); amsApiApplicationContainer.Uses(amsDatabaseContainer, "Reads from and writes to", "ADO.Net"); amsApiApplicationContainer.Uses(amsCacheContainer, "Reads from, writes to and invalidates data in", "StackExchange.Redis client"); amsApiApplicationContainer.Uses(amsCacheContainer, "Subscribes to notifications from Hangfire", "Redis Pub/Sub"); hangfireServiceContainer.Uses(hangfireMessageQueuesContainer, "Processes queued jobs"); hangfireServiceContainer.Uses(hangfireDatabaseContainer, "Persists jobs data"); hangfireServiceContainer.Uses(amsCacheContainer, "Reads from, writes to and invalidates in", "StackExchange.Redis client"); hangfireServiceContainer.Uses(amsCacheContainer, "Publishes notifications for AMS", "Redis Pub/Sub"); hangfireServiceContainer.Uses(amsDatabaseContainer, "Reads from and writes to", "ADO.Net"); hangfireServiceContainer.Uses(modelOutputsFileSharesContainer, "Registers created model output files"); hangfireServiceContainer.Uses(modelOutputsFileSharesContainer, "Removes old model output files"); hangfireServiceContainer.Uses(modelOutputsKpiDatabaseContainer, "Removes old model outputs"); hangfireServiceContainer.Uses(modelOutputsTimeSeriesDatabaseContainer, "Removes old model outputs"); hangfireDashboardContainer.Uses(hangfireServiceContainer, "Provides user interface for"); amsApiApplicationContainer.Uses(hangfireMessageQueuesContainer, "Enqueues and schedules jobs using"); var failoverRelationship = clusterNode2.Uses(clusterNode1, "Failover to", "Windows Server Failover Cluster"); var failoverRelationshipReverse = clusterNode1.Uses(clusterNode2, "Failover to", "Windows Server Failover Cluster"); rcDistributorContainer.Uses(rcDatabaseContainer, "Reads from and writes to", "ADO.Net"); rcClientContainer.Uses(rcDistributorContainer, "Requests packages to execute; send package reports and changes in package status", "WCF, http"); rcPortalContainer.Uses(rcDistributorContainer, "Reads data to display from and sends requests to manage data to", "WCF, http"); scpUser.Uses(rcPortalContainer, "Manages submissions and packages"); hangfireServiceContainer.Uses(rcDistributorContainer, "Creates AnyLogic packages and submissions, creates post-processing packages and submissions", "WCF, http"); hangfireServiceContainer.Uses(rcReportingAPIServiceContainer, "Reads submission details to be cached in AMS and displayed in AMS", "http"); spotfireSoftwareSystem.Uses(rcReportingAPIServiceContainer, "Reads submission details to be displayed on the environment performance dashboard", "http"); amsApiApplicationContainer.Uses(rcDistributorContainer, "Updates Customer and Project details", "WCF, http"); rcCommandLineToolContainer.Uses(rcDistributorContainer, "Creates Arena packages and submissions, updates customer and project", "WCF, http"); rcSubmissionToolContainer.Uses(rcCommandLineToolContainer, "Uses it to creates Arena packages and submissions an to update customer and project"); rcNotificationClientContainer.Uses(rcDistributorContainer, "Subscribes to user's submission changes", "WCF, http"); rcReportingAPIServiceContainer.Uses(rcDatabaseContainer, "Reads persisted submission data", "ADO.Net"); rcReportingAPIServiceContainer.Uses(rcDistributorContainer, "Reads queue details", "WCF, http"); scpUser.Uses(rcNotificationClientContainer, "Gets notified when his submission is finished"); scpUser.Uses(rcSubmissionToolContainer, "Creates Arena submissions using"); rcClientContainer.Uses(modelOutputsFileSharesContainer, "Generates output files in"); p2cModelDevelopmentSoftwareSystem.Uses(amsApiApplicationContainer, "Exports model versions to"); #endregion #endregion #region Views (diagrams) // define some views (the diagrams you would like to see) ViewSet views = workspace.Views; #region Enterprise context EnterpriseContextView enterpriseContextView = views.CreateEnterpriseContextView("EnterpriseContext", "Enterprise Context diagram."); enterpriseContextView.PaperSize = PaperSize.A4_Landscape; enterpriseContextView.AddAllSoftwareSystems(); enterpriseContextView.AddAllPeople(); #endregion #region AMS System Context SystemContextView amsSystemContextView = views.CreateSystemContextView( amsSoftwareSystem, "AMSSystemContext", "AMS System Context diagram."); amsSystemContextView.AddNearestNeighbours(amsSoftwareSystem); amsSystemContextView.AddNearestNeighbours(hangfireSoftwareSystem); #endregion #region Runs Controller System Context SystemContextView runsControllerSystemContextView = views.CreateSystemContextView( runsControllerSoftwareSystem, "RunsControllerSystemContext", "RunsController System Context diagram."); runsControllerSystemContextView.AddNearestNeighbours(runsControllerSoftwareSystem); #endregion #region AMS Container Diagram var amsContainerView = views.CreateContainerView(amsSoftwareSystem, "AMSContainerDiagram", "AMS container diagram"); amsContainerView.AddAllContainers(); amsContainerView.Add(scpUser); amsContainerView.Add(adminUser); amsContainerView.Add(hangfireServiceContainer); amsContainerView.Add(hangfireMessageQueuesContainer); amsContainerView.Add(hangfireServiceContainer); amsContainerView.Add(p2cModelDevelopmentSoftwareSystem); #endregion #region Runs Controller Container Diagram var runsControllerContainerView = views.CreateContainerView(runsControllerSoftwareSystem, "RCContainerDiagram", "Runs Controller container diagram"); runsControllerContainerView.AddAllContainers(); runsControllerContainerView.Add(scpUser); runsControllerContainerView.Add(hangfireServiceContainer); runsControllerContainerView.Add(amsApiApplicationContainer); runsControllerContainerView.Add(spotfireSoftwareSystem); runsControllerContainerView.Add(modelOutputsFileSharesContainer); #endregion #region Hangfire Container Diagram var hangfireContainerView = views.CreateContainerView(hangfireSoftwareSystem, "HangfireContainerDiagram", "Hangfire container diagram"); hangfireContainerView.AddAllContainers(); hangfireContainerView.Add(adminUser); hangfireContainerView.Add(amsCacheContainer); hangfireContainerView.Add(amsDatabaseContainer); hangfireContainerView.Add(amsApiApplicationContainer); #endregion #region AMS Deployment Diagram var amsDeploymentView = views.CreateDeploymentView("AMSDeploymentDiagram", "AMS Deployment Diagram"); amsDeploymentView.Add(amsWebServer); amsDeploymentView.Add(clusterNode2); amsDeploymentView.Add(clusterNode1); amsDeploymentView.Add(failoverRelationship); amsDeploymentView.Add(failoverRelationshipReverse); #endregion #region Runs Controller Deployment Diagram var runsControllerDeploymentView = views.CreateDeploymentView("RunsControllerDeploymentDiagram", "Runs Controller Deployment Diagram"); runsControllerDeploymentView.Add(runsControllerDistributorServer); runsControllerDeploymentView.Add(gen8processingClients); runsControllerDeploymentView.Add(gen8postProcessingClients); runsControllerDeploymentView.Add(gen9processingClients); runsControllerDeploymentView.Add(gen9postProcessingClients); runsControllerDeploymentView.Add(clusterNode2); runsControllerDeploymentView.Add(clusterNode2); runsControllerDeploymentView.Add(clusterNode1); runsControllerDeploymentView.Add(failoverRelationship); runsControllerDeploymentView.Add(failoverRelationshipReverse); #endregion #region Submission creation workflow var submissionCreationWorkflow = views.CreateDynamicView("SubmissionWorkflow", "Submission creation workflow"); submissionCreationWorkflow.Add(p2cModelDevelopmentSoftwareSystem, "Exports new model version to AMS", amsSoftwareSystem); submissionCreationWorkflow.Add(scpUser, "Defines project, scenario, case and input state", amsSoftwareSystem); submissionCreationWorkflow.Add(scpUser, "Initiates creation of a new submission", amsSoftwareSystem); submissionCreationWorkflow.Add(amsSoftwareSystem, "Creates Hangfire job to create submission in Runs Controller", hangfireSoftwareSystem); submissionCreationWorkflow.Add(hangfireSoftwareSystem, "Creates submission in Runs Controller", runsControllerSoftwareSystem); submissionCreationWorkflow.Add(amsSoftwareSystem, "Receives submission creation notification from Hangfire through Redis", hangfireSoftwareSystem); submissionCreationWorkflow.Add(scpUser, "Receives on-screen notification about created submission", amsSoftwareSystem); #endregion #region Submission execution and post-processing var submissionExecutionWorkflow = views.CreateDynamicView("SubmissionExecutionWorkflow", "Submission execution workflow"); submissionExecutionWorkflow.Add(runsControllerSoftwareSystem, "Finished submission packages produce model outputs", modelOutputsStorageSoftwareSystem); submissionExecutionWorkflow.Add(hangfireSoftwareSystem, "Registers produced model outputs", modelOutputsStorageSoftwareSystem); submissionExecutionWorkflow.Add(hangfireSoftwareSystem, "Regularly checks submissions and creates post-processing submission", modelOutputsStorageSoftwareSystem); submissionExecutionWorkflow.Add(runsControllerSoftwareSystem, "Post-processing package produces post-processed model outputs", modelOutputsStorageSoftwareSystem); submissionExecutionWorkflow.Add(controlFrameworkSoftwareSystem, "Loads post-processed model outputs to database and archive", modelOutputsStorageSoftwareSystem); submissionExecutionWorkflow.Add(hangfireSoftwareSystem, "Performs post-load processing", modelOutputsStorageSoftwareSystem); submissionExecutionWorkflow.Add(spotfireSoftwareSystem, "Loaded post-processed outputs are available in Spotfire", modelOutputsStorageSoftwareSystem); #endregion #region Styles // add some styling Styles styles = views.Configuration.Styles; styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#1168bd", Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.Person) { Background = "#08427b", Color = "#ffffff", Shape = Shape.Person }); // styles.Add(new RelationshipStyle(Tags.Relationship) {Routing = Routing.Orthogonal, Position = 30 }); #endregion #endregion #region Documentation // add some documentation StructurizrDocumentationTemplate template = new StructurizrDocumentationTemplate(workspace); var documentationFolderPath = Path.Combine(AppContext.BaseDirectory, "Documentation"); template.AddContextSection(amsSoftwareSystem, new FileInfo(Path.Combine(documentationFolderPath, "Context.md"))); template.AddFunctionalOverviewSection(amsSoftwareSystem, new FileInfo(Path.Combine(documentationFolderPath, "FunctionalOverview.md"))); template.AddDataSection(amsSoftwareSystem, new FileInfo(Path.Combine(documentationFolderPath, "Data.md"))); template.AddPrinciplesSection(amsSoftwareSystem, new FileInfo(Path.Combine(documentationFolderPath, "Principles.md"))); template.AddSoftwareArchitectureSection(amsSoftwareSystem, new FileInfo(Path.Combine(documentationFolderPath, "SoftwareArchitecture.md"))); template.AddDeploymentSection(amsSoftwareSystem, new FileInfo(Path.Combine(documentationFolderPath, "Deployment.md"))); template.AddOperationAndSupportSection(amsSoftwareSystem, new FileInfo(Path.Combine(documentationFolderPath, "OperationAndSupport.md"))); template.AddInfrastructureArchitectureSection(amsSoftwareSystem, new FileInfo(Path.Combine(documentationFolderPath, "InfrastructureArchitecture.md"))); #endregion // documentation on documentation AddDocumentationDiagram(workspace, template); #region Upload; generate local DGML; generate local PlantUML // upload workspace to Structurizr (https://structurizr.com/) UploadWorkspaceToStructurizr(workspace); // Convert diagrams to DGML - dgml files can be opened using Visual Studio (extension is needed for VS 2017) var dgml = workspace.ToDgml(); dgml.WriteToFile("c4model.dgml"); // Convert diagrams to PlantUML format (http://plantuml.com/) StringWriter stringWriter = new StringWriter(); PlantUMLWriter plantUMLWriter = new PlantUMLWriter(); plantUMLWriter.Write(workspace, stringWriter); // content of the generated file can be visualized online (http://www.plantuml.com/plantuml/uml/) // or converted to image locally (using local PlantUML jar + Graphwiz or one of available VS Code extensions) File.WriteAllText("c4model_plant_UML.txt", stringWriter.ToString()); #endregion }
private static Workspace Create(bool usePaidFeatures) { Workspace workspace = new Workspace("Big Bank plc", "This is an example workspace to illustrate the key features of Structurizr, based around a fictional online banking system."); Model model = workspace.Model; ViewSet views = workspace.Views; model.Enterprise = new Enterprise("Big Bank plc"); // people and software systems Person customer = model.AddPerson(Location.External, "Customer", "A customer of the bank."); SoftwareSystem internetBankingSystem = model.AddSoftwareSystem(Location.Internal, "Internet Banking System", "Allows customers to view information about their bank accounts and make payments."); customer.Uses(internetBankingSystem, "Uses"); SoftwareSystem mainframeBankingSystem = model.AddSoftwareSystem(Location.Internal, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc."); internetBankingSystem.Uses(mainframeBankingSystem, "Uses"); SoftwareSystem atm = model.AddSoftwareSystem(Location.Internal, "ATM", "Allows customers to withdraw cash."); atm.Uses(mainframeBankingSystem, "Uses"); customer.Uses(atm, "Withdraws cash using"); Person bankStaff = model.AddPerson(Location.Internal, "Bank Staff", "Staff within the bank."); bankStaff.Uses(mainframeBankingSystem, "Uses"); // containers Container webApplication = internetBankingSystem.AddContainer("Web Application", "Provides all of the Internet banking functionality to customers.", "Java and Spring MVC"); Container database = internetBankingSystem.AddContainer("Database", "Stores interesting data.", "Relational Database Schema"); database.AddTags(DatabaseTag); customer.Uses(webApplication, "HTTPS"); webApplication.Uses(database, "Reads from and writes to", "JDBC"); webApplication.Uses(mainframeBankingSystem, "Uses", "XML/HTTPS"); // components // - for a real-world software system, you would probably want to extract the components using // - static analysis/reflection rather than manually specifying them all Component homePageController = webApplication.AddComponent("Home Page Controller", "Serves up the home page.", "Spring MVC Controller"); Component signinController = webApplication.AddComponent("Sign In Controller", "Allows users to sign in to the Internet Banking System.", "Spring MVC Controller"); Component accountsSummaryController = webApplication.AddComponent("Accounts Summary Controller", "Provides customers with an summary of their bank accounts.", "Spring MVC Controller"); Component securityComponent = webApplication.AddComponent("Security Component", "Provides functionality related to signing in, changing passwords, etc.", "Spring Bean"); Component mainframeBankingSystemFacade = webApplication.AddComponent("Mainframe Banking System Facade", "A facade onto the mainframe banking system.", "Spring Bean"); webApplication.Components.Where(c => "Spring MVC Controller".Equals(c.Technology)).ToList().ForEach(c => customer.Uses(c, "Uses", "HTTPS")); signinController.Uses(securityComponent, "Uses"); accountsSummaryController.Uses(mainframeBankingSystemFacade, "Uses"); securityComponent.Uses(database, "Reads from and writes to", "JDBC"); mainframeBankingSystemFacade.Uses(mainframeBankingSystem, "Uses", "XML/HTTPS"); // deployment nodes and container instances DeploymentNode developerLaptop = model.AddDeploymentNode("Developer Laptop", "A developer laptop.", "Windows 7 or 10"); developerLaptop.AddDeploymentNode("Docker Container - Web Server", "A Docker container.", "Docker") .AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8")) .Add(webApplication); developerLaptop.AddDeploymentNode("Docker Container - Database Server", "A Docker container.", "Docker") .AddDeploymentNode("Database Server", "A development database.", "Oracle 12c") .Add(database); DeploymentNode liveWebServer = model.AddDeploymentNode("bigbank-web***", "A web server residing in the web server farm, accessed via F5 BIG-IP LTMs.", "Ubuntu 16.04 LTS", 8, DictionaryUtils.Create("Location=London")); liveWebServer.AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8")) .Add(webApplication); DeploymentNode primaryDatabaseServer = model.AddDeploymentNode("bigbank-db01", "The primary database server.", "Ubuntu 16.04 LTS", 1, DictionaryUtils.Create("Location=London")) .AddDeploymentNode("Oracle - Primary", "The primary, live database server.", "Oracle 12c"); primaryDatabaseServer.Add(database); DeploymentNode secondaryDatabaseServer = model.AddDeploymentNode("bigbank-db02", "The secondary database server.", "Ubuntu 16.04 LTS", 1, DictionaryUtils.Create("Location=Reading")) .AddDeploymentNode("Oracle - Secondary", "A secondary, standby database server, used for failover purposes only.", "Oracle 12c"); ContainerInstance secondaryDatabase = secondaryDatabaseServer.Add(database); model.Relationships.Where(r => r.Destination.Equals(secondaryDatabase)).ToList().ForEach(r => r.AddTags("Failover")); Relationship dataReplicationRelationship = primaryDatabaseServer.Uses(secondaryDatabaseServer, "Replicates data to", ""); secondaryDatabase.AddTags("Failover"); // views/diagrams EnterpriseContextView enterpriseContextView = views.CreateEnterpriseContextView("EnterpriseContext", "The system context diagram for the Internet Banking System."); enterpriseContextView.AddAllElements(); enterpriseContextView.PaperSize = PaperSize.A5_Landscape; SystemContextView systemContextView = views.CreateSystemContextView(internetBankingSystem, "SystemContext", "The system context diagram for the Internet Banking System."); systemContextView.AddNearestNeighbours(internetBankingSystem); systemContextView.PaperSize = PaperSize.A5_Landscape; ContainerView containerView = views.CreateContainerView(internetBankingSystem, "Containers", "The container diagram for the Internet Banking System."); containerView.Add(customer); containerView.AddAllContainers(); containerView.Add(mainframeBankingSystem); containerView.PaperSize = PaperSize.A5_Landscape; ComponentView componentView = views.CreateComponentView(webApplication, "Components", "The components diagram for the Web Application"); componentView.AddAllContainers(); componentView.AddAllComponents(); componentView.Add(customer); componentView.Add(mainframeBankingSystem); componentView.PaperSize = PaperSize.A5_Landscape; if (usePaidFeatures) { // dynamic diagrams, deployment diagrams and corporate branding are not available with the Free Plan DynamicView dynamicView = views.CreateDynamicView(webApplication, "SignIn", "Summarises how the sign in feature works."); dynamicView.Add(customer, "Requests /signin from", signinController); dynamicView.Add(customer, "Submits credentials to", signinController); dynamicView.Add(signinController, "Calls isAuthenticated() on", securityComponent); dynamicView.Add(securityComponent, "select * from users u where username = ?", database); dynamicView.PaperSize = PaperSize.A5_Landscape; DeploymentView developmentDeploymentView = views.CreateDeploymentView(internetBankingSystem, "DevelopmentDeployment", "An example development deployment scenario for the Internet Banking System."); developmentDeploymentView.Add(developerLaptop); developmentDeploymentView.PaperSize = PaperSize.A5_Landscape; DeploymentView liveDeploymentView = views.CreateDeploymentView(internetBankingSystem, "LiveDeployment", "An example live deployment scenario for the Internet Banking System."); liveDeploymentView.Add(liveWebServer); liveDeploymentView.Add(primaryDatabaseServer); liveDeploymentView.Add(secondaryDatabaseServer); liveDeploymentView.Add(dataReplicationRelationship); liveDeploymentView.PaperSize = PaperSize.A5_Landscape; } // colours, shapes and other diagram styling Styles styles = views.Configuration.Styles; styles.Add(new ElementStyle(Tags.Element) { Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#1168bd" }); styles.Add(new ElementStyle(Tags.Container) { Background = "#438dd5" }); styles.Add(new ElementStyle(Tags.Component) { Background = "#85bbf0", Color = "#000000" }); styles.Add(new ElementStyle(Tags.Person) { Background = "#08427b", Shape = Shape.Person }); styles.Add(new ElementStyle(DatabaseTag) { Shape = Shape.Cylinder }); styles.Add(new ElementStyle("Failover") { Opacity = 25 }); styles.Add(new RelationshipStyle("Failover") { Opacity = 25, Position = 70 }); // documentation // - usually the documentation would be included from separate Markdown/AsciiDoc files, but this is just an example StructurizrDocumentationTemplate template = new StructurizrDocumentationTemplate(workspace); template.AddContextSection(internetBankingSystem, Format.Markdown, "Here is some context about the Internet Banking System...\n" + "![](embed:EnterpriseContext)\n" + "![](embed:SystemContext)\n" + "### Internet Banking System\n...\n" + "### Mainframe Banking System\n...\n"); template.AddContainersSection(internetBankingSystem, Format.Markdown, "Here is some information about the containers within the Internet Banking System...\n" + "![](embed:Containers)\n" + "### Web Application\n...\n" + "### Database\n...\n"); template.AddComponentsSection(webApplication, Format.Markdown, "Here is some information about the Web Application...\n" + "![](embed:Components)\n" + "### Sign in process\n" + "Here is some information about the Sign In Controller, including how the sign in process works...\n" + "![](embed:SignIn)"); template.AddDevelopmentEnvironmentSection(internetBankingSystem, Format.AsciiDoc, "Here is some information about how to set up a development environment for the Internet Banking System...\n" + "image::embed:DevelopmentDeployment[]"); template.AddDeploymentSection(internetBankingSystem, Format.AsciiDoc, "Here is some information about the live deployment environment for the Internet Banking System...\n" + "image::embed:LiveDeployment[]"); return(workspace); }
private void PopulateWorkspace() { Model model = _workspace.Model; ViewSet views = _workspace.Views; model.Enterprise = new Enterprise("Some Enterprise"); Person user = model.AddPerson(Location.Internal, "User", ""); SoftwareSystem softwareSystem = model.AddSoftwareSystem(Location.Internal, "Software System", ""); user.Uses(softwareSystem, "Uses"); SoftwareSystem emailSystem = model.AddSoftwareSystem(Location.External, "E-mail System", ""); softwareSystem.Uses(emailSystem, "Sends e-mail using"); emailSystem.Delivers(user, "Delivers e-mails to"); Container webApplication = softwareSystem.AddContainer("Web Application", "", ""); Container database = softwareSystem.AddContainer("Database", "", ""); user.Uses(webApplication, "Uses", "HTTP"); webApplication.Uses(database, "Reads from and writes to", "JDBC"); webApplication.Uses(emailSystem, "Sends e-mail using"); Component controller = webApplication.AddComponent("SomeController", "", "Spring MVC Controller"); Component emailComponent = webApplication.AddComponent("EmailComponent", ""); Component repository = webApplication.AddComponent("SomeRepository", "", "Spring Data"); user.Uses(controller, "Uses", "HTTP"); controller.Uses(repository, "Uses"); controller.Uses(emailComponent, "Sends e-mail using"); repository.Uses(database, "Reads from and writes to", "JDBC"); emailComponent.Uses(emailSystem, "Sends e-mails using", "SMTP"); DeploymentNode webServer = model.AddDeploymentNode("Web Server", "A server hosted at AWS EC2.", "Ubuntu 12.04 LTS"); webServer.AddDeploymentNode("Apache Tomcat", "The live web server", "Apache Tomcat 8.x") .Add(webApplication); DeploymentNode databaseServer = model.AddDeploymentNode("Database Server", "A server hosted at AWS EC2.", "Ubuntu 12.04 LTS"); databaseServer.AddDeploymentNode("MySQL", "The live database server", "MySQL 5.5.x") .Add(database); SystemLandscapeView systemLandscapeView = views.CreateSystemLandscapeView("enterpriseContext", ""); systemLandscapeView.AddAllElements(); SystemContextView systemContextView = views.CreateSystemContextView(softwareSystem, "systemContext", ""); systemContextView.AddAllElements(); ContainerView containerView = views.CreateContainerView(softwareSystem, "containers", ""); containerView.AddAllElements(); ComponentView componentView = views.CreateComponentView(webApplication, "components", ""); componentView.AddAllElements(); DynamicView dynamicView = views.CreateDynamicView(webApplication, "dynamic", ""); dynamicView.Add(user, "Requests /something", controller); dynamicView.Add(controller, repository); dynamicView.Add(repository, "select * from something", database); DeploymentView deploymentView = views.CreateDeploymentView(softwareSystem, "deployment", ""); deploymentView.AddAllDeploymentNodes(); }
private static Workspace CreateBugbank() { Workspace workspace = new Workspace("Big Bank plc", "This is an example workspace to illustrate the key features of Structurizr, based around a fictional online banking system."); Model model = workspace.Model; ViewSet views = workspace.Views; model.Enterprise = new Enterprise("Big Bank plc"); // people and software systems Person customer = model.AddPerson(Location.External, "Personal Banking Customer", "A customer of the bank, with personal bank accounts."); SoftwareSystem internetBankingSystem = model.AddSoftwareSystem(Location.Internal, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments."); customer.Uses(internetBankingSystem, "Uses"); SoftwareSystem mainframeBankingSystem = model.AddSoftwareSystem(Location.Internal, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc."); mainframeBankingSystem.AddTags(ExistingSystemTag); internetBankingSystem.Uses(mainframeBankingSystem, "Uses"); SoftwareSystem emailSystem = model.AddSoftwareSystem(Location.Internal, "E-mail System", "The internal Microsoft Exchange e-mail system."); emailSystem.AddTags(ExistingSystemTag); emailSystem.Delivers(customer, "Sends e-mails to"); SoftwareSystem atm = model.AddSoftwareSystem(Location.Internal, "ATM", "Allows customers to withdraw cash."); atm.AddTags(ExistingSystemTag); atm.Uses(mainframeBankingSystem, "Uses"); customer.Uses(atm, "Withdraws cash using"); Person customerServiceStaff = model.AddPerson(Location.Internal, "Customer Service Staff", "Customer service staff within the bank."); customerServiceStaff.AddTags(BankStaffTag); customerServiceStaff.Uses(mainframeBankingSystem, "Uses"); customer.InteractsWith(customerServiceStaff, "Asks questions to", "Telephone"); Person backOfficeStaff = model.AddPerson(Location.Internal, "Back Office Staff", "Administration and support staff within the bank."); backOfficeStaff.AddTags(BankStaffTag); backOfficeStaff.Uses(mainframeBankingSystem, "Uses"); // containers Container singlePageApplication = internetBankingSystem.AddContainer("Single-Page Application", "Provides all of the Internet banking functionality to customers via their web browser.", "JavaScript and Angular"); singlePageApplication.AddTags(WebBrowserTag); Container mobileApp = internetBankingSystem.AddContainer("Mobile App", "Provides a limited subset of the Internet banking functionality to customers via their mobile device.", "Xamarin"); mobileApp.AddTags(MobileAppTag); Container webApplication = internetBankingSystem.AddContainer("Web Application", "Delivers the static content and the Internet banking single page application.", "Java and Spring MVC"); Container apiApplication = internetBankingSystem.AddContainer("API Application", "Provides Internet banking functionality via a JSON/HTTPS API.", "Java and Spring MVC"); Container database = internetBankingSystem.AddContainer("Database", "Stores user registration information, hashed authentication credentials, access logs, etc.", "Relational Database Schema"); database.AddTags(DatabaseTag); customer.Uses(webApplication, "Uses", "HTTPS"); customer.Uses(singlePageApplication, "Uses", ""); customer.Uses(mobileApp, "Uses", ""); webApplication.Uses(singlePageApplication, "Delivers", ""); apiApplication.Uses(database, "Reads from and writes to", "JDBC"); apiApplication.Uses(mainframeBankingSystem, "Uses", "XML/HTTPS"); apiApplication.Uses(emailSystem, "Sends e-mail using", "SMTP"); // components // - for a real-world software system, you would probably want to extract the components using // - static analysis/reflection rather than manually specifying them all Component signinController = apiApplication.AddComponent("Sign In Controller", "Allows users to sign in to the Internet Banking System.", "Spring MVC Rest Controller"); Component accountsSummaryController = apiApplication.AddComponent("Accounts Summary Controller", "Provides customers with a summary of their bank accounts.", "Spring MVC Rest Controller"); Component securityComponent = apiApplication.AddComponent("Security Component", "Provides functionality related to signing in, changing passwords, etc.", "Spring Bean"); Component mainframeBankingSystemFacade = apiApplication.AddComponent("Mainframe Banking System Facade", "A facade onto the mainframe banking system.", "Spring Bean"); apiApplication.Components.Where(c => "Spring MVC Rest Controller".Equals(c.Technology)).ToList().ForEach(c => singlePageApplication.Uses(c, "Uses", "HTTPS")); apiApplication.Components.Where(c => "Spring MVC Rest Controller".Equals(c.Technology)).ToList().ForEach(c => mobileApp.Uses(c, "Uses", "HTTPS")); signinController.Uses(securityComponent, "Uses"); accountsSummaryController.Uses(mainframeBankingSystemFacade, "Uses"); securityComponent.Uses(database, "Reads from and writes to", "JDBC"); mainframeBankingSystemFacade.Uses(mainframeBankingSystem, "Uses", "XML/HTTPS"); model.AddImplicitRelationships(); // deployment nodes and container instances DeploymentNode developerLaptop = model.AddDeploymentNode("Developer Laptop", "A developer laptop.", "Microsoft Windows 10 or Apple macOS"); DeploymentNode apacheTomcat = developerLaptop.AddDeploymentNode("Docker Container - Web Server", "A Docker container.", "Docker") .AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8")); apacheTomcat.Add(webApplication); apacheTomcat.Add(apiApplication); developerLaptop.AddDeploymentNode("Docker Container - Database Server", "A Docker container.", "Docker") .AddDeploymentNode("Database Server", "A development database.", "Oracle 12c") .Add(database); developerLaptop.AddDeploymentNode("Web Browser", "", "Google Chrome, Mozilla Firefox, Apple Safari or Microsoft Edge").Add(singlePageApplication); DeploymentNode customerMobileDevice = model.AddDeploymentNode("Customer's mobile device", "", "Apple iOS or Android"); customerMobileDevice.Add(mobileApp); DeploymentNode customerComputer = model.AddDeploymentNode("Customer's computer", "", "Microsoft Windows or Apple macOS"); customerComputer.AddDeploymentNode("Web Browser", "", "Google Chrome, Mozilla Firefox, Apple Safari or Microsoft Edge").Add(singlePageApplication); DeploymentNode bigBankDataCenter = model.AddDeploymentNode("Big Bank plc", "", "Big Bank plc data center"); DeploymentNode liveWebServer = bigBankDataCenter.AddDeploymentNode("bigbank-web***", "A web server residing in the web server farm, accessed via F5 BIG-IP LTMs.", "Ubuntu 16.04 LTS", 4, DictionaryUtils.Create("Location=London and Reading")); liveWebServer.AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8")) .Add(webApplication); DeploymentNode liveApiServer = bigBankDataCenter.AddDeploymentNode("bigbank-api***", "A web server residing in the web server farm, accessed via F5 BIG-IP LTMs.", "Ubuntu 16.04 LTS", 8, DictionaryUtils.Create("Location=London and Reading")); liveApiServer.AddDeploymentNode("Apache Tomcat", "An open source Java EE web server.", "Apache Tomcat 8.x", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", "Java Version=8")) .Add(apiApplication); DeploymentNode primaryDatabaseServer = bigBankDataCenter.AddDeploymentNode("bigbank-db01", "The primary database server.", "Ubuntu 16.04 LTS", 1, DictionaryUtils.Create("Location=London")) .AddDeploymentNode("Oracle - Primary", "The primary, live database server.", "Oracle 12c"); primaryDatabaseServer.Add(database); DeploymentNode secondaryDatabaseServer = bigBankDataCenter.AddDeploymentNode("bigbank-db02", "The secondary database server.", "Ubuntu 16.04 LTS", 1, DictionaryUtils.Create("Location=Reading")) .AddDeploymentNode("Oracle - Secondary", "A secondary, standby database server, used for failover purposes only.", "Oracle 12c"); ContainerInstance secondaryDatabase = secondaryDatabaseServer.Add(database); model.Relationships.Where(r => r.Destination.Equals(secondaryDatabase)).ToList().ForEach(r => r.AddTags(FailoverTag)); Relationship dataReplicationRelationship = primaryDatabaseServer.Uses(secondaryDatabaseServer, "Replicates data to", ""); secondaryDatabase.AddTags(FailoverTag); // views/diagrams //SystemLandscapeView systemLandscapeView = views.CreateSystemLandscapeView("SystemLandscape", "The system landscape diagram for Big Bank plc."); //systemLandscapeView.AddAllElements(); //systemLandscapeView.PaperSize = PaperSize.A5_Landscape; SystemContextView systemContextView = views.CreateSystemContextView(internetBankingSystem, "SystemContext", "The system context diagram for the Internet Banking System."); //systemContextView.EnterpriseBoundaryVisible = false; systemContextView.AddNearestNeighbours(internetBankingSystem); systemContextView.PaperSize = PaperSize.A5_Landscape; ContainerView containerView = views.CreateContainerView(internetBankingSystem, "Containers", "The container diagram for the Internet Banking System."); containerView.Add(customer); containerView.AddAllContainers(); containerView.Add(mainframeBankingSystem); containerView.Add(emailSystem); containerView.PaperSize = PaperSize.A5_Landscape; ComponentView componentView = views.CreateComponentView(apiApplication, "Components", "The component diagram for the API Application."); componentView.Add(mobileApp); componentView.Add(singlePageApplication); componentView.Add(database); componentView.AddAllComponents(); componentView.Add(mainframeBankingSystem); componentView.PaperSize = PaperSize.A5_Landscape; // dynamic diagrams and deployment diagrams are not available with the Free Plan DynamicView dynamicView = views.CreateDynamicView(apiApplication, "SignIn", "Summarises how the sign in feature works in the single-page application."); dynamicView.Add(singlePageApplication, "Submits credentials to", signinController); dynamicView.Add(signinController, "Calls isAuthenticated() on", securityComponent); dynamicView.Add(securityComponent, "select * from users where username = ?", database); dynamicView.PaperSize = PaperSize.A5_Landscape; DeploymentView developmentDeploymentView = views.CreateDeploymentView(internetBankingSystem, "DevelopmentDeployment", "An example development deployment scenario for the Internet Banking System."); //developmentDeploymentView.Environment = "Development"; developmentDeploymentView.Add(developerLaptop); developmentDeploymentView.PaperSize = PaperSize.A5_Landscape; DeploymentView liveDeploymentView = views.CreateDeploymentView(internetBankingSystem, "LiveDeployment", "An example live deployment scenario for the Internet Banking System."); //liveDeploymentView.Environment = "Live"; liveDeploymentView.Add(bigBankDataCenter); liveDeploymentView.Add(customerMobileDevice); liveDeploymentView.Add(customerComputer); liveDeploymentView.Add(dataReplicationRelationship); liveDeploymentView.PaperSize = PaperSize.A5_Landscape; // colours, shapes and other diagram styling Styles styles = views.Configuration.Styles; styles.Add(new ElementStyle(Tags.Element) { Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#1168bd" }); styles.Add(new ElementStyle(Tags.Container) { Background = "#438dd5" }); styles.Add(new ElementStyle(Tags.Component) { Background = "#85bbf0", Color = "#000000" }); styles.Add(new ElementStyle(Tags.Person) { Background = "#08427b", Shape = Shape.Person, FontSize = 22 }); styles.Add(new ElementStyle(ExistingSystemTag) { Background = "#999999" }); styles.Add(new ElementStyle(BankStaffTag) { Background = "#999999" }); styles.Add(new ElementStyle(WebBrowserTag) { Shape = Shape.WebBrowser }); styles.Add(new ElementStyle(MobileAppTag) { Shape = Shape.MobileDeviceLandscape }); styles.Add(new ElementStyle(DatabaseTag) { Shape = Shape.Cylinder }); styles.Add(new ElementStyle(FailoverTag) { Opacity = 25 }); styles.Add(new RelationshipStyle(FailoverTag) { Opacity = 25, Position = 70 }); return(workspace); }
static void Main() { Workspace workspace = new Workspace("Structurizr for .NET Annotations", "This is a model of my software system."); Model model = workspace.Model; Person user = model.AddPerson("User", "A user of my software system."); SoftwareSystem softwareSystem = model.AddSoftwareSystem("Software System", "My software system."); Container webApplication = softwareSystem.AddContainer("Web Application", "Provides users with information.", "C#"); Container database = softwareSystem.AddContainer("Database", "Stores information.", "Relational database schema"); database.AddTags(DatabaseTag); ComponentFinder componentFinder = new ComponentFinder( webApplication, "Structurizr.Examples.Annotations", new StructurizrAnnotationsComponentFinderStrategy() ); componentFinder.FindComponents(); model.AddImplicitRelationships(); ViewSet views = workspace.Views; SystemContextView contextView = views.CreateSystemContextView(softwareSystem, "SystemContext", "An example of a System Context diagram."); contextView.AddAllElements(); ContainerView containerView = views.CreateContainerView(softwareSystem, "Containers", "The container diagram from my software system."); containerView.AddAllElements(); ComponentView componentView = views.CreateComponentView(webApplication, "Components", "The component diagram for the web application."); componentView.AddAllElements(); Styles styles = views.Configuration.Styles; styles.Add(new ElementStyle(Tags.Element) { Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#1168bd" }); styles.Add(new ElementStyle(Tags.Container) { Background = "#438dd5" }); styles.Add(new ElementStyle(Tags.Component) { Background = "#85bbf0", Color = "#000000" }); styles.Add(new ElementStyle(Tags.Person) { Background = "#08427b", Shape = Shape.Person }); styles.Add(new ElementStyle(DatabaseTag) { Shape = Shape.Cylinder }); StructurizrClient structurizrClient = new StructurizrClient(ApiKey, ApiSecret); structurizrClient.PutWorkspace(WorkspaceId, workspace); }
static void Main(string[] args) { Workspace workspace = new Workspace("Park Soft", "Software for parking system"); Model model = workspace.Model; ViewSet views = workspace.Views; AddContext(model, views); model.Enterprise = new Enterprise("System parkingowy"); Person customer = model.AddPerson( Location.External, "Klient", "Klient parkingu, " + "posiada konto w systemie"); Person parkingOperator = model.AddPerson( Location.External, "Operator", "Operator parkingu, " + "posiada konto w systemie"); SoftwareSystem clientPlatformSystem = model.AddSoftwareSystem( Location.Internal, "Platforma kliencka", "Pozwala na zarządzanie swoimi rezerwacjami"); customer.Uses(clientPlatformSystem, "Używa"); SoftwareSystem mainframeParkingSystem = model.AddSoftwareSystem( Location.Internal, "System parkingowy", "Core'owy system parkingowy."); clientPlatformSystem.Uses( mainframeParkingSystem, "Pobiera informacje/Wysyła informacje"); parkingOperator.Uses(mainframeParkingSystem, "obsługuje"); SoftwareSystem emailSystem = model.AddSoftwareSystem(Location.Internal, "E-mail System", "System e-mailowy Microsoft Exchange"); clientPlatformSystem.Uses(emailSystem, "Wysyła e-maile używając"); emailSystem.Delivers(customer, "Wysyła e-maile do"); clientPlatformSystem.Uses( mainframeParkingSystem, "Pobiera informacje/Wysyła informacje"); SystemContextView systemContextView = views.CreateSystemContextView( clientPlatformSystem, "SystemContext", "Diagram kontekstowy systemu parkingowego"); systemContextView.AddNearestNeighbours(clientPlatformSystem); systemContextView.AddAnimation(clientPlatformSystem); systemContextView.AddAnimation(customer); //systemContextView.AddAnimation(parkingOperator); systemContextView.AddAnimation(mainframeParkingSystem); //wcześniej zdefiniowany kontekst Container mobileApp = mainframeParkingSystem.AddContainer( "Aplikacja mobilna", "Dostarcza ograniczoną funkcjonalność bankowości online dla klienta", "Xamarin"); Container apiApplication = mainframeParkingSystem.AddContainer( "API", "Dostarcza funkcjonalność bankowości online poprzez JSON/HTTP", "Java i Spring MVC"); Container database = mainframeParkingSystem.AddContainer( "Baza danych", "Informacje o klientach, hashowane hasła, logi", "Relacyjna baza danych"); parkingOperator.Uses(mobileApp, "Używa", ""); apiApplication.Uses(database, "Czyta/Zapisuje", "JDBC"); apiApplication.Uses(mainframeParkingSystem, "Używa", "XML/HTTPS"); apiApplication.Uses(emailSystem, "Wysyła maile", "SMTP"); ContainerView containerView = views.CreateContainerView( clientPlatformSystem, "Containers", "Diagram kontenerów systemu Platformy Bankowowości Online"); containerView.Add(customer); containerView.AddAllContainers(); containerView.Add(mainframeParkingSystem); containerView.Add(emailSystem); containerView.AddAnimation( customer, mainframeParkingSystem, emailSystem); // containerView.AddAnimation(mobileApp); // containerView.AddAnimation(apiApplication); UploadWorkspaceToStructurizr(workspace); }
static void Main(string[] args) { Workspace workspace = new Workspace("Financial Risk System", "A simple example C4 model based upon the financial risk system architecture kata, created using Structurizr for .NET"); Model model = workspace.Model; // create the basic model SoftwareSystem financialRiskSystem = model.AddSoftwareSystem(Location.Internal, "Financial Risk System", "Calculates the bank's exposure to risk for product X"); Person businessUser = model.AddPerson(Location.Internal, "Business User", "A regular business user"); businessUser.Uses(financialRiskSystem, "Views reports using"); Person configurationUser = model.AddPerson(Location.Internal, "Configuration User", "A regular business user who can also configure the parameters used in the risk calculations"); configurationUser.Uses(financialRiskSystem, "Configures parameters using"); SoftwareSystem tradeDataSystem = model.AddSoftwareSystem(Location.Internal, "Trade Data System", "The system of record for trades of type X"); financialRiskSystem.Uses(tradeDataSystem, "Gets trade data from"); SoftwareSystem referenceDataSystem = model.AddSoftwareSystem(Location.Internal, "Reference Data System", "Manages reference data for all counterparties the bank interacts with"); financialRiskSystem.Uses(referenceDataSystem, "Gets counterparty data from"); SoftwareSystem emailSystem = model.AddSoftwareSystem(Location.Internal, "E-mail system", "Microsoft Exchange"); financialRiskSystem.Uses(emailSystem, "Sends a notification that a report is ready to"); emailSystem.Delivers(businessUser, "Sends a notification that a report is ready to", "E-mail message", InteractionStyle.Asynchronous); SoftwareSystem centralMonitoringService = model.AddSoftwareSystem(Location.Internal, "Central Monitoring Service", "The bank-wide monitoring and alerting dashboard"); financialRiskSystem.Uses(centralMonitoringService, "Sends critical failure alerts to", "SNMP", InteractionStyle.Asynchronous).AddTags(AlertTag); SoftwareSystem activeDirectory = model.AddSoftwareSystem(Location.Internal, "Active Directory", "Manages users and security roles across the bank"); financialRiskSystem.Uses(activeDirectory, "Uses for authentication and authorisation"); Container webApplication = financialRiskSystem.AddContainer("Web Application", "Allows users to view reports and modify risk calculation parameters", "ASP.NET MVC"); businessUser.Uses(webApplication, "Views reports using"); configurationUser.Uses(webApplication, "Modifies risk calculation parameters using"); webApplication.Uses(activeDirectory, "Uses for authentication and authorisation"); Container batchProcess = financialRiskSystem.AddContainer("Batch Process", "Calculates the risk", "Windows Service"); batchProcess.Uses(emailSystem, "Sends a notification that a report is ready to"); batchProcess.Uses(tradeDataSystem, "Gets trade data from"); batchProcess.Uses(referenceDataSystem, "Gets counterparty data from"); batchProcess.Uses(centralMonitoringService, "Sends critical failure alerts to", "SNMP", InteractionStyle.Asynchronous).AddTags(AlertTag); Container fileSystem = financialRiskSystem.AddContainer("File System", "Stores risk reports", "Network File Share"); webApplication.Uses(fileSystem, "Consumes risk reports from"); batchProcess.Uses(fileSystem, "Publishes risk reports to"); Component scheduler = batchProcess.AddComponent("Scheduler", "Starts the risk calculation process at 5pm New York time", "Quartz.NET"); Component orchestrator = batchProcess.AddComponent("Orchestrator", "Orchestrates the risk calculation process", "C#"); Component tradeDataImporter = batchProcess.AddComponent("Trade data importer", "Imports data from the Trade Data System", "C#"); Component referenceDataImporter = batchProcess.AddComponent("Reference data importer", "Imports data from the Reference Data System", "C#"); Component riskCalculator = batchProcess.AddComponent("Risk calculator", "Calculates risk", "C#"); Component reportGenerator = batchProcess.AddComponent("Report generator", "Generates a Microsoft Excel compatible risk report", "C# and Microsoft.Office.Interop.Excel"); Component reportPublisher = batchProcess.AddComponent("Report distributor", "Publishes the report to the web application", "C#"); Component emailComponent = batchProcess.AddComponent("E-mail component", "Sends e-mails", "C#"); Component reportChecker = batchProcess.AddComponent("Report checker", "Checks that the report has been generated by 9am singapore time", "C#"); Component alertComponent = batchProcess.AddComponent("Alert component", "Sends SNMP alerts", "C# and #SNMP Library"); scheduler.Uses(orchestrator, "Starts"); scheduler.Uses(reportChecker, "Starts"); orchestrator.Uses(tradeDataImporter, "Imports data using"); tradeDataImporter.Uses(tradeDataSystem, "Imports data from"); orchestrator.Uses(referenceDataImporter, "Imports data using"); referenceDataImporter.Uses(referenceDataSystem, "Imports data from"); orchestrator.Uses(riskCalculator, "Calculates the risk using"); orchestrator.Uses(reportGenerator, "Generates the risk report using"); orchestrator.Uses(reportPublisher, "Publishes the risk report using"); reportPublisher.Uses(fileSystem, "Publishes the risk report to"); orchestrator.Uses(emailComponent, "Sends e-mail using"); emailComponent.Uses(emailSystem, "Sends a notification that a report is ready to"); reportChecker.Uses(alertComponent, "Sends alerts using"); alertComponent.Uses(centralMonitoringService, "Sends alerts using", "SNMP", InteractionStyle.Asynchronous).AddTags(AlertTag); // create some views ViewSet viewSet = workspace.Views; SystemContextView contextView = viewSet.CreateSystemContextView(financialRiskSystem, "Context", ""); contextView.PaperSize = PaperSize.A4_Landscape; contextView.AddAllSoftwareSystems(); contextView.AddAllPeople(); ContainerView containerView = viewSet.CreateContainerView(financialRiskSystem, "Containers", ""); contextView.PaperSize = PaperSize.A4_Landscape; containerView.AddAllElements(); ComponentView componentViewForBatchProcess = viewSet.CreateComponentView(batchProcess, "Components", ""); contextView.PaperSize = PaperSize.A3_Landscape; componentViewForBatchProcess.AddAllElements(); componentViewForBatchProcess.Remove(configurationUser); componentViewForBatchProcess.Remove(webApplication); componentViewForBatchProcess.Remove(activeDirectory); // tag and style some elements Styles styles = viewSet.Configuration.Styles; financialRiskSystem.AddTags("Risk System"); styles.Add(new ElementStyle(Tags.Element) { Color = "#ffffff", FontSize = 34 }); styles.Add(new ElementStyle("Risk System") { Background = "#8a458a" }); styles.Add(new ElementStyle(Tags.SoftwareSystem) { Width = 650, Height = 400, Background = "#510d51", Shape = Shape.Box }); styles.Add(new ElementStyle(Tags.Person) { Width = 550, Background = "#62256e", Shape = Shape.Person }); styles.Add(new ElementStyle(Tags.Container) { Width = 650, Height = 400, Background = "#a46ba4", Shape = Shape.Box }); styles.Add(new ElementStyle(Tags.Component) { Width = 550, Background = "#c9a1c9", Shape = Shape.Box }); styles.Add(new RelationshipStyle(Tags.Relationship) { Thickness = 4, Dashed = false, FontSize = 32, Width = 400 }); styles.Add(new RelationshipStyle(Tags.Synchronous) { Dashed = false }); styles.Add(new RelationshipStyle(Tags.Asynchronous) { Dashed = true }); styles.Add(new RelationshipStyle(AlertTag) { Color = "#ff0000" }); Documentation documentation = workspace.Documentation; FileInfo documentationRoot = new FileInfo(@"..\..\FinancialRiskSystem"); documentation.Add(financialRiskSystem, SectionType.Context, DocumentationFormat.Markdown, new FileInfo(Path.Combine(documentationRoot.FullName, "context.md"))); documentation.Add(financialRiskSystem, SectionType.FunctionalOverview, DocumentationFormat.Markdown, new FileInfo(Path.Combine(documentationRoot.FullName, "functional-overview.md"))); documentation.Add(financialRiskSystem, SectionType.QualityAttributes, DocumentationFormat.Markdown, new FileInfo(Path.Combine(documentationRoot.FullName, "quality-attributes.md"))); documentation.AddImages(documentationRoot); // add some example corporate branding Branding branding = viewSet.Configuration.Branding; branding.Font = new Font("Trebuchet MS"); branding.Color1 = new ColorPair("#510d51", "#ffffff"); branding.Color2 = new ColorPair("#62256e", "#ffffff"); branding.Color3 = new ColorPair("#a46ba4", "#ffffff"); branding.Color4 = new ColorPair("#c9a1c9", "#ffffff"); branding.Color5 = new ColorPair("#c9a1c9", "#ffffff"); branding.Logo = ImageUtils.GetImageAsDataUri(new FileInfo(Path.Combine(documentationRoot.FullName, "codingthearchitecture.png"))); // and upload the model to structurizr.com StructurizrClient structurizrClient = new StructurizrClient("key", "secret"); structurizrClient.PutWorkspace(9481, workspace); }
static void Banking() { const long workspaceId = 54351; const string apiKey = "c289e1d0-d703-4114-bd20-0c57e2e3c18f"; const string apiSecret = "5795af71-0e72-4b66-a286-ac801015b755"; StructurizrClient structurizrClient = new StructurizrClient(apiKey, apiSecret); Workspace workspace = new Workspace("Inventory", "Inventory - C4 Model"); Model model = workspace.Model; SoftwareSystem internetBankingSystem = model.AddSoftwareSystem("Inventory", "Permite a los clientes consultar información de sus inventarios."); Person cliente = model.AddPerson("Cliente", "Cliente de Inventory."); cliente.Uses(internetBankingSystem, "Realiza consultas sobre sus inventarios."); ViewSet viewSet = workspace.Views; // 1. Diagrama de Contexto SystemContextView contextView = viewSet.CreateSystemContextView(internetBankingSystem, "Contexto", "Diagrama de contexto - Banking"); contextView.PaperSize = PaperSize.A4_Landscape; contextView.AddAllSoftwareSystems(); contextView.AddAllPeople(); //contextView.EnableAutomaticLayout(); Styles styles = viewSet.Configuration.Styles; styles.Add(new ElementStyle(Tags.Person) { Background = "#0a60ff", Color = "#ffffff", Shape = Shape.Person }); styles.Add(new ElementStyle("Mobile App") { Background = "#29c732", Color = "#ffffff", Shape = Shape.MobileDevicePortrait }); styles.Add(new ElementStyle("Mainframe") { Background = "#90714c", Color = "#ffffff", Shape = Shape.RoundedBox }); styles.Add(new ElementStyle("SendGrid") { Background = "#a5cdff", Color = "#ffffff", Shape = Shape.RoundedBox }); // 2. Diagrama de Contenedores Container webApplication = internetBankingSystem.AddContainer("Aplicación Web React", "Permite a los clientes consultar información de sus inventarios", "ReactJS, nginx port 80"); Container webApplicationVue = internetBankingSystem.AddContainer("Aplicación Web Vue", "Permite a los clientes consultar información de sus inventarios", "Vue, nginx port 80"); Container webApplicationAngular = internetBankingSystem.AddContainer("Aplicación Web Angular", "Permite a los clientes consultar información de sus inventarios", "Angular, nginx port 80"); Container restApi = internetBankingSystem.AddContainer("RESTful API", "Permite a los clientes consultar información de sus inventarios", "Nest, nginx port 80"); Container root = internetBankingSystem.AddContainer("ROOT", "Permite integrar los micro-frontends", "Single SPA, nginx port 80"); Container database = internetBankingSystem.AddContainer("Base de Datos", "Repositorio de información de inventarios.", "Postgres port 5432"); Container hearthbeat = internetBankingSystem.AddContainer("HearthBeat", "Verifica cada 10 segundos que el API se este ejecutando", "Nodejs, ngix"); webApplication.AddTags("WebAppReact"); webApplicationVue.AddTags("WebAppVue"); webApplicationAngular.AddTags("WebAppAngular"); restApi.AddTags("API"); database.AddTags("Database"); root.AddTags("Root"); hearthbeat.AddTags("HearthBeat"); cliente.Uses(root, "Usa", "https 443"); root.Uses(webApplicationVue, "Usa", "https 443"); root.Uses(webApplicationAngular, "Usa", "https 443"); root.Uses(webApplication, "Usa", "https 443"); webApplication.Uses(restApi, "Usa", "https 443"); webApplicationVue.Uses(restApi, "Usa", "https 443"); webApplicationAngular.Uses(restApi, "Usa", "https 443"); restApi.Uses(database, "Usa", "typeorm 5432"); hearthbeat.Uses(restApi, "Petición", "https 443"); styles.Add(new ElementStyle("WebAppReact") { Background = "#9d33d6", Color = "#ffffff", Shape = Shape.WebBrowser, Icon = "data:image/png;base64,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" }); styles.Add(new ElementStyle("WebAppVue") { Background = "#9d33d6", Color = "#ffffff", Shape = Shape.WebBrowser, Icon = "data:image/png;base64,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" }); styles.Add(new ElementStyle("WebAppAngular") { Background = "#9d33d6", Color = "#ffffff", Shape = Shape.WebBrowser, Icon = "data:image/png;base64,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" }); styles.Add(new ElementStyle("API") { Background = "#929000", Color = "#ffffff", Shape = Shape.RoundedBox, Icon = "data:image/png;base64,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" }); styles.Add(new ElementStyle("Root") { Background = "#929000", Color = "#ffffff", Shape = Shape.RoundedBox, Icon = "data:image/png;base64,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" }); styles.Add(new ElementStyle("Database") { Background = "#ff0000", Color = "#ffffff", Shape = Shape.Cylinder }); ContainerView containerView = viewSet.CreateContainerView(internetBankingSystem, "Contenedor", "Diagrama de contenedores - Banking"); contextView.PaperSize = PaperSize.A4_Landscape; containerView.AddAllElements(); //containerView.EnableAutomaticLayout(); // 3. Diagrama de Componentes Component transactionController = restApi.AddComponent("Products Controller", "Permite a los usuarios manejar sus productos.", "Nest REST Controller"); Component signinController = restApi.AddComponent("Auth Controller", "Permite a los usuarios iniciar sesión en Inventory.", "Nest REST Controller"); Component accountsSummaryController = restApi.AddComponent("Customers Controller", "Proporciona a los clientes un resumen de sus cuentas.", "Nest REST Controller"); Component qualityController = restApi.AddComponent("Quality Controller", "Permite diagnosticar el estado del sistema.", "Nest REST Controller "); restApi.Components.Where(c => "Nest REST Controller".Equals(c.Technology)).ToList().ForEach(c => webApplication.Uses(c, "Uses", "HTTPS")); restApi.Components.Where(c => "Nest REST Controller".Equals(c.Technology)).ToList().ForEach(c => webApplicationVue.Uses(c, "Uses", "HTTPS")); restApi.Components.Where(c => "Nest REST Controller".Equals(c.Technology)).ToList().ForEach(c => webApplicationAngular.Uses(c, "Uses", "HTTPS")); // accountsSummaryController.Uses(mainframeBankingSystemFacade, "Uses"); transactionController.Uses(database, "Lee y escribe en", "Typeorm"); signinController.Uses(database, "Lee y escribe en", "Typeorm"); accountsSummaryController.Uses(database, "Lee y escribe en", "Typeorm"); hearthbeat.Uses(qualityController, "Usa", "https"); ComponentView componentViewForRestApi = viewSet.CreateComponentView(restApi, "Components", "The components diagram for the REST API"); componentViewForRestApi.PaperSize = PaperSize.A4_Landscape; componentViewForRestApi.AddAllContainers(); componentViewForRestApi.AddAllComponents(); componentViewForRestApi.Add(cliente); //componentViewForRestApi.EnableAutomaticLayout(); structurizrClient.UnlockWorkspace(workspaceId); structurizrClient.PutWorkspace(workspaceId, workspace); }
static void Main(string[] args) { Workspace workspace = new Workspace("Contoso University", "A software architecture model of the Contoso University sample project."); Model model = workspace.Model; ViewSet views = workspace.Views; Styles styles = views.Configuration.Styles; Person universityStaff = model.AddPerson("University Staff", "A staff member of the Contoso University."); SoftwareSystem contosoUniversity = model.AddSoftwareSystem("Contoso University", "Allows staff to view and update student, course, and instructor information."); universityStaff.Uses(contosoUniversity, "uses"); // if the client-side of this application was richer (e.g. it was a single-page app), I would include the web browser // as a container (i.e. User --uses-> Web Browser --uses-> Web Application (backend for frontend) --uses-> Database) Container webApplication = contosoUniversity.AddContainer("Web Application", "Allows staff to view and update student, course, and instructor information.", "Microsoft ASP.NET MVC"); Container database = contosoUniversity.AddContainer("Database", "Stores information about students, courses and instructors", "Microsoft SQL Server Express LocalDB"); database.AddTags("Database"); universityStaff.Uses(webApplication, "Uses", "HTTPS"); webApplication.Uses(database, "Reads from and writes to"); Assembly.LoadFrom("C:\\Users\\simon\\ContosoUniversity\\ContosoUniversity\\bin\\ContosoUniversity.dll"); ComponentFinder componentFinder = new ComponentFinder( webApplication, "ContosoUniversity", //typeof(ContosoUniversity.MvcApplication).Namespace, // doing this typeof forces the ContosoUniversity assembly to be loaded new TypeBasedComponentFinderStrategy( new InterfaceImplementationTypeMatcher(typeof(System.Web.Mvc.IController), null, "ASP.NET MVC Controller"), new ExtendsClassTypeMatcher(typeof(System.Data.Entity.DbContext), null, "Entity Framework DbContext") ) //new TypeSummaryComponentFinderStrategy(@"C:\Users\simon\ContosoUniversity\ContosoUniversity.sln", "ContosoUniversity") ); componentFinder.FindComponents(); // connect the user to the web MVC controllers webApplication.Components.ToList().FindAll(c => c.Technology == "ASP.NET MVC Controller").ForEach(c => universityStaff.Uses(c, "uses")); // connect all DbContext components to the database webApplication.Components.ToList().FindAll(c => c.Technology == "Entity Framework DbContext").ForEach(c => c.Uses(database, "Reads from and writes to")); // link the components to the source code foreach (Component component in webApplication.Components) { foreach (CodeElement codeElement in component.Code) { if (codeElement.Url != null) { codeElement.Url = codeElement.Url.Replace(new Uri(@"C:\Users\simon\ContosoUniversity\").AbsoluteUri, "https://github.com/simonbrowndotje/ContosoUniversity/blob/master/"); codeElement.Url = codeElement.Url.Replace('\\', '/'); } } } // rather than creating a component model for the database, let's simply link to the DDL // (this is really just an example of linking an arbitrary element in the model to an external resource) database.Url = "https://github.com/simonbrowndotje/ContosoUniversity/tree/master/ContosoUniversity/Migrations"; SystemContextView contextView = views.CreateSystemContextView(contosoUniversity, "Context", "The system context view for the Contoso University system."); contextView.AddAllElements(); ContainerView containerView = views.CreateContainerView(contosoUniversity, "Containers", "The containers that make up the Contoso University system."); containerView.AddAllElements(); ComponentView componentView = views.CreateComponentView(webApplication, "Components", "The components inside the Contoso University web application."); componentView.AddAllElements(); // create an example dynamic view for a feature DynamicView dynamicView = views.CreateDynamicView(webApplication, "GetCoursesForDepartment", "A summary of the \"get courses for department\" feature."); Component courseController = webApplication.GetComponentWithName("CourseController"); Component schoolContext = webApplication.GetComponentWithName("SchoolContext"); dynamicView.Add(universityStaff, "Requests the list of courses from", courseController); dynamicView.Add(courseController, "Uses", schoolContext); dynamicView.Add(schoolContext, "Gets a list of courses from", database); // add some styling styles.Add(new ElementStyle(Tags.Person) { Background = "#0d4d4d", Color = "#ffffff", Shape = Shape.Person }); styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#003333", Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.Container) { Background = "#226666", Color = "#ffffff" }); styles.Add(new ElementStyle("Database") { Shape = Shape.Cylinder }); styles.Add(new ElementStyle(Tags.Component) { Background = "#407f7f", Color = "#ffffff" }); StructurizrClient structurizrClient = new StructurizrClient("key", "secret"); structurizrClient.PutWorkspace(5651, workspace); }
static void Main() { Workspace workspace = new Workspace("Microservices example", "An example of a microservices architecture, which includes asynchronous and parallel behaviour."); Model model = workspace.Model; SoftwareSystem mySoftwareSystem = model.AddSoftwareSystem("Customer Information System", "Stores information "); Person customer = model.AddPerson("Customer", "A customer"); Container customerApplication = mySoftwareSystem.AddContainer("Customer Application", "Allows customers to manage their profile.", "Angular"); Container customerService = mySoftwareSystem.AddContainer("Customer Service", "The point of access for customer information.", "Java and Spring Boot"); customerService.AddTags(MicroserviceTag); Container customerDatabase = mySoftwareSystem.AddContainer("Customer Database", "Stores customer information.", "Oracle 12c"); customerDatabase.AddTags(DataStoreTag); Container reportingService = mySoftwareSystem.AddContainer("Reporting Service", "Creates normalised data for reporting purposes.", "Ruby"); reportingService.AddTags(MicroserviceTag); Container reportingDatabase = mySoftwareSystem.AddContainer("Reporting Database", "Stores a normalised version of all business data for ad hoc reporting purposes.", "MySQL"); reportingDatabase.AddTags(DataStoreTag); Container auditService = mySoftwareSystem.AddContainer("Audit Service", "Provides organisation-wide auditing facilities.", "C# .NET"); auditService.AddTags(MicroserviceTag); Container auditStore = mySoftwareSystem.AddContainer("Audit Store", "Stores information about events that have happened.", "Event Store"); auditStore.AddTags(DataStoreTag); Container messageBus = mySoftwareSystem.AddContainer("Message Bus", "Transport for business events.", "RabbitMQ"); messageBus.AddTags(MessageBusTag); customer.Uses(customerApplication, "Uses"); customerApplication.Uses(customerService, "Updates customer information using", "JSON/HTTPS", InteractionStyle.Synchronous); customerService.Uses(messageBus, "Sends customer update events to", "", InteractionStyle.Asynchronous); customerService.Uses(customerDatabase, "Stores data in", "JDBC", InteractionStyle.Synchronous); customerService.Uses(customerApplication, "Sends events to", "WebSocket", InteractionStyle.Asynchronous); messageBus.Uses(reportingService, "Sends customer update events to", "", InteractionStyle.Asynchronous); messageBus.Uses(auditService, "Sends customer update events to", "", InteractionStyle.Asynchronous); reportingService.Uses(reportingDatabase, "Stores data in", "", InteractionStyle.Synchronous); auditService.Uses(auditStore, "Stores events in", "", InteractionStyle.Synchronous); ViewSet views = workspace.Views; ContainerView containerView = views.CreateContainerView(mySoftwareSystem, "Containers", null); containerView.AddAllElements(); DynamicView dynamicView = views.CreateDynamicView(mySoftwareSystem, "CustomerUpdateEvent", "This diagram shows what happens when a customer updates their details."); dynamicView.Add(customer, customerApplication); dynamicView.Add(customerApplication, customerService); dynamicView.Add(customerService, customerDatabase); dynamicView.Add(customerService, messageBus); dynamicView.StartParallelSequence(); dynamicView.Add(messageBus, reportingService); dynamicView.Add(reportingService, reportingDatabase); dynamicView.EndParallelSequence(); dynamicView.StartParallelSequence(); dynamicView.Add(messageBus, auditService); dynamicView.Add(auditService, auditStore); dynamicView.EndParallelSequence(); dynamicView.StartParallelSequence(); dynamicView.Add(customerService, "Confirms update to", customerApplication); dynamicView.EndParallelSequence(); Styles styles = views.Configuration.Styles; styles.Add(new ElementStyle(Tags.Element) { Color = "#000000" }); styles.Add(new ElementStyle(Tags.Person) { Background = "#ffbf00", Shape = Shape.Person }); styles.Add(new ElementStyle(Tags.Container) { Background = "#facc2E" }); styles.Add(new ElementStyle(MessageBusTag) { Width = 1600, Shape = Shape.Pipe }); styles.Add(new ElementStyle(MicroserviceTag) { Shape = Shape.Hexagon }); styles.Add(new ElementStyle(DataStoreTag) { Background = "#f5da81", Shape = Shape.Cylinder }); styles.Add(new RelationshipStyle(Tags.Relationship) { Routing = Routing.Orthogonal }); styles.Add(new RelationshipStyle(Tags.Asynchronous) { Dashed = true }); styles.Add(new RelationshipStyle(Tags.Synchronous) { Dashed = false }); StructurizrClient structurizrClient = new StructurizrClient(ApiKey, ApiSecret); structurizrClient.PutWorkspace(WorkspaceId, workspace); }
static void Main(string[] args) { Workspace workspace = new Workspace("Architectural Kata: Make the Grade", "This is a model of the solution to the architectural kata \"Make the Grade\", found at http://nealford.com/katas/list.html."); #region Models Model model = workspace.Model; Person student = model.AddPerson("Student", "A student undertaking a test."); Person grader = model.AddPerson("Grader", "A grader assessing the sudents' test answers."); Person admin = model.AddPerson("Administrator", "A representative of the state authority in education."); SoftwareSystem resultsRepoSubSystem = model.AddSoftwareSystem("Results Repository", "Single location representing all of the test scores across the state."); admin.Uses(resultsRepoSubSystem, "Extracts grading reports."); SoftwareSystem testsCatalogueSubSystem = model.AddSoftwareSystem("Tests Catalogue", "Authoritative source for tests and grading rules."); admin.Uses(testsCatalogueSubSystem, "Administers tests."); SoftwareSystem localTestUnitSubSystem = model.AddSoftwareSystem("Local Testing Unit", "On-premises testing subsystem deployed in each testing center."); student.Uses(localTestUnitSubSystem, "Undertakes tests"); grader.Uses(localTestUnitSubSystem, "Grades students"); localTestUnitSubSystem.Uses(resultsRepoSubSystem, "Push results (batch)"); localTestUnitSubSystem.Uses(testsCatalogueSubSystem, "Pull tests"); Container resultsRepo = resultsRepoSubSystem.AddContainer("Results Database", "Single location representing all of the test scores across the state.", "Microsoft Azure SQL Database"); resultsRepo.AddTags("Database"); Container reportingService = resultsRepoSubSystem.AddContainer("Reporting Service", "A reporting system to know which students have taken the tests and what score they received.", "ASP.NET single page app"); reportingService.Uses(resultsRepo, "Reads from"); Container testsCatalogueService = testsCatalogueSubSystem.AddContainer("Catalogue Service", "Web API provider of latest test and grading rules.", "ASP.NET Web API microservice"); Container testsCatalogueFrontEnd = testsCatalogueSubSystem.AddContainer("Catalogue Front End", "Front end application for administrators managing tests.", "ASP.NET MVC web app"); Container testsRepo = testsCatalogueSubSystem.AddContainer("Tests Repository", "Stores test questions, answers and grading rules.", "NoSQL DBMS"); testsRepo.AddTags("Database"); testsCatalogueFrontEnd.Uses(testsRepo, "Reads from and writes to"); testsCatalogueService.Uses(testsRepo, "Reads from"); Container locatTestResultsStorage = localTestUnitSubSystem.AddContainer("Local Tests Storage", "Stores test answers and grades for students from local testing unit.", "MySQL database"); locatTestResultsStorage.AddTags("Database"); Container testingApp = localTestUnitSubSystem.AddContainer("Testing application", "Allows students to undertake tests and graders to assess them.", "AngularJS web app"); Container testResultQueue = localTestUnitSubSystem.AddContainer("Test results queue", "Asynchronous queue on which an event is placed when a student finishes a test, so that a grader can be notified.", "RabbitMQ"); testResultQueue.AddTags("Queue"); Container evaluator = localTestUnitSubSystem.AddContainer("Evaluator", "Retrieves a finished test, grades the multiple choice answers and gives manual control to graders", ""); Container synchronizer = localTestUnitSubSystem.AddContainer("Synchronizer", "Uploads local test results to central repository", "WCF service"); synchronizer.Uses(resultsRepoSubSystem, "Push results (batch)"); synchronizer.Uses(locatTestResultsStorage, "Read from"); testingApp.Uses(testResultQueue, "Undertake test"); testingApp.Uses(testsCatalogueSubSystem, "Pull tests"); testResultQueue.Uses(evaluator, "Notify grader"); evaluator.Uses(locatTestResultsStorage, "Store and read results"); evaluator.Uses(testsCatalogueSubSystem, "Pull tests"); #endregion #region Views var layoutWorkspace = WorkspaceUtils.LoadWorkspaceFromJson(new FileInfo("layout.json")); ViewSet viewSet = workspace.Views; SystemContextView contextView = viewSet.CreateSystemContextView(testsCatalogueSubSystem, "SystemContext", "A system used for standardized testing across all public school systems grades 3-12."); contextView.AddAllSoftwareSystems(); contextView.AddAllPeople(); contextView.AddNearestNeighbours(testsCatalogueSubSystem); contextView.CopyLayoutInformationFrom(layoutWorkspace.Views.SystemContextViews.FirstOrDefault(x => x.Key == "SystemContext")); ContainerView resultsContainerView = viewSet.CreateContainerView(resultsRepoSubSystem, "ResultsContainer", "The container diagram for the Results Repository Subsystem."); admin.Uses(reportingService, "Extracts reports"); resultsContainerView.Add(admin); resultsContainerView.AddAllContainers(); resultsContainerView.CopyLayoutInformationFrom(layoutWorkspace.Views.ContainerViews.FirstOrDefault(x => x.Key == "ResultsContainer")); ContainerView testsContainerView = viewSet.CreateContainerView(testsCatalogueSubSystem, "TestsContainers", "The container diagram for the Tests Catalogue Subsystem."); admin.Uses(testsCatalogueFrontEnd, "Administers tests"); testsContainerView.Add(admin); testsContainerView.AddAllContainers(); testsContainerView.CopyLayoutInformationFrom(layoutWorkspace.Views.ContainerViews.FirstOrDefault(x => x.Key == "TestsContainers")); ContainerView testUnitContainerView = viewSet.CreateContainerView(localTestUnitSubSystem, "TestUnitsContainers", "The container diagram for the Local Testing Unit Subsystem."); student.Uses(testingApp, "Undertake test"); grader.Uses(evaluator, "Grade test answers"); testUnitContainerView.Add(student); testUnitContainerView.Add(grader); testUnitContainerView.AddAllContainers(); testUnitContainerView.Add(resultsRepoSubSystem); testUnitContainerView.Add(testsCatalogueSubSystem); testUnitContainerView.CopyLayoutInformationFrom(layoutWorkspace.Views.ContainerViews.FirstOrDefault(x => x.Key == "TestUnitsContainers")); Styles styles = viewSet.Configuration.Styles; styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#1168bd", Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.Person) { Background = "#08427b", Color = "#ffffff", Shape = Shape.Person }); styles.Add(new ElementStyle("Database") { Shape = Shape.Cylinder }); styles.Add(new ElementStyle("Queue") { Shape = Shape.Ellipse }); #endregion PushWorkspace(workspace); }
static void Banking() { const long workspaceId = 0; const string apiKey = ""; const string apiSecret = ""; StructurizrClient structurizrClient = new StructurizrClient(apiKey, apiSecret); Workspace workspace = new Workspace("Software Design & Patterns - C4 Model - Sistema de Monitoreo", "Sistema de Monitoreo del Traslado Aéreo de Vacunas SARS-CoV-2"); ViewSet viewSet = workspace.Views; Model model = workspace.Model; // 1. Diagrama de Contexto SoftwareSystem monitoringSystem = model.AddSoftwareSystem("Monitoreo del Traslado Aéreo de Vacunas SARS-CoV-2", "Permite el seguimiento y monitoreo del traslado aéreo a nuestro país de las vacunas para la COVID-19."); SoftwareSystem googleMaps = model.AddSoftwareSystem("Google Maps", "Plataforma que ofrece una REST API de información geo referencial."); SoftwareSystem aircraftSystem = model.AddSoftwareSystem("Aircraft System", "Permite transmitir información en tiempo real por el avión del vuelo a nuestro sistema"); Person ciudadano = model.AddPerson("Ciudadano", "Ciudadano peruano."); ciudadano.Uses(monitoringSystem, "Realiza consultas para mantenerse al tanto de la planificación de los vuelos hasta la llegada del lote de vacunas al Perú"); monitoringSystem.Uses(aircraftSystem, "Consulta información en tiempo real por el avión del vuelo"); monitoringSystem.Uses(googleMaps, "Usa la API de google maps"); SystemContextView contextView = viewSet.CreateSystemContextView(monitoringSystem, "Contexto", "Diagrama de contexto"); contextView.PaperSize = PaperSize.A4_Landscape; contextView.AddAllSoftwareSystems(); contextView.AddAllPeople(); // Tags ciudadano.AddTags("Ciudadano"); monitoringSystem.AddTags("SistemaMonitoreo"); googleMaps.AddTags("GoogleMaps"); aircraftSystem.AddTags("AircraftSystem"); Styles styles = viewSet.Configuration.Styles; styles.Add(new ElementStyle("Ciudadano") { Background = "#0a60ff", Color = "#ffffff", Shape = Shape.Person }); styles.Add(new ElementStyle("SistemaMonitoreo") { Background = "#008f39", Color = "#ffffff", Shape = Shape.RoundedBox }); styles.Add(new ElementStyle("GoogleMaps") { Background = "#90714c", Color = "#ffffff", Shape = Shape.RoundedBox }); styles.Add(new ElementStyle("AircraftSystem") { Background = "#2f95c7", Color = "#ffffff", Shape = Shape.RoundedBox }); // 2. Diagrama de Contenedores Container mobileApplication = monitoringSystem.AddContainer("Mobile App", "Permite a los usuarios visualizar un dashboard con el resumen de toda la información del traslado de los lotes de vacunas.", "Flutter"); Container webApplication = monitoringSystem.AddContainer("Web App", "Permite a los usuarios visualizar un dashboard con el resumen de toda la información del traslado de los lotes de vacunas.", "Flutter Web"); Container landingPage = monitoringSystem.AddContainer("Landing Page", "", "Flutter Web"); Container apiRest = monitoringSystem.AddContainer("API Rest", "API Rest", "NodeJS (NestJS) port 8080"); Container flightPlanningContext = monitoringSystem.AddContainer("Flight Planning Context", "Bounded Context del Microservicio de Planificación de Vuelos", "NodeJS (NestJS)"); Container airportContext = monitoringSystem.AddContainer("Airport Context", "Bounded Context del Microservicio de información de Aeropuertos", "NodeJS (NestJS)"); Container aircraftInventoryContext = monitoringSystem.AddContainer("Aircraft Inventory Context", "Bounded Context del Microservicio de Inventario de Aviones", "NodeJS (NestJS)"); Container vaccinesInventoryContext = monitoringSystem.AddContainer("Vaccines Inventory Context", "Bounded Context del Microservicio de Inventario de Vacunas", "NodeJS (NestJS)"); Container monitoringContext = monitoringSystem.AddContainer("Monitoring Context", "Bounded Context del Microservicio de Monitoreo en tiempo real del status y ubicación del vuelo que transporta las vacunas", "NodeJS (NestJS)"); Container database = monitoringSystem.AddContainer("Database", "", "Oracle"); ciudadano.Uses(mobileApplication, "Consulta"); ciudadano.Uses(webApplication, "Consulta"); ciudadano.Uses(landingPage, "Consulta"); mobileApplication.Uses(apiRest, "API Request", "JSON/HTTPS"); webApplication.Uses(apiRest, "API Request", "JSON/HTTPS"); apiRest.Uses(flightPlanningContext, "", ""); apiRest.Uses(airportContext, "", ""); apiRest.Uses(aircraftInventoryContext, "", ""); apiRest.Uses(vaccinesInventoryContext, "", ""); apiRest.Uses(monitoringContext, "", ""); flightPlanningContext.Uses(database, "", "JDBC"); airportContext.Uses(database, "", "JDBC"); aircraftInventoryContext.Uses(database, "", "JDBC"); vaccinesInventoryContext.Uses(database, "", "JDBC"); monitoringContext.Uses(database, "", "JDBC"); monitoringContext.Uses(googleMaps, "API Request", "JSON/HTTPS"); monitoringContext.Uses(aircraftSystem, "API Request", "JSON/HTTPS"); // Tags mobileApplication.AddTags("MobileApp"); webApplication.AddTags("WebApp"); landingPage.AddTags("LandingPage"); apiRest.AddTags("APIRest"); database.AddTags("Database"); flightPlanningContext.AddTags("FlightPlanningContext"); airportContext.AddTags("AirportContext"); aircraftInventoryContext.AddTags("AircraftInventoryContext"); vaccinesInventoryContext.AddTags("VaccinesInventoryContext"); monitoringContext.AddTags("MonitoringContext"); styles.Add(new ElementStyle("MobileApp") { Background = "#9d33d6", Color = "#ffffff", Shape = Shape.MobileDevicePortrait, Icon = "" }); styles.Add(new ElementStyle("WebApp") { Background = "#9d33d6", Color = "#ffffff", Shape = Shape.WebBrowser, Icon = "" }); styles.Add(new ElementStyle("LandingPage") { Background = "#929000", Color = "#ffffff", Shape = Shape.WebBrowser, Icon = "" }); styles.Add(new ElementStyle("APIRest") { Shape = Shape.RoundedBox, Background = "#0000ff", Color = "#ffffff", Icon = "" }); styles.Add(new ElementStyle("Database") { Shape = Shape.Cylinder, Background = "#ff0000", Color = "#ffffff", Icon = "" }); styles.Add(new ElementStyle("FlightPlanningContext") { Shape = Shape.Hexagon, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("AirportContext") { Shape = Shape.Hexagon, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("AircraftInventoryContext") { Shape = Shape.Hexagon, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("VaccinesInventoryContext") { Shape = Shape.Hexagon, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("MonitoringContext") { Shape = Shape.Hexagon, Background = "#facc2e", Icon = "" }); ContainerView containerView = viewSet.CreateContainerView(monitoringSystem, "Contenedor", "Diagrama de contenedores"); contextView.PaperSize = PaperSize.A4_Landscape; containerView.AddAllElements(); // 3. Diagrama de Componentes Component domainLayer = monitoringContext.AddComponent("Domain Layer", "", "NodeJS (NestJS)"); Component monitoringController = monitoringContext.AddComponent("Monitoring Controller", "REST API endpoints de monitoreo.", "NodeJS (NestJS) REST Controller"); Component monitoringApplicationService = monitoringContext.AddComponent("Monitoring Application Service", "Provee métodos para el monitoreo, pertenece a la capa Application de DDD", "NestJS Component"); Component flightRepository = monitoringContext.AddComponent("Flight Repository", "Información del vuelo", "NestJS Component"); Component vaccineLoteRepository = monitoringContext.AddComponent("VaccineLote Repository", "Información de lote de vacunas", "NestJS Component"); Component locationRepository = monitoringContext.AddComponent("Location Repository", "Ubicación del vuelo", "NestJS Component"); Component aircraftSystemFacade = monitoringContext.AddComponent("Aircraft System Facade", "", "NestJS Component"); apiRest.Uses(monitoringController, "", "JSON/HTTPS"); monitoringController.Uses(monitoringApplicationService, "Invoca métodos de monitoreo"); monitoringController.Uses(aircraftSystemFacade, "Usa"); monitoringApplicationService.Uses(domainLayer, "Usa", ""); monitoringApplicationService.Uses(flightRepository, "", "JDBC"); monitoringApplicationService.Uses(vaccineLoteRepository, "", "JDBC"); monitoringApplicationService.Uses(locationRepository, "", "JDBC"); flightRepository.Uses(database, "", "JDBC"); vaccineLoteRepository.Uses(database, "", "JDBC"); locationRepository.Uses(database, "", "JDBC"); locationRepository.Uses(googleMaps, "", "JSON/HTTPS"); aircraftSystemFacade.Uses(aircraftSystem, "JSON/HTTPS"); // Tags domainLayer.AddTags("DomainLayer"); monitoringController.AddTags("MonitoringController"); monitoringApplicationService.AddTags("MonitoringApplicationService"); flightRepository.AddTags("FlightRepository"); vaccineLoteRepository.AddTags("VaccineLoteRepository"); locationRepository.AddTags("LocationRepository"); aircraftSystemFacade.AddTags("AircraftSystemFacade"); styles.Add(new ElementStyle("DomainLayer") { Shape = Shape.Component, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("MonitoringController") { Shape = Shape.Component, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("MonitoringApplicationService") { Shape = Shape.Component, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("MonitoringDomainModel") { Shape = Shape.Component, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("FlightStatus") { Shape = Shape.Component, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("FlightRepository") { Shape = Shape.Component, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("VaccineLoteRepository") { Shape = Shape.Component, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("LocationRepository") { Shape = Shape.Component, Background = "#facc2e", Icon = "" }); styles.Add(new ElementStyle("AircraftSystemFacade") { Shape = Shape.Component, Background = "#facc2e", Icon = "" }); ComponentView componentView = viewSet.CreateComponentView(monitoringContext, "Components", "Component Diagram"); componentView.PaperSize = PaperSize.A4_Landscape; componentView.Add(mobileApplication); componentView.Add(webApplication); componentView.Add(apiRest); componentView.Add(database); componentView.Add(aircraftSystem); componentView.Add(googleMaps); componentView.AddAllComponents(); structurizrClient.UnlockWorkspace(workspaceId); structurizrClient.PutWorkspace(workspaceId, workspace); }