This page demonstrates how the solution architecture document is used to present a solution to a wide audience throughout the course of the development from idea to fully implemented and operational solution.

Solution architecture


Danish law demands that businesses start using digitized bookkeeping that adheres to a standardized chart of accounts, keeps an audit trail, enables auditing by a professional accountant, and protects the integrity of bookkeeping data by automated backups.

My current solution works but isn’t efficient, and it lacks a few features to be compliant when the new law takes effect. Therefore, I’m developing erp as my own proprietary solution that will be fully compliant and optimize the finance capabilities of my company.


erp is a fully compliant web application built on standard technologies supported by most hosting providers. It’s tailored to optimize my business model execution, which means implementing only the exact features I need using technologies that allow me to use it on mobile devices like mobile phones, tablets and laptops.

The develop also showcases my recommended development process and solution architecture document template.

Development plan

BuildDescriptionArchitectural significanceStatus
PDF PoCDisplay a PDF read from a data source.Determines how to read a PDF from a data source like a file or database table and renders it in a Blazor page.Done.
Boilerplate deployable appPicks a session id, logs and measures activity, shows the signature app bar.Sets up the JetBrains Rider solution to accommodate continued development.

Deployed to ASP webhotel to secure working release mechanism.

Demonstrates generation of logs and metrics in mon.
Email upload PoCRead the PDF from an email and write it to a file.Determines how to read PDF attachments from emails and write them to a file.

Will be practical on a mobile phone when receiving emails with attached PDF invoices that need to be uploaded to the erp.
Send email PoCGenerate and send email with verification code.Demonstrates how the generate emails via the web hotel hosting provider’s SMTP server.

Demonstrates how to send emails that aren’t caught in the recipient’s junk filter.
Unit testingUnit test model and database entities.Adds unit tests that use in-memory database to drive development of model and database classes.In development.
Login capabilityIndex (landing) page shows login and registration forms.Adds initial database with tables for user and session.

Turns Index Blazor page into landing and sign in/register page.

Adds user page.

Established the policy for guest users who wish to see the application with restrictions that prevent full-scale use.
Change logRegister changes to key entities.Adds the change table to the database.

Adds an area in the user page for viewing changes.
Company pageCreate company.Adds company table to the database.

Adds company page. Changes to company are written to the change log.
Chart of accountsIn the company page, define the chart of accounts.Add tables for account groups and accounts to the database.

Add area in the company page for setting up the chart of accounts.

Supplementary documentation


Revision history

RevisionPublishedSummary of changes
0.1March, ‘24Early stage, focus is on defining future processes and the necessary functionality and addressing key design concerns.
0.2April, ’24

Solution overview

The erp software is deployed to a web hotel provider and is accessed through standard web browsers.

Bookkeepers and auditors use the erp application via their preferred web browser on their tablet or computer. The admin user monitors the system’s activity with the mon application also running on the web server. The developer controls the system using the web hotel provider’s dashboard.


The ERP solution manages the following key information entities:

UserBookkeepers create and view transactions. Auditors view transactions.Name, email address, role (bookkeeper or auditor), salted password.

List of companies and recorded activity.
ChangeDocuments a user’s data changes.Date and time of the change and copy of the original data.
CompanyThe company using the system for bookkeeping.Name, company registration and VAT number.
ContractA freelance contract that is the basis for time registration and invoicing.

It also generates projected transactions.
Contract details, hourly rate, currency code, exchange rate, start and end dates.

List of timesheets.
TimesheetAn open or closed time registration sheet.Year, month, accumulated hours.

List of daily time registrations.
Daily time registration with an optional comment.Day, hours, optional comment.
InvoiceA monthly invoicing of registered time.Details about supplier and customer as well as an itemized list of billed hours.

Link to the underlying timesheet and corresponding transaction.
A group of accounts.Account number and account name. Summarizes the accounts in the group.

List of subgroups and accounts.
AccountAn account that holds ledger entries.Account number and account name. Summarizes the ledger entries in the account.

Link to the account group.
A reoccurring cost that generates projected transactions.Brief description, amount regularity, accounts.
YearCollates the year’s transactions leading to VAT and TAX statements.Year.

List of months.
MonthCollates monthly transactions.Month.

List of transactions.
TransactionCollates two or more ledger entries in accounts.Transaction text, date and number.

Actual or projected transaction.

Link to any attached documents and to or more ledger entries.
Places a positive (debit) or negative (credit) amount in an account.Amount.

Link to the transaction.
DocumentDigitization of a document that documents the validity of a registered transaction.Filename, content.

Link to the transaction.
Totals VAT amounts for a prescribed VAT registration period. VAT period (first and last month), VAT amount from corresponding accounts.

Link to the transaction.
Totals income, costs, assets and liabilities for a TAX registration year.TAX year, amounts from the accounts.

Link to the transaction.


The following processes will utilize the erp system:

Book and pay bills

Most costs are monthly or annual subscriptions, which are billed electronically. Digitized bills need to be downloaded from the providers’ websites. Costs are booked on the date of issue as debts, which are then cleared later when the payment is withdrawn from the bank account.

Invoice customers and receive payment

Contracts are created to keep track of hourly rate and billable hours. Hours are registered daily in monthly timesheets. End of month, an invoice is generated and booked as a receivable. Received payment clears the receivable.

Project VAT and income tax

Future costs and revenue are projected by generating draft transactions that are replaced when the actual bills and invoices are booked.

Report and pay VAT

When the last month in a VAT period is passed, and before the period is closed, a VAT statement is generated and booked as a corresponding transaction that closes the period.

Report and pay tax

when the last VAT report in the year’s last month has been booked, the year is closed with the booking of the year’s income statement and transfer of the result to the equity account.

Audit bookkeeping

An accountant is invited to log in and review transactions and documents.

Manage solution

Process and system architecture documentation is kept up to date and available on demand from auditors and authorities. Data is backed up and kept safe. Disaster recovery procedures and tools are kept ready. The system is maintained without disrupting processes.

Design constraints

Life expectancy

The solution will be in operation at least 15-20 years until 3-5 years after my last active year.


Bookkeeping will be made both in the legacy solution and in the new erp solution for one whole year, and VAT and tax statements will be compared.


When the solution goes live, every transaction since the beginning of the year will be manually registered in erp.


It’s a key requirement that the erp software can be hosted by my current hosting provider. This means using .NET Core and MySQL, which are available in my current hosting subscription.




TechnologyDescriptionMore information
NET CorePart of the Microsoft ASP.NET technology stack. Microsoft ASP.NET
C#Rich object-oriented programming language.Microsoft C#
BlazorC# Framework for building server-side rendered web pages.Microsoft Blazor
Entity FrameworkC# Framework for creating, reading from and writing to databases.Microsoft EF Core
MySQLSQL database software.Oracle MySQL
MudBlazorRich component library for creating complex Blazor web pages.MudBlazor
BCryptEncryption mechanism used to hash password to protect agains leaks.BCrypt

Design principles

Session handling

When the user opens the erp webapplication is the browser, the browser internally creates a session, which can be used to manage application state between refreshes in JavaScript-based web applications. But this isn’t recommended for Blazor applications like erp.

Therefore, erp picks its own session identifier for each underlying internal browser session. This ‘elevated’ session identifier is then kept in an application state object, which in turn is written to and read from protected session storage, which is a mechanism in Net Core. Protected session storage is only suitable for saving the state of the user interface, so it can be restored in response to a browser refresh.

The user’s data is kept in the database, which also registers the session in the user entity upon successful sign-in. This is used to prevent the user from creating multiple sessions, either in separate tabs in the same browser, or by opening it simultaneously in different browser instances on the same or different devices, which would otherwise threaten data integrity.

The identifier of the ‘elevated’ session is also referenced in all log entries and metrics generated by erp in response to the user’s activity.

Database and service layers

To minimize dependency of database structures all Entity Framework code is isolated in classes in a database package, and they are only used by classes in the services package.

The services package holds classes the provide the core functionality that services the user interface. This packaging enables test-driven development of said functionality, reducing turn-around time between running unit tests and adjusting service methods before adding the complexity of using the same service methods from Blazor pages in the user interface.

Methods in the service classes are measured with metrics, and they log extensively. This enables testing and fine-tuning of metrics generation and logging during the test-driven development phase.

Public methods i service classes must not call other public service methods because this would generate too many metrics and log entries. Service classes can utilize internal methods that dont’ generate metrics and log entries to do smaller common internal tasks.

Unit testing

Unit tests are created to test core functionality, which minimized turn-around time between code changes and testing. Testing via the user interface takes longer because it’s slower to spin up the web application locally and go through multiple steps to tests all scenarios.

To make unit testing viable, database classes are only called from service classes, and service classes encapsulate the entire core functionality. To enable unit testing all scenarios some service classes may require operations that only service testing and aren’t called in Blazor page code.

Blazor page code may only call service classes (ruling out code that uses classes that handle the database).

Database entity relationships

Data is stored using the Entity Framework. This mechanism can manage object aggregation and referencing, but this leads to more tightly coupled entities and makes it more difficult to write unit tests focusing on a single entity type.

Since all entities are required to include a unique identifier, erp assigns GUID identifiers to all entities and maintains relationships between entities by referencing their related entities’ identifier in ordinary fields.

This makes it easier to gradually add new entity types to the database without interfering with already written unit tests. It also makes it easier to reuse parts of the database code base in other applications, for example the User and Email entity classes used solely by the UserService class. This part would be ideal to reuse in the coming cut web application.

Design concerns


User activity is logged (end measured with metrics), which ensures transparency in who’s viewing and updating which data.

Also, changes to key information entities are recorded in a change log, which enables users to view their own changes.



Passwords are only stored as hashed values, which eliminates the risk of leaking passwords that could give others access to the system.

Access to the system is tied to the user’s email address, and email addresses are verified before access is granted.



Users identify themselves with email address and password. Email addresses must be confirmed before access to the system is granted.











The software is structured so that user interface-driven scenarios can be thoroughly tested from unit tests without actual user interaction. This is achieved by building classes that mimic services, which in turn rely on entity classes that are persisted in the database.

Unit tests are setup to use in-memory database storage for entities, and logs and metrics are written to a local SQLite database, which is reset for every test run. This allows a local mon instance to show logs and metrics from the running unit tests.



High-level design


User interaction

Registration, login and session control

When a user opens erp in the webbrowser, the application picks a session id, which is persisted in application’s protected browser storage. Initially, the session only gives access to the application’s landing page, from which the user must register or sign in. The newly opened session isn’t persisted as a Session entity in the database until the user signs in.

To register, a user enters email address, username and a password. This creates an Email entity and a User entity. The username and the hashed password are written to the User entity. The email address is written to the Email entity, which is also assigned a 6-digit randomized verification code, which is emailed to the new user. The user isn’t signed in yet. Signing in requires that the email address is verified by entering the 6-digit verification code.

When signing in, the active session is registered in the corresponding field in the user’s entity in the database. This ensures that each user can only have one active session at any given time. If the user entity has another session registered, it’s assumed to be an abandon

Keeping email addresses as entities prevents duplicate email addresses, and it allows users to transition from an old to a new email address.

When the user signs in, the Session entity is created. Any prior Session entities related to the User entity are deleted. This means that Users can only use the erp application from one device and one browser tab at a time.

The Index page serves as the sign-in page when users open erp in their browser:

It allows users to sign in and go to their user page, in which they manage their settings and companies. Sign in errors are shown directly in the sign-in page. If the user is signing in using a yet unverified email address, the user is taken to the verify page allows them to input the verification code sent to the email address being used.

From the sign-in page, unregistered users can go to the registration page, in which the new user inputs their name, email and password. Upon registration, the new user is taken on to the verify page, where they must enter the verification code sent to their email address. Successful verification takes them to their user page.


Scheduled jobs












Reoccurring tasks


Incident handling