public void Test_AddNearestNeighbours_AddsNearestNeighbours_WhenThereAreSomeNearestNeighbours() { SoftwareSystem softwareSystemA = model.AddSoftwareSystem("System A", "Description"); SoftwareSystem softwareSystemB = model.AddSoftwareSystem("System B", "Description"); Person userA = model.AddPerson("User A", "Description"); Person userB = model.AddPerson("User B", "Description"); // userA -> systemA -> system -> systemB -> userB userA.Uses(softwareSystemA, ""); softwareSystemA.Uses(softwareSystem, ""); softwareSystem.Uses(softwareSystemB, ""); softwareSystemB.Delivers(userB, ""); // userA -> systemA -> web application -> systemB -> userB // web application -> database Container webApplication = softwareSystem.AddContainer("Web Application", "", ""); Container database = softwareSystem.AddContainer("Database", "", ""); softwareSystemA.Uses(webApplication, ""); webApplication.Uses(softwareSystemB, ""); webApplication.Uses(database, ""); // userA -> systemA -> controller -> service -> repository -> database Component controller = webApplication.AddComponent("Controller", ""); Component service = webApplication.AddComponent("Service", ""); Component repository = webApplication.AddComponent("Repository", ""); softwareSystemA.Uses(controller, ""); controller.Uses(service, ""); service.Uses(repository, ""); repository.Uses(database, ""); // userA -> systemA -> controller -> service -> systemB -> userB service.Uses(softwareSystemB, ""); view.AddNearestNeighbours(softwareSystem); Assert.AreEqual(3, view.Elements.Count); Assert.IsTrue(view.Elements.Contains(new ElementView(softwareSystemA))); Assert.IsTrue(view.Elements.Contains(new ElementView(softwareSystem))); Assert.IsTrue(view.Elements.Contains(new ElementView(softwareSystemB))); view = new SystemContextView(softwareSystem, "context", "Description"); view.AddNearestNeighbours(softwareSystemA); Assert.AreEqual(3, view.Elements.Count); Assert.IsTrue(view.Elements.Contains(new ElementView(userA))); Assert.IsTrue(view.Elements.Contains(new ElementView(softwareSystemA))); Assert.IsTrue(view.Elements.Contains(new ElementView(softwareSystem))); }
static void Main() { Workspace workspace = new Workspace("Widgets Limited", "Sells widgets to customers online."); Model model = workspace.Model; ViewSet views = workspace.Views; Styles styles = views.Configuration.Styles; model.Enterprise = new Enterprise("Widgets Limited"); Person customer = model.AddPerson(Location.External, "Customer", "A customer of Widgets Limited."); Person customerServiceUser = model.AddPerson(Location.Internal, "Customer Service Agent", "Deals with customer enquiries."); SoftwareSystem ecommerceSystem = model.AddSoftwareSystem(Location.Internal, "E-commerce System", "Allows customers to buy widgets online via the widgets.com website."); SoftwareSystem fulfilmentSystem = model.AddSoftwareSystem(Location.Internal, "Fulfilment System", "Responsible for processing and shipping of customer orders."); SoftwareSystem taxamo = model.AddSoftwareSystem(Location.External, "Taxamo", "Calculates local tax (for EU B2B customers) and acts as a front-end for Braintree Payments."); taxamo.Url = "https://www.taxamo.com"; SoftwareSystem braintreePayments = model.AddSoftwareSystem(Location.External, "Braintree Payments", "Processes credit card payments on behalf of Widgets Limited."); braintreePayments.Url = "https://www.braintreepayments.com"; SoftwareSystem jerseyPost = model.AddSoftwareSystem(Location.External, "Jersey Post", "Calculates worldwide shipping costs for packages."); model.People.Where(p => p.Location == Location.External).ToList().ForEach(p => p.AddTags(ExternalTag)); model.People.Where(p => p.Location == Location.Internal).ToList().ForEach(p => p.AddTags(InternalTag)); model.SoftwareSystems.Where(ss => ss.Location == Location.External).ToList().ForEach(ss => ss.AddTags(ExternalTag)); model.SoftwareSystems.Where(ss => ss.Location == Location.Internal).ToList().ForEach(ss => ss.AddTags(InternalTag)); customer.InteractsWith(customerServiceUser, "Asks questions to", "Telephone"); customerServiceUser.Uses(ecommerceSystem, "Looks up order information using"); customer.Uses(ecommerceSystem, "Places orders for widgets using"); ecommerceSystem.Uses(fulfilmentSystem, "Sends order information to"); fulfilmentSystem.Uses(jerseyPost, "Gets shipping charges from"); ecommerceSystem.Uses(taxamo, "Delegates credit card processing to"); taxamo.Uses(braintreePayments, "Uses for credit card processing"); EnterpriseContextView enterpriseContextView = views.CreateEnterpriseContextView("EnterpriseContext", "The enterprise context for Widgets Limited."); enterpriseContextView.AddAllElements(); SystemContextView ecommerceSystemContext = views.CreateSystemContextView(ecommerceSystem, "EcommerceSystemContext", "The system context diagram for the Widgets Limited e-commerce system."); ecommerceSystemContext.AddNearestNeighbours(ecommerceSystem); ecommerceSystemContext.Remove(customer.GetEfferentRelationshipWith(customerServiceUser)); SystemContextView fulfilmentSystemContext = views.CreateSystemContextView(fulfilmentSystem, "FulfilmentSystemContext", "The system context diagram for the Widgets Limited fulfilment system."); fulfilmentSystemContext.AddNearestNeighbours(fulfilmentSystem); DynamicView dynamicView = views.CreateDynamicView("CustomerSupportCall", "A high-level overview of the customer support call process."); dynamicView.Add(customer, customerServiceUser); dynamicView.Add(customerServiceUser, ecommerceSystem); StructurizrDocumentationTemplate template = new StructurizrDocumentationTemplate(workspace); template.AddSection("Enterprise Context", 1, Format.Markdown, "Here is some information about the Widgets Limited enterprise context... ![](embed:EnterpriseContext)"); template.AddContextSection(ecommerceSystem, Format.Markdown, "This is the context section for the E-commerce System... ![](embed:EcommerceSystemContext)"); template.AddContextSection(fulfilmentSystem, Format.Markdown, "This is the context section for the Fulfilment System... ![](embed:FulfilmentSystemContext)"); styles.Add(new ElementStyle(Tags.SoftwareSystem) { Shape = Shape.RoundedBox }); styles.Add(new ElementStyle(Tags.Person) { Shape = Shape.Person }); styles.Add(new ElementStyle(Tags.Element) { Color = "#ffffff" }); styles.Add(new ElementStyle(ExternalTag) { Background = "#EC5381", Border = Border.Dashed }); styles.Add(new ElementStyle(InternalTag) { Background = "#B60037" }); StructurizrClient structurizrClient = new StructurizrClient(ApiKey, ApiSecret); structurizrClient.PutWorkspace(WorkspaceId, workspace); }
public static Workspace Create() { 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."); internetBankingSystem.Uses(emailSystem, "Sends e-mail using"); 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 to the customer's web browser", ""); 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 resetPasswordController = apiApplication.AddComponent("Reset Password Controller", "Allows users to reset their passwords with a single use URL.", "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"); Component emailComponent = apiApplication.AddComponent("E-mail Component", "Sends e-mails to users.", "Spring Bean"); apiApplication.Components.Where(c => "Spring MVC Rest Controller".Equals(c.Technology)).ToList().ForEach(c => singlePageApplication.Uses(c, "Makes API calls to", "JSON/HTTPS")); apiApplication.Components.Where(c => "Spring MVC Rest Controller".Equals(c.Technology)).ToList().ForEach(c => mobileApp.Uses(c, "Makes API calls to", "JSON/HTTPS")); signinController.Uses(securityComponent, "Uses"); accountsSummaryController.Uses(mainframeBankingSystemFacade, "Uses"); resetPasswordController.Uses(securityComponent, "Uses"); resetPasswordController.Uses(emailComponent, "Uses"); securityComponent.Uses(database, "Reads from and writes to", "JDBC"); mainframeBankingSystemFacade.Uses(mainframeBankingSystem, "Uses", "XML/HTTPS"); emailComponent.Uses(emailSystem, "Sends e-mail using"); model.AddImplicitRelationships(); // deployment nodes and container instances DeploymentNode developerLaptop = model.AddDeploymentNode("Development", "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", "", "Chrome, Firefox, Safari, or Edge").Add(singlePageApplication); DeploymentNode customerMobileDevice = model.AddDeploymentNode("Live", "Customer's mobile device", "", "Apple iOS or Android"); customerMobileDevice.Add(mobileApp); DeploymentNode customerComputer = model.AddDeploymentNode("Live", "Customer's computer", "", "Microsoft Windows or Apple macOS"); customerComputer.AddDeploymentNode("Web Browser", "", "Chrome, Firefox, Safari, or Edge").Add(singlePageApplication); DeploymentNode bigBankDataCenter = model.AddDeploymentNode("Live", "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 bigBankdb02 = bigBankDataCenter.AddDeploymentNode("bigbank-db02", "The secondary database server.", "Ubuntu 16.04 LTS", 1, DictionaryUtils.Create("Location=Reading")); bigBankdb02.AddTags(FailoverTag); DeploymentNode secondaryDatabaseServer = bigBankdb02.AddDeploymentNode("Oracle - Secondary", "A secondary, standby database server, used for failover purposes only.", "Oracle 12c"); secondaryDatabaseServer.AddTags(FailoverTag); 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.Add(emailSystem); componentView.PaperSize = PaperSize.A5_Landscape; systemLandscapeView.AddAnimation(internetBankingSystem, customer, mainframeBankingSystem, emailSystem); systemLandscapeView.AddAnimation(atm); systemLandscapeView.AddAnimation(customerServiceStaff, backOfficeStaff); systemContextView.AddAnimation(internetBankingSystem); systemContextView.AddAnimation(customer); systemContextView.AddAnimation(mainframeBankingSystem); systemContextView.AddAnimation(emailSystem); containerView.AddAnimation(customer, mainframeBankingSystem, emailSystem); containerView.AddAnimation(webApplication); containerView.AddAnimation(singlePageApplication); containerView.AddAnimation(mobileApp); containerView.AddAnimation(apiApplication); containerView.AddAnimation(database); componentView.AddAnimation(singlePageApplication, mobileApp); componentView.AddAnimation(signinController, securityComponent, database); componentView.AddAnimation(accountsSummaryController, mainframeBankingSystemFacade, mainframeBankingSystem); componentView.AddAnimation(resetPasswordController, emailComponent, database); // 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.SoftwareSystem) { Background = "#1168bd", Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.Container) { Background = "#438dd5", Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.Component) { Background = "#85bbf0", Color = "#000000" }); styles.Add(new ElementStyle(Tags.Person) { Background = "#08427b", Color = "#ffffff", Shape = Shape.Person, FontSize = 22 }); styles.Add(new ElementStyle(ExistingSystemTag) { Background = "#999999", Color = "#ffffff" }); styles.Add(new ElementStyle(BankStaffTag) { Background = "#999999", Color = "#ffffff" }); 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 }); // 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:SystemLandscape)\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 API 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); }
public void Test_AddNearestNeightbours_DoesNothing_WhenANullElementIsSpecified() { view.AddNearestNeighbours(null); Assert.AreEqual(1, view.Elements.Count); }
private const string DATABASE_TAG = "database"; // analizar el uso static void Main(string[] args) { // Crear el nuevo espacio de trabajo Workspace workspace = new Workspace("Arquitectura de Software - Plataforma de Gestion y Monitoreo de Transporte de Carga", "Diseño de la arquitectura de software de proyectos de transformacion digital"); Model model = workspace.Model; model.Enterprise = new Enterprise("Transport Manangement System"); // Agregar los elementos que contendra el sistema Person userCompany = model.AddPerson(Location.External, "Empresa", "Empresa que adquiere los servicios de la plataforma de gestion y seguimiento de transporte de carga"); Person userDriver = model.AddPerson(Location.External, "Chofer", "Persona encargada que transporta la carga de los clientes administrando el flujo de la operacion"); Person userOperator = model.AddPerson(Location.External, "Operador", "Persona encargada de adminstrar y monitorear las operaciones"); Person userClient = model.AddPerson(Location.External, "Cliente", "Persona interesada en realizar el seguimiento de su carga"); // SoftwareSystem tmsSoftwareSystem = model.AddSoftwareSystem(Location.Internal, "TMS Generico", "Plataforma de Gestion y Seguimiento del transporte y logistica de Carga a Nivel Nacional"); SoftwareSystem odooErpSoftwareSystem = model.AddSoftwareSystem(Location.Internal, "Odoo Sh", "ERP: Sistema de Planificacion de Recursos Empresariales"); SoftwareSystem mailServerSoftwareSystem = model.AddSoftwareSystem(Location.Internal, "Servidor de Correos", "Servidor de Correos Interno Microsoft Exchange"); SoftwareSystem fcmSoftwareSystem = model.AddSoftwareSystem(Location.Internal, "Firebase Cloud Messaging ", "Sistema de mensajeria en tiempo real multiplaforma ofrecido por Google"); SoftwareSystem azureBlobStorageSoftwareSystem = model.AddSoftwareSystem(Location.Internal, "Azure Blob Storage", "Servidor de Almacenamiento de archivos en la nube de Microsft Azure"); SoftwareSystem googlMapsPlatoformSoftwareSystem = model.AddSoftwareSystem(Location.Internal, "Google Maps Plataform", "Plataforma web que ofrece un conjunto de APIs (Aplication Interface Programming) para la gestion de mapas, rutas, direcciones, etc. Soportado por Google"); odooErpSoftwareSystem.AddTags(EXISTS_SYSTEM_TAG); mailServerSoftwareSystem.AddTags(EXISTS_SYSTEM_TAG); fcmSoftwareSystem.AddTags(EXISTS_SYSTEM_TAG); azureBlobStorageSoftwareSystem.AddTags(EXISTS_SYSTEM_TAG); googlMapsPlatoformSoftwareSystem.AddTags(EXISTS_SYSTEM_TAG); tmsSoftwareSystem.Uses(odooErpSoftwareSystem, "Integra la informacion contable de las operaciones de carga"); tmsSoftwareSystem.Uses(fcmSoftwareSystem, "Administra notificaciones y mensajes en tiempo real"); tmsSoftwareSystem.Uses(azureBlobStorageSoftwareSystem, "Administra los archivos generados por el sistema"); tmsSoftwareSystem.Uses(googlMapsPlatoformSoftwareSystem, "Integra los mapas en las aplicaciones"); tmsSoftwareSystem.Uses(mailServerSoftwareSystem, "Envia correos electronicos usando"); fcmSoftwareSystem.Delivers(userDriver, "Envia notificaciones push a la aplicación movil"); mailServerSoftwareSystem.Delivers(userClient, "Envia Correo electronico a"); userCompany.Uses(tmsSoftwareSystem, "Adquiere los servicios de la plataforma, administra y registra sus propias operaciones, choferes, clientes"); userDriver.Uses(tmsSoftwareSystem, "Oferta sus servicios y administra el flujo de la operacion"); userOperator.Uses(tmsSoftwareSystem, "Adminstrar y monitorear las operaciones, oportunidades de carga, operaciones, rutas, clientes y operadores"); userClient.Uses(tmsSoftwareSystem, "Administra sus operaciones y cotizaciones de nuevos servicios"); // Contenendores Container mobileApp = tmsSoftwareSystem.AddContainer("Mobile App", "Provee un conjunto de funcionalidades a los choferes como: postulaciones, notificaciones de posibilidades carga, gestion de operaciones, entre otros", "Flutter"); mobileApp.AddTags(MOBILE_APP_TAG); Container spaOperations = tmsSoftwareSystem.AddContainer("Single-Page Application (Portal Operaciones)", "Provee las funcionalidades de gestion y monitoreo operaciones, oportunidades, rutas de entre otras atraves del navegador web", "Javascript y Angular 9"); spaOperations.AddTags(SINGLE_PAGE_APPLICATION_TAG); Container spaClients = tmsSoftwareSystem.AddContainer("Single-Page Application (Portal Clientes)", "Provee las funcionalidades de seguimiento de operaciones y cotizaciones atraves del navegador web", "Javascript y Angular 9"); spaClients.AddTags(SINGLE_PAGE_APPLICATION_TAG); Container webApplication = tmsSoftwareSystem.AddContainer("Web Application", "Entrega el contenido estático y las Single-Page Application de los Portales de Operaciones y Clientes", "NodeJs y Express Framework"); Container apiTmsServicesApplication = tmsSoftwareSystem.AddContainer("API TMS Application", "Provee las funcionalidades de gestion de informacion para los portales via JSON/HTTPS API", "NodeJs y Express Framework"); Container apiAppServicesApplication = tmsSoftwareSystem.AddContainer("API Mobile Application", "Provee las funcionalidades de gestion de informacion para la aplicacion movil via JSON/HTTPS API", "NodeJs y Express Framework"); Container database = tmsSoftwareSystem.AddContainer("Database", "Almacena y Registra la informacion de la gestion de operaciones y procesos asociados como: Oportunidades, Postulaciones, Autenticacion de Usuarios, etc.", "Microsoft Azure SQL Database"); database.AddTags(DATABASE_TAG); userDriver.Uses(mobileApp, "Visualiza las oportunidades, operaciones, beneficios entre usando", "Flutter"); userOperator.Uses(webApplication, "Visita globaltms.la usando", "HTTPS"); userCompany.Uses(webApplication, "Visita globaltms.la usando", "HTTPS"); userClient.Uses(webApplication, "Visita globaltms.la usando", "HTTPS"); userCompany.Uses(spaOperations, "Administrar sus propias oportunidades, operaciones, rutas, clientes, choferes, entre otros. Usando", "HTTPS"); userOperator.Uses(spaOperations, "Visualiza las oportunidades, operaciones, rutas, clientes, choferes, entre otros. Usando", "HTTPS"); userClient.Uses(spaClients, "Visualiza las operaciones y cotizaciones de nuevos servicios usando", "HTTPS"); webApplication.Uses(spaClients, "Entrega al navegador web del cliente"); webApplication.Uses(spaOperations, "Entrega al navegador web del operador"); spaClients.Uses(googlMapsPlatoformSoftwareSystem, "Integra Mapa de Google en la Aplicacion Web", "HTTPS/XML"); spaOperations.Uses(googlMapsPlatoformSoftwareSystem, "Integra Mapa de Google en la Aplicacion Web", "HTTPS/XML"); mobileApp.Uses(googlMapsPlatoformSoftwareSystem, "Integra Mapa de Google en la Aplicacion Movil", "HTTPS/XML"); apiAppServicesApplication.Uses(database, "Lee y Escribe en", "Tedious MSSQL"); apiTmsServicesApplication.Uses(database, "Lee y Escribe en", "Tedious MSSQL"); apiAppServicesApplication.Uses(azureBlobStorageSoftwareSystem, "Administrar archivos en la nube usando", "HTTPS"); apiTmsServicesApplication.Uses(azureBlobStorageSoftwareSystem, "Administrar archivos en la nube usando", "HTTPS"); apiTmsServicesApplication.Uses(mailServerSoftwareSystem, "Envia correos electronicos usando", "SMTP"); apiTmsServicesApplication.Uses(odooErpSoftwareSystem, "Realiza solicitudes a la API", "HTTP/XML-RPC/JSON-RPC"); apiTmsServicesApplication.Uses(fcmSoftwareSystem, "Emision de mensajes del servidor usando", "HTTPS/JSON"); fcmSoftwareSystem.Uses(mobileApp, "Realiza difusion de los mensajes proveidos por el servidor usando", "HTTPS/JSON"); // EVENTUAL (HASTA AGREGAR LOS COMPONENTES), modificar al momento de agregar los componentes //spaClients.Uses(apiTmsServicesApplication, "Realiza solicitudes a la API", "HTTPS/JSON"); //spaOperations.Uses(apiTmsServicesApplication, "Realiza solicitudes a la API", "HTTPS/JSON"); //mobileApp.Uses(apiAppServicesApplication, "Realiza solicitudes a la API", "HTTPS/JSON"); // Componentes (API APP SERVICES) string expressApiController = "Express API Controller"; // Controllers Component userControllerMobile = apiAppServicesApplication.AddComponent("User Controller", "Permite a los usuarios autenticarse para acceder a la aplicacion movil", "Express API Controller"); Component carrierControllerMobile = apiAppServicesApplication.AddComponent("Carrier Controller", "Permite gestionar los datos relacionados a su perfil", "Express API Controller"); Component unitTransportControllerMobile = apiAppServicesApplication.AddComponent("UnitTransport Controller", "Permite gestionar los datos relacionados a su unidad de transporte", "Express API Controller"); Component loadingOrderControllerMobile = apiAppServicesApplication.AddComponent("LoadingOrder Controller", "Permite gestionar las operaciones vinculadas como tambien el flujo de cada una de ellas", "Express API Controller"); // Services Component servicePassportAuthenticationMobile = apiAppServicesApplication.AddComponent("Module Passport Authentication", "Provee autenticacion segura del lado del servidor", "Node Module"); Component serviceAzureBlobStorageMobile = apiAppServicesApplication.AddComponent("Service Azure Blob Storage", "Provee los metodos para administrar archivos a la nube de Azure", "Node Module"); // Business Component userBusinessMobile = apiAppServicesApplication.AddComponent("User Business", "Provee funcionalidades de administracion de usuarios", "Javascript Class"); Component carrierBusinessMobile = apiAppServicesApplication.AddComponent("Carrier Business", "Provee funcionalidades de gestion de informacion de los choferes", "Javascript Class"); Component unitTransportBusinessMobile = apiAppServicesApplication.AddComponent("UnitTransport Business", "Provee funcionalidades de gestion de informacion de las unidades de transporte", "Javascript Class"); Component loadingOrderBusinessMobile = apiAppServicesApplication.AddComponent("LoadingOrder Business", "Provee funcionalidades de gestion del flujo de datos de las ordenes de carga", "Javascript Class"); // Conexion a Base de datos Component moduleSequelizeOrmAppServicesMobile = apiAppServicesApplication.AddComponent("Module Sequelize ORM", "Provee una capa de abstraccion para la conexiona a la base de datos", "Node Module"); // Relations apiAppServicesApplication.Components.Where(comp => expressApiController.Equals(comp.Technology)) .ToList() .ForEach(comp => mobileApp.Uses(comp, "Realiza solicitudes a la API", "HTTPS/JSON")); userControllerMobile.Uses(servicePassportAuthenticationMobile, "Usa"); carrierControllerMobile.Uses(serviceAzureBlobStorageMobile, "Usa"); unitTransportControllerMobile.Uses(serviceAzureBlobStorageMobile, "Usa"); loadingOrderControllerMobile.Uses(serviceAzureBlobStorageMobile, "Usa"); serviceAzureBlobStorageMobile.Uses(azureBlobStorageSoftwareSystem, "Usa", "HTTPS"); userControllerMobile.Uses(userBusinessMobile, "Usa"); carrierControllerMobile.Uses(carrierBusinessMobile, "Usa"); unitTransportControllerMobile.Uses(unitTransportBusinessMobile, "Usa"); loadingOrderControllerMobile.Uses(loadingOrderBusinessMobile, "Usa"); userBusinessMobile.Uses(moduleSequelizeOrmAppServicesMobile, "Usa"); carrierBusinessMobile.Uses(moduleSequelizeOrmAppServicesMobile, "Usa"); unitTransportBusinessMobile.Uses(moduleSequelizeOrmAppServicesMobile, "Usa"); loadingOrderBusinessMobile.Uses(moduleSequelizeOrmAppServicesMobile, "Usa"); moduleSequelizeOrmAppServicesMobile.Uses(database, "Lee y Escribe en", "MSSQL Tedious"); // Componentes (API TMS SERVICES) // Controllers Component userControllerTms = apiTmsServicesApplication.AddComponent("User Controller", "Permite a los usuarios autenticarse para acceder a los portales web", "Express API Controller"); Component carrierControllerTms = apiTmsServicesApplication.AddComponent("Carrier Controller", "Permite gestionar los datos relacionados al perfil del chofer", "Express API Controller"); Component unitTransportControllerTms = apiTmsServicesApplication.AddComponent("UnitTransport Controller", "Permite gestionar los datos relacionados a su unidad de transporte", "Express API Controller"); Component loadingOrderControllerTms = apiTmsServicesApplication.AddComponent("LoadingOrder Controller", "Permite administrar las ordenes de carga", "Express API Controller"); Component opportunityControllerTms = apiTmsServicesApplication.AddComponent("Opportunity Controller", "Permite administrar las oportunidades de carga", "Express API Controller"); Component operationControllerTms = apiTmsServicesApplication.AddComponent("Operation Controller", "Permite administrar las operaciones y su flujo", "Express API Controller"); Component clientControllerTms = apiTmsServicesApplication.AddComponent("Client Controller", "Permite gestionar los datos de clientes", "Express API Controller"); // Services Component servicePassportAuthenticationTms = apiTmsServicesApplication.AddComponent("Module Passport Authentication", "Provee seguridad en autenticacion de usuario del lado del servidor", "Node Module"); Component serviceAzureBlobStorageTms = apiTmsServicesApplication.AddComponent("Service Azure Blob Storage", "Provee los metodos para administrar archivos a la nube de Azure", "Node Module"); Component serviceFirebaseCloudMessagingTms = apiTmsServicesApplication.AddComponent("Service Firebase Cloud Messaging", "Provee funcionalidades para emitir/recepcionar notificaciones en tiempo real", "API Firebase"); Component serviceOdooApiTms = apiTmsServicesApplication.AddComponent("Service Odoo API", "Provee funcionalidades de integracion con la base de datos de Odoo", "Node Module"); Component serviceMailerTms = apiTmsServicesApplication.AddComponent("Service NodeMailer", "Provee funcionalidades para enviar correos electronicos", "Node Module"); // Business Component userBusinessTms = apiTmsServicesApplication.AddComponent("User Business", "Provee funcionalidades de administracion de usuarios", "Javascript Class"); Component carrierBusinessTms = apiTmsServicesApplication.AddComponent("Carrier Business", "Provee funcionalidades de gestion de informacion de los choferes", "Javascript Class"); Component unitTransportBusinessTms = apiTmsServicesApplication.AddComponent("UnitTransport Business", "Provee funcionalidades de gestion de informacion de las unidades de transporte", "Javascript Class"); Component opportunityBusinessTms = apiTmsServicesApplication.AddComponent("Opportunity Business", "Provee funcionalidades de gestion del reclutamiento de choferes para las operaciones", "Javascript Class"); Component operationBusinessTms = apiTmsServicesApplication.AddComponent("Operation Business", "Provee funcionalidades de gestion y seguimiento de operaciones", "Javascript Class"); Component clientBusinessTms = apiTmsServicesApplication.AddComponent("Client Business", "Provee funcionalidades de gestion de los clientes", "Javascript Class"); Component loadingOrderBusinessTms = apiTmsServicesApplication.AddComponent("LoadingOrder Business", "Provee funcionalidades de gestion del flujo de datos de las ordenes de carga", "Javascript Class"); // Conexion a Base de datos Component moduleSequelizeOrmAppServicesTms = apiTmsServicesApplication.AddComponent("Module Sequelize ORM", "Provee una capa de abstraccion para la conexiona a la base de datos", "Node Module"); // Relations apiTmsServicesApplication.Components.Where(comp => expressApiController.Equals(comp.Technology)) .ToList() .ForEach(comp => spaOperations.Uses(comp, "Realiza solicitudes a la API", "HTTPS/JSON")); List <string> excludeControllersForClients = new List <string> { "Carrier Controller", "UnitTransport Controller", "Opportunity Controller" }; apiTmsServicesApplication.Components.Where(comp => expressApiController.Equals(comp.Technology)) .ToList() .ForEach(comp => { if (!excludeControllersForClients.Contains(comp.Name)) { spaClients.Uses(comp, "Realiza solicitudes a la API", "HTTPS/JSON"); } }); userControllerTms.Uses(servicePassportAuthenticationTms, "Usa"); carrierControllerTms.Uses(serviceFirebaseCloudMessagingTms, "Usa"); unitTransportControllerTms.Uses(serviceFirebaseCloudMessagingTms, "Usa"); loadingOrderControllerTms.Uses(serviceAzureBlobStorageTms, "Usa"); loadingOrderControllerTms.Uses(serviceFirebaseCloudMessagingTms, "Usa"); loadingOrderControllerTms.Uses(serviceOdooApiTms, "Usa"); operationControllerTms.Uses(serviceFirebaseCloudMessagingTms, "Usa"); operationControllerTms.Uses(serviceOdooApiTms, "Usa"); opportunityControllerTms.Uses(serviceFirebaseCloudMessagingTms, "Usa"); clientControllerTms.Uses(serviceMailerTms, "Usa"); serviceAzureBlobStorageTms.Uses(azureBlobStorageSoftwareSystem, "Usa", "HTTPS"); serviceMailerTms.Uses(mailServerSoftwareSystem, "Envia correos electronicos usando", "SMTP"); serviceOdooApiTms.Uses(odooErpSoftwareSystem, "Usa", "HTTP/XML-RPC/JSON-RPC"); serviceFirebaseCloudMessagingTms.Uses(fcmSoftwareSystem, "Usa", "HTTPS"); serviceAzureBlobStorageTms.Uses(azureBlobStorageSoftwareSystem, "Usa", "HTTPS"); userControllerTms.Uses(userBusinessTms, "Usa"); carrierControllerTms.Uses(carrierBusinessTms, "Usa"); unitTransportControllerTms.Uses(unitTransportBusinessTms, "Usa"); loadingOrderControllerTms.Uses(loadingOrderBusinessTms, "Usa"); operationControllerTms.Uses(operationBusinessTms, "Usa"); opportunityControllerTms.Uses(opportunityBusinessTms, "Usa"); clientControllerTms.Uses(clientBusinessTms, "Usa"); userBusinessTms.Uses(moduleSequelizeOrmAppServicesTms, "Usa"); carrierBusinessTms.Uses(moduleSequelizeOrmAppServicesTms, "Usa"); unitTransportBusinessTms.Uses(moduleSequelizeOrmAppServicesTms, "Usa"); loadingOrderBusinessTms.Uses(moduleSequelizeOrmAppServicesTms, "Usa"); opportunityBusinessTms.Uses(moduleSequelizeOrmAppServicesTms, "Usa"); operationBusinessTms.Uses(moduleSequelizeOrmAppServicesTms, "Usa"); clientBusinessTms.Uses(moduleSequelizeOrmAppServicesTms, "Usa"); moduleSequelizeOrmAppServicesTms.Uses(database, "Lee y Escribe en", "MSSQL Tedious"); model.AddImplicitRelationships(); // Definir la visualizacion de los diagramas ViewSet views = workspace.Views; SystemContextView systemContextView = views.CreateSystemContextView(tmsSoftwareSystem, "Contexto de Sistema", "Diagrama de Contexto de Sistema (Nivel 1)"); systemContextView.EnterpriseBoundaryVisible = false; systemContextView.AddNearestNeighbours(tmsSoftwareSystem); systemContextView.PaperSize = PaperSize.A5_Landscape; /*contextView.AddAllSoftwareSystems(); * contextView.AddAllPeople();*/ ContainerView containerView = views.CreateContainerView(tmsSoftwareSystem, "Contenedores de Sistema", "Diagrama de contenedores de Sistema (Nivel 2)"); containerView.Add(userOperator); containerView.Add(userClient); containerView.Add(userCompany); containerView.Add(userDriver); containerView.AddAllContainers(); containerView.AddAllSoftwareSystems(); containerView.Remove(tmsSoftwareSystem); // Componentes for API Mobile Application ComponentView componentMobileView = views.CreateComponentView(apiAppServicesApplication, "Componentes de Sistema - API Mobile", "Diagrama de Componentes de Sistema (Nivel 3)"); componentMobileView.Add(mobileApp); componentMobileView.Add(azureBlobStorageSoftwareSystem); componentMobileView.Add(database); componentMobileView.AddAllComponents(); componentMobileView.PaperSize = PaperSize.A5_Landscape; // Componentes for API TMS Application ComponentView componentTMSView = views.CreateComponentView(apiTmsServicesApplication, "Componentes de Sistema - API TMS", "Diagrama de Componentes de Sistema (Nivel 3)"); componentTMSView.Add(spaClients); componentTMSView.Add(spaOperations); componentTMSView.Add(azureBlobStorageSoftwareSystem); componentTMSView.Add(mailServerSoftwareSystem); componentTMSView.Add(odooErpSoftwareSystem); componentTMSView.Add(fcmSoftwareSystem); componentTMSView.Add(database); componentTMSView.AddAllComponents(); componentTMSView.PaperSize = PaperSize.A5_Landscape; // Agregar algo de documentacion StructurizrDocumentationTemplate template = new StructurizrDocumentationTemplate(workspace); template.AddContextSection(tmsSoftwareSystem, Format.Markdown, "Definiendo el contexto del sistema de software\n![](embed:SystemContext)"); // agregando estilos personalizados 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 ElementStyle(Tags.Container) { Background = "#438dd5", Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.Component) { Background = "#85bbf0", Color = "#000000" }); styles.Add(new ElementStyle(EXISTS_SYSTEM_TAG) { Background = "#999999", Color = "#ffffff" }); styles.Add(new ElementStyle(MOBILE_APP_TAG) { Shape = Shape.MobileDeviceLandscape }); styles.Add(new ElementStyle(SINGLE_PAGE_APPLICATION_TAG) { Shape = Shape.WebBrowser }); styles.Add(new ElementStyle(DATABASE_TAG) { Shape = Shape.Cylinder }); // cargar el documento actual (formato JSON) updateWorkspaceToStructurizr(workspace); Console.WriteLine("Generated Diagram Sucessfully!"); }
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, "Uses", "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("SystemLandscape", "The system landscape diagram for Big Bank plc."); 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 component 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 BuildC4Model() { // Add stakeholders en Systemen SoftwareSystem boekhoudSysteem = model.AddSoftwareSystem(Location.Internal, "Boekhoudsysteem", "Boekhoudsysteem voor midden en kleinbedrijf en ZZP'er"); SoftwareSystem itsmSysteem = model.AddSoftwareSystem(Location.Internal, "ITSM Systeem", "Interne CRM applicatie"); itsmSysteem.AddTags(InternalSystemTag); boekhoudSysteem.Uses(itsmSysteem, "Haalt abonnement gegevens op"); SoftwareSystem website = model.AddSoftwareSystem(Location.Internal, "Website", $"publieke website van {BedrijfsNaam}"); website.AddTags(WebBrowserTag); website.Uses(itsmSysteem, "Registreert een abonnement"); SoftwareSystem webshop = model.AddSoftwareSystem(Location.External, "Webshop", $"Webshopkoppeling names klant met Boekhoudsysteem"); webshop.AddTags(ExternalSystemTag); boekhoudSysteem.Uses(webshop, "krijgt gegevens van"); SoftwareSystem bank = model.AddSoftwareSystem(Location.External, "Bank", $"Bankkoppeling names klant met Boekhoudsysteem"); bank.AddTags(ExternalSystemTag); boekhoudSysteem.Uses(bank, "krijgt gegevens van"); Person hoofdgebruiker = model.AddPerson(Location.External, "Hoofdgebruiker", "De gebruiker van de klant die het abonnenement heeft afgesloten"); hoofdgebruiker.Uses(boekhoudSysteem, Gebruikt); hoofdgebruiker.Uses(website, Gebruikt); Person gebruiker = model.AddPerson(Location.External, "Gebruiker", "De medewerker van de klant"); gebruiker.Uses(boekhoudSysteem, Gebruikt); Person accountant = model.AddPerson(Location.External, "Accountant", "De accountant van de klant"); accountant.Uses(boekhoudSysteem, Gebruikt); hoofdgebruiker.InteractsWith(accountant, "Vraagt controle aan bij"); Person helpdesk = model.AddPerson(Location.Internal, "Helpdeskmedewerker", $"Helpdeskmedewerker van {BedrijfsNaam}"); helpdesk.Uses(boekhoudSysteem, Gebruikt); helpdesk.Uses(itsmSysteem, Gebruikt); hoofdgebruiker.InteractsWith(helpdesk, "Vraagt hulp van"); // Extra diagram: Systeemlandschap SystemLandscapeView systemLandscapeView = views.CreateSystemLandscapeView("SystemLandscape", "System Context diagram Boekhoudsysteem."); systemLandscapeView.AddAllElements(); systemLandscapeView.EnableAutomaticLayout(); // containers Container coreModule = boekhoudSysteem.AddContainer("Core Module", "Basis module voor inrichting, gebruikers", "C#"); coreModule.AddTags(Tags.Container); coreModule.Uses(itsmSysteem, "krijgt gegevens van"); Container bankModule = boekhoudSysteem.AddContainer("Bank Module", "Importeren van betaalgegevens", "C#"); bankModule.AddTags(Tags.Container); bankModule.Uses(bank, "krijgt gegevens van"); Container koppelingModule = boekhoudSysteem.AddContainer("Koppelingen Module", "Module voor inrichten diverse externe koppelingen", "C#"); koppelingModule.AddTags(Tags.Container); koppelingModule.Uses(webshop, "krijgt gegevens van"); Container boekhoudModule = boekhoudSysteem.AddContainer("Boekhoud Module", "Basis onderdelen van een Boekhoudsysteem zoals dagboeken en rapportages", "C#"); boekhoudModule.AddTags(Tags.Container); boekhoudModule.Uses(webshop, "krijgt gegevens van"); Container facturatieModule = boekhoudSysteem.AddContainer("Facturatie Module", "Facturatie en Offerte module", "C#"); facturatieModule.AddTags(Tags.Container); facturatieModule.Uses(boekhoudModule, "geeft verkooporders aan"); Container importModule = boekhoudSysteem.AddContainer("Import Module", "Module voor import en export gegevens", "C#"); importModule.AddTags(Tags.Container); importModule.Uses(boekhoudModule, "geeft relaties aan"); importModule.Uses(facturatieModule, "geeft artikelen aan"); hoofdgebruiker.Uses(coreModule, Gebruikt); hoofdgebruiker.Uses(boekhoudModule, Gebruikt); hoofdgebruiker.Uses(facturatieModule, Gebruikt); hoofdgebruiker.Uses(bankModule, Gebruikt); hoofdgebruiker.Uses(koppelingModule, Gebruikt); hoofdgebruiker.Uses(importModule, Gebruikt); gebruiker.Uses(boekhoudModule, Gebruikt); gebruiker.Uses(facturatieModule, Gebruikt); gebruiker.Uses(bankModule, Gebruikt); accountant.Uses(boekhoudModule, Gebruikt); helpdesk.Uses(boekhoudModule, Gebruikt); Container databaseSystem = boekhoudSysteem.AddContainer("Systeem Database", "Opslag gebruikers, abonnement, administratie gegevens, hashed authentication credentials, access logs, etc.", "Relational Database Schema"); databaseSystem.AddTags(DatabaseTag); coreModule.Uses(databaseSystem, Gebruikt); Container databaseAccount = boekhoudSysteem.AddContainer("Boekhouding Database", "Opslag boekhouding per abonnement per administratie", "Relational Database Schema"); databaseAccount.AddTags(DatabaseTag); boekhoudModule.Uses(databaseAccount, Gebruikt); facturatieModule.Uses(databaseAccount, Gebruikt); bankModule.Uses(databaseAccount, Gebruikt); // Components Component bankImportView = bankModule.AddComponent("Bank statement Import", "Importscherm bankafschriften", "ASP.Net Webform"); bankImportView.AddTags(WebBrowserTag); Component bankPaymentLogic = bankModule.AddComponent("Payment logic service", "Businesslaag bankafschriften", "C#"); bankPaymentLogic.AddTags(InternalSystemTag); Component bankPaymentData = bankModule.AddComponent("Payment data service", "Datalaag bankafschriften", "C#"); bankPaymentData.AddTags(InternalSystemTag); bankImportView.Uses(bankPaymentLogic, Gebruikt); bankPaymentLogic.Uses(bankPaymentData, Gebruikt); bankPaymentLogic.Uses(bank, Gebruikt); Component bankPaymentView = bankModule.AddComponent("Bank payments", "Betaalopdrachten", "ASP.Net Webform"); bankPaymentView.AddTags(WebBrowserTag); bankPaymentView.Uses(bankPaymentLogic, Gebruikt); Component bankInstellingView = bankModule.AddComponent("Instellingen Bankstatements", "Instellingen bankafschriften", "ASP.Net Webform"); bankInstellingView.AddTags(WebBrowserTag); Component bankInstellingLogic = bankModule.AddComponent("Bankinstellingen logic service", "Businesslaag bankinstellingen", "C#"); bankInstellingLogic.AddTags(InternalSystemTag); Component bankInstellingData = bankModule.AddComponent("Bankinstellingen data service", "Datalaag bankinstellingen", "C#"); bankInstellingData.AddTags(InternalSystemTag); bankInstellingView.Uses(bankInstellingLogic, Gebruikt); bankInstellingLogic.Uses(bankInstellingData, Gebruikt); bankPaymentData.Uses(databaseAccount, "Leest en schrijft naar", "Linq2Sql"); bankInstellingData.Uses(databaseAccount, "Leest en schrijft naar", "Linq2Sql"); Component importExportView = importModule.AddComponent("Artikel Import", "Importscherm artikelen", "ASP.Net Webform"); importExportView.AddTags(WebBrowserTag); Component importExportLogic = importModule.AddComponent("Import Export logic service", "Businesslaag import export functionaliteit", "C#"); importExportLogic.AddTags(InternalSystemTag); Component importExportData = importModule.AddComponent("Import Export data service", "Datalaag import export functionaliteit", "C#"); importExportData.AddTags(InternalSystemTag); importExportView.Uses(importExportLogic, Gebruikt); importExportLogic.Uses(importExportData, Gebruikt); importExportData.Uses(databaseAccount, "Leest en schrijft naar", "Linq2Sql"); // Add Views SystemContextView contextView = views.CreateSystemContextView(boekhoudSysteem, "SystemContext", "System Context diagram Boekhoudsysteem."); contextView.AddNearestNeighbours(boekhoudSysteem); contextView.EnableAutomaticLayout(); ContainerView containerView = views.CreateContainerView(boekhoudSysteem, "Containers", "Het container diagram voor het boekhoudsysteem."); containerView.EnableAutomaticLayout(); containerView.Add(hoofdgebruiker); containerView.Add(gebruiker); containerView.Add(accountant); containerView.Add(helpdesk); containerView.AddAllContainers(); containerView.Add(webshop); containerView.Add(bank); containerView.Add(itsmSysteem); ComponentView bankComponentView = views.CreateComponentView(bankModule, "Bank Components", "Component diagram van de Bank module"); bankComponentView.EnableAutomaticLayout(); bankComponentView.Add(databaseAccount); bankComponentView.AddAllComponents(); bankComponentView.Add(bank); ComponentView importExportComponentView = views.CreateComponentView(importModule, "Import-Export Components", "Component diagram van de Import Export module."); importExportComponentView.EnableAutomaticLayout(); importExportComponentView.Add(databaseAccount); importExportComponentView.AddAllComponents(); // Extra diagram: Deployment const string Productie = "Productieomgeving"; DeploymentNode productieOmgeving = model.AddDeploymentNode(Productie, $"{BedrijfsNaam}", "", $"{BedrijfsNaam} data center"); DeploymentNode customerComputer = model.AddDeploymentNode(Productie, "Gebruiker's computer", "", "Microsoft Windows or Apple macOS"); customerComputer.AddDeploymentNode("Web Browser", "", "Chrome, Firefox, Edge or IE11").Add(boekhoudModule); customerComputer.AddTags(WebBrowserTag); DeploymentNode productieWebServer = productieOmgeving.AddDeploymentNode($"{BedrijfsNaam}-web***", "Een webserver gehost in een webserver farm", "Windows 2019", 2, DictionaryUtils.Create("Location=Amsterdam")); productieWebServer .AddDeploymentNode("Microsoft IIS", "Microsoft web server.", "IIS", 1, DictionaryUtils.Create("Xmx=512M", "Xms=1024M", ".Net Framework 4.8")) .Add(boekhoudModule); customerComputer.Uses(productieWebServer, Gebruikt, "https"); DeploymentNode primaryDatabaseServer = productieOmgeving .AddDeploymentNode($"{BedrijfsNaam}-db01", "Primary database server.", "Windows 2019", 1, DictionaryUtils.Create("Location=Amsterdam")) .AddDeploymentNode("SQL Server - Primary", $"Primary, {Productie} databaseserver.", "SqlServer 2017"); primaryDatabaseServer.Add(databaseSystem); primaryDatabaseServer.Add(databaseAccount); DeploymentNode failoverDb = productieOmgeving.AddDeploymentNode($"{BedrijfsNaam}-db02", "Secondary database server.", "Windows 2019", 1, DictionaryUtils.Create("Location=Amsterdam")); failoverDb.AddTags(FailoverTag); DeploymentNode secondaryDatabaseServer = failoverDb.AddDeploymentNode("SQL Server - Secondary", "Secondary, standby database server, alleen voor failover.", "SqlServer 2017"); secondaryDatabaseServer.AddTags(FailoverTag); ContainerInstance secondaryDatabaseSystem = secondaryDatabaseServer.Add(databaseSystem); ContainerInstance secondaryDatabaseAccount = secondaryDatabaseServer.Add(databaseAccount); model.Relationships.Where(r => r.Destination.Equals(secondaryDatabaseSystem)).ToList().ForEach(r => r.AddTags(FailoverTag)); model.Relationships.Where(r => r.Destination.Equals(secondaryDatabaseAccount)).ToList().ForEach(r => r.AddTags(FailoverTag)); Relationship dataReplicationRelationship = primaryDatabaseServer.Uses(secondaryDatabaseServer, "Replicates data to", ""); secondaryDatabaseSystem.AddTags(FailoverTag); secondaryDatabaseAccount.AddTags(FailoverTag); DeploymentView systeemDeploymentView = views.CreateDeploymentView(boekhoudSysteem, Productie, $"De productieomgeving van {BedrijfsNaam}."); //systeemDeploymentView.EnableAutomaticLayout(); systeemDeploymentView.Environment = Productie; systeemDeploymentView.Add(productieOmgeving); systeemDeploymentView.Add(customerComputer); systeemDeploymentView.Add(dataReplicationRelationship); // Set Styling Styles styles = views.Configuration.Styles; styles.Add(new ElementStyle(Tags.SoftwareSystem) { Background = "#1168bd", Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.Container) { Background = "#438dd5", Color = "#ffffff" }); styles.Add(new ElementStyle(Tags.Component) { Background = "#85bbf0", Color = "#000000" }); styles.Add(new ElementStyle(Tags.Person) { Background = "#08427b", Color = "#ffffff", Shape = Shape.Person }); styles.Add(new ElementStyle(InternalSystemTag) { Background = "#999999", Color = "#ffffff" }); styles.Add(new ElementStyle(ExternalSystemTag) { Background = "#999999", Color = "#ffffff" }); styles.Add(new ElementStyle(WebBrowserTag) { Shape = Shape.WebBrowser }); styles.Add(new ElementStyle(DatabaseTag) { Shape = Shape.Cylinder }); styles.Add(new ElementStyle(FailoverTag) { Opacity = 25 }); styles.Add(new RelationshipStyle(FailoverTag) { Opacity = 25, Position = 70 }); }
private static void AddDocumentationDiagram(Workspace workspace, StructurizrDocumentationTemplate template) { Model model = workspace.Model; SoftwareSystem documentationProjectSoftwareSystem = model.AddSoftwareSystem( Location.Internal, "Documentation Project", "Visual Studio Project (or VS Code Workspace) containing all documentation artifacts"); Container diagramsDefinitionsContainer = documentationProjectSoftwareSystem.AddContainer("Diagram Definitions", "This is core Structurizr Library functionality - architecture diagrams defined as a code", "C# code"); Container documentationSectionsContainer = documentationProjectSoftwareSystem.AddContainer("Documentation Sections", "Documentation sections in Markdown format - these can reference screenshots and diagrams", "Markdown"); Container screenshotsContainer = documentationProjectSoftwareSystem.AddContainer("Screenshots", "Screenshots and other images that we want to include in the documentation", "PNG"); SoftwareSystem gitHubRepositorySoftwareSystem = model.AddSoftwareSystem( Location.Unspecified, "GitHub Repository", "Used as remote repository; we use it as online host for screenshots"); Container onlineScreenshotsContainer = gitHubRepositorySoftwareSystem.AddContainer("Online Screenshots", "Screenshots in GitHub available with public URL", "PNG, HTTP"); SoftwareSystem structurizrWorkspaceSoftwareSystem = model.AddSoftwareSystem( Location.Unspecified, "Online Structurizr Workspace", "Transforms diagram definitions into interactive diagrams and also hosts diagrams as images; hosts online documentation"); Container interactiveDiagramsContainer = structurizrWorkspaceSoftwareSystem.AddContainer("Interactive Diagrams", "User can modify diagram layout; there is additional functionality that helps getting architecture insights", "Structurizr SAAS"); Container diagramsAsImagesContainer = structurizrWorkspaceSoftwareSystem.AddContainer("Diagram PNGs", "Interactive diagrams are automatically exported to PNG format and made available online", "PNG, HTTP"); Container documentationAsHtmlContainer = structurizrWorkspaceSoftwareSystem.AddContainer("Documentation Online", "Markdown documents are automatically presented as online HTML", "HTTP, HTML"); // what uses what documentationProjectSoftwareSystem.Uses(gitHubRepositorySoftwareSystem, "Uses it as a Git Remote"); documentationSectionsContainer.Uses(onlineScreenshotsContainer, "Markdown documents reference online screenshots on GitHub"); documentationProjectSoftwareSystem.Uses(structurizrWorkspaceSoftwareSystem, "Pushes diagram definitions and documentation sections into Structurizr workspace"); documentationAsHtmlContainer.Uses(diagramsAsImagesContainer, "Generated HTML references diagrams as images (replacement for customer references to interactive diagrams)"); documentationAsHtmlContainer.Uses(onlineScreenshotsContainer, "Generated HTML references online screenshots on GitHub"); interactiveDiagramsContainer.Uses(diagramsAsImagesContainer, "Are transformed to images automatically"); diagramsDefinitionsContainer.Uses(interactiveDiagramsContainer, "Code is transformed to interactive diagrams"); documentationSectionsContainer.Uses(documentationAsHtmlContainer, "Markdown documents are presented as HTML on Structurizr"); documentationSectionsContainer.Uses(diagramsAsImagesContainer, "Markdown documents reference diagrams hosted on Structurizr"); // diagrams ViewSet views = workspace.Views; SystemContextView documentationSystemContextView = views.CreateSystemContextView( documentationProjectSoftwareSystem, "DocumentationSystemContext", "Documentation System Context diagram."); documentationSystemContextView.AddNearestNeighbours(documentationProjectSoftwareSystem); ContainerView documentationContainerView = views.CreateContainerView(documentationProjectSoftwareSystem, "DocumentationContainerDiagram", "Documentation container diagram"); documentationContainerView.AddAllContainers(); foreach (var githubContainer in gitHubRepositorySoftwareSystem.Containers) { githubContainer.AddTags("GitHub Container"); documentationContainerView.Add(githubContainer); } foreach (var structurizrContainer in structurizrWorkspaceSoftwareSystem.Containers) { structurizrContainer.AddTags("Structurizr Container"); documentationContainerView.Add(structurizrContainer); } // styles Styles styles = views.Configuration.Styles; styles.Add(new ElementStyle("GitHub Container") { Background = "#00BFFF" }); styles.Add(new ElementStyle("Structurizr Container") { Background = "#ADFF2F" }); // documentation sections var documentationFolderPath = Path.Combine(AppContext.BaseDirectory, "Documentation"); template.AddSection(documentationProjectSoftwareSystem, "Documentation system", 1, new FileInfo(Path.Combine(documentationFolderPath, "DocumentationOfDocumentation.md"))); }
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 }
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("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); }