UBORA e-platform architecture

The e-platform is currently a single service web application (a monolith) and is fully custom-built in the sense that it does not use any existing project/task management and wiki software underneath, but instead takes advantages of many smaller pieces of free open-source technology.

To ensure a seamless e-infrastructure with good user experience, the UBORA e-infrastructure is built on Microsoft's ASP.NET Core web framework. The programming language for the back-end is C#. The front-end of the e-infrastructure is quite lightweight in terms of client-side code (JavaScript) as it is a multi-page application (MPA), not a single-page application (SPA), which means that pages are rendered on the server and then sent to the client (browser). The codebase has been written using agile methodologies. The codebase is supported by a substantial test suite which consists of unit, integration and functional user interface tests.

List of used technologies


Bootstrap 4
For simplifying the construction of a best standards compatible user interface with unified experience, we elected to use Bootstrap 4, a modern HTML/CSS/JS framework, as the foundation. Other than the overall visual feeling, Bootstrap 4 has helped us with many components we need for the UBORA e-infrastructure: notifications, alerts, navigation menus, modals etc.

jQuery
We use jQuery to provide client-side interactivity for some parts of the e-infrastructure.

QuillJS
Because the UBORA e-infrastructure has many parts for users to input text with links, pictures and videos, which necessitate a WYSIWYG editor for the best user experience, we chose an free open-source editor QuillJS. It uses HTML-s content editable element as input but internally stores it’s own document model.

Quill-Delta-To-HTML
A simple library for converting Quill’s format to HTML on the back-end using Node.js.

DropzoneJS
To be able to provide a smooth drag and drop experience for the users on the repository parts of the UBORA e-infrastructure, we used an open-source embeddable JavaScript library DropzoneJS.

Select2 and autocomplete.js
We used these 2 JavaScript frameworks to provide a more powerful user experience for all the input and dropdown fields UBORA e-infrastructure has.

three.js
A JavaScript library we use to display uploaded 3D models spatially inside the web browser.

Node Package Manager (NPM)
We used NPM for managing all the JavaScript package dependencies.

Webpack
We have integrated Webpack in the building process of the e-infrastructure, which we use to prepare the HTML/CSS/JS assets for the production environment. Webpack allows us to use the best practices and syntaxes of CSS and JavaScript for development while maintaining compatibility with older internet browsers. Webpack bundles and minifies the client-side assets for optimal use of bandwidth and HTTP transfers.

Azure App Service
We used Microsoft’s Azure (platform as a service [PaaS]) for hosting the e-infrastructure. Here we have flexible pricing based on usage and we can easily upscale and downscale and use other advanced cloud features.

Azure Blob Storage
For storing all the files uploaded by UBORA users, we use Blob Storage service by Microsoft Azure. Non-public files uploaded to a UBORA project are secured with a shared access signature (SAS token). The secured files are authorized and served through the UBORA e-infrastructure based on the privileges of the user.

Azure Application Insights
We monitor the usage statistics of the platform using the Application Insights service by Microsoft Azure.

WebdriverIO
In addition to the unit tests on codebase level, we write automated user interface tests. WebdriverIO provides a nice API and it uses Selenium internally.

ASP.NET Core MVC
Modern open-source cross-platform framework for building back-end web services with the C# programming language using model-view-controller pattern.

ASP.NET Identity Core
High quality membership engine for storing users and authenticating users.

PostgreSQL
Open-source cross-platform polyglot database engine for storing the state of our business entities. We use both the relational and document database capabilities of PostgreSQL.

Marten
An open-source abstraction layer over PostgreSQL for .NET which enables safer and more productive development experience. Marten features architectural patterns in a tested and easy to use manner: event-sourcing, multi-tenancy, soft-deletes etc.

Docker
The build for the UBORA e-infrastructure is containerized in a Docker image which can be deployed to different environments and provides a single source of truth for a working build. New developers can quickly set up the environment to start developing the e-infrastructure on their computers.

Bitbucket
We use Git version control with Bitbucket to put up all the new code to be merged into the platform as pull requests which other developers can code review and test independently. We imagine we will move to GitHub when it comes time to open-source the codebase.

Pandoc
A universal document converter we use to convert HTML to Open Document Format (.odt).

ASP.NET NodeServices
A library for invoking Node.js code from the back-end inside .NET application.

TeamCity
The development supporting continuous integration (CI) server which is the single source of truth whether new versions of the e-infrastructure are buildable & deployable. The main indicator is running all the tests successfully.

Database

UBORA e-infrastructure is built on top of the free open-source cross-platform database engine PostgreSQL. It is a relational database that can effectively store documents using the JSONB type. Thanks to the .NET’s Marten abstraction, we created a document-oriented database, which includes all the good parts of an SQL database (e.g. ACID operations, foreign keys), and is well-fitted with the object-oriented domain model.
Thanks to this choice, we have gained in developer productivity due to reduced trade-offs when modeling data: if an object can be serialized into a JSON type, it can be stored in the database. When a problem is best resolved using relational data, then it can be easily “drop down” to relational model with PostgreSQL and Marten. If some database query is best optimized using relational data and indexes, data can be easily duplicated from the document to the relational table. The technique of combining database storing paradigms is called “polyglot persistence”.

Overview of the .NET solution


Ubora.Domain


This project holds the most important building blocks and internal API of the application: commands, queries, events, entities & specifications. The state of the application is persisted in an immutable append-only event store (event sourcing). The domain entities are a projection of successfully persisted events.
When a new event persists, it is applied to all the relevant inline projections to check for any domain validation errors: if any error is found then the event will not be persisted. If an event is successfully persisted, subscribers can do additional work based on it (for example the platform can send out notifications to one or many of the end-users based on the type of event).

Ubora.Web


Ubora.Web is the main executable ASP.NET Model-View-Controller (MVC) project which holds the HTTP endpoint controllers, data transfers objects (view & post models), authorization logic and other services.
The UBORA e-infrastructure uses policy-based authorization and resource-based authorization. Each policy has one or more requirements, which can have one or more handlers. Users are authorized on each HTTP request and the system does not blindly trust any data that comes from the client-side, because they can always be tampered.

Ubora.Domain.Tests & Ubora.Web.Tests


These projects hold unit and integration tests for the components that make up the e-infrastructure. The file structures usually correspond to the projects with real implementation. For example, when Ubora.Domain holds UserProfile.cs under the folder Users, the Test project will have UserProfileTests.cs under the same folder. When developing new components, the unit tests have been written before the real implementation, to check if the component works properly and how the API looks to its users. In this way, when the real implementation is created after the test, we will get fast feedback (much faster than starting the e-infrastructure and clicking through) to have a so-called safety net when future developers will modify the component.