Construction / Logistics SaaS · client work, details anonymised
Laydown
A multi-tenant booking system for construction-site logistics. Contractors book hoists, gates and offloading areas, and each vehicle visit is tracked against its booking. I worked on it from its first deployments to its move onto AWS, its own identity server and a rewrite of the web app.
- Role
- Engineer, then solution architect
- When
- Nov 2020 – Nov 2026
- Source
- Client code, not public
- Stack
- .NET
- Next.js
- Angular
- MongoDB
- Redis
- OpenIddict
- AWS Lambda
- API Gateway
- CloudFront
- App Runner
- Terraform
- Over 2,400 commits across the platform, identity server, control plane and infrastructure repositories, including all 74 in the Terraform repository and all 182 in the new web app
- Moved the platform from Kubernetes on Azure to AWS: the .NET API runs as one Lambda behind API Gateway, beside nine background-job Lambdas on SQS and schedules
- Built a multi-tenant OpenID Connect server that federates Microsoft Entra ID and Autodesk sign-in, with signing keys held in Secrets Manager under KMS
- Led the rewrite of a roughly 300,000-line Angular frontend in Next.js, with a backend-for-frontend that keeps tokens out of the browser and a data layer generated from OpenAPI
Problem
On a busy construction site, the hoists, the gates and the patch of ground where a lorry can unload are all shared, and they run out. Contractors book them ahead of time, each booking goes through approval, and every vehicle that arrives is recorded against it. It is multi-tenant, so each company using it gets its own subdomain, branding and sign-in.
The first version ran on Kubernetes in Azure. By 2025 it was moving to AWS and needed its own identity provider, and Angular development on its frontend had stopped.
My role
I worked on the platform from November 2020, when it was a .NET API on AKS, through to November 2026. Early on that meant deployments, Redis caching and the notifications service. From 2025 I moved it to AWS and wrote the Terraform for it, then built the identity server and the tenant control plane, and in September 2026 started the frontend rewrite. In the main platform repository I made 2,041 of its 8,045 commits. I also set up the iOS release pipelines that push UAT, demo and production builds to TestFlight.
Architecture
The .NET API runs as a single Lambda behind API Gateway and reaches its dependencies through VPC endpoints. Nine smaller Lambdas share its projects and each run one job, such as booking reminders, bulk cancellations, QR code generation and new tenant setup. MongoDB holds the data, with Redis in front for caching. Terraform covers the queues, API Gateway stages, WAF rules, certificates and ECR repositories, with deployments in a Middle East and an EU region.
Sign-in goes through an OpenIddict server, also on Lambda, that issues tokens for every tenant and federates Entra ID and Autodesk accounts. A separate control plane owns tenants, their domains and their branding. When a tenant is created, the setup Lambda adds its subdomain to the shared CloudFront distribution after checking that the certificate covers it.
The new web app is Next.js on App Runner behind CloudFront. Its server side holds the session, and every API call from the browser goes through it.
Key decisions
- One Lambda for the API, separate Lambdas for jobs. Shipping the whole API as one function made the move to AWS a hosting change. Background jobs got their own functions and pipelines so a reminder fix doesn’t redeploy the API.
- Big bang, not strangler. The usual advice for replacing a large frontend is to move routes over one at a time. Here the product had no live customers yet, so a freeze cost nothing and running two apps side by side would have.
- The server holds the session. The Angular app kept its refresh token in
localStorage, where any script on the page could read it. The backend-for-frontend keeps tokens on the server and gives the browser an httpOnly session cookie. - Generate the data layer. Most API operations declared no response type, so a typed client couldn’t be generated. I typed the contract first, 236 of 273 operations by late September, and generated the client from it.
- Match Angular exactly. The first pass built screens from the company design system and looked like nothing users had seen. I reset it so the new app reproduces the Angular screens pixel for pixel, checked by a Playwright parity suite.
Outcomes
The platform runs on AWS with its infrastructure in Terraform and a pipeline per deployable. A new tenant gets sign-in, a subdomain and branding without anyone editing CloudFront by hand. The Next.js rewrite runs on a preview environment against the dev API, with screens being ported one ticket at a time.