Client contract · 2022 – 2026 · client since 2020
ISMS CompliancePlatform
Multi-tenant SaaS that takes organizations through information-security certification — ISO 27001 and beyond.
- NestJS
- TypeScript
- Angular
- NATS JetStream
- Kubernetes
- Helm / Helmfile
- MongoDB
- Redis
- MinIO
- Antivirus scanning
- Docker
- Skaffold
- Angular SPA front end
- API Gateway single ingress
- NATS JetStream event bus
- User domain service
- Core domain service
- Document domain service
- Analytics domain consumer
- Support domain service
- Ops domain consumer
- MongoDB · Redis · MinIO · antivirus stores
A multi-tenant SaaS platform that guides organizations through ISO 27001 certification — seven independently deployable services communicating over an event bus, orchestrated on Kubernetes.
The client first hired me in 2020 to build their company website. Later they trusted me again — this time to build their core product on a microservices architecture.
For hiring managers
I owned all of it: the architecture, the separation of the domains into services, the front end, and the deployment layer.
The services deploy and fail independently. An API gateway is the single ingress point, authenticating requests and translating them into NATS subjects; backend services never expose themselves directly. Each service owns its own bounded context and publishes domain events (user.created, project.updated, file.uploaded) that other services subscribe to. The analytics and ops domains are pure consumers — they hold no write path of their own and rebuild their state entirely from the event stream.
| Domain | Responsibility |
|---|---|
| API Gateway | Auth, validation, HTTP→NATS translation, WebSocket proxy |
| Analytics domain | Event-sourced dashboards and statistics |
| Domain services | Each owns the operations of its own bounded context — nothing reaches into another's data |
Infrastructure is declarative end to end: NATS JetStream, MongoDB (replica set via the Community Operator), Redis, MinIO, an antivirus engine, and Ingress NGINX all managed through helmfile, with Skaffold providing hot-reload development against a live cluster.
Decisions, answered: event-driven over REST between services, because decoupled services absorb each other's downtime instead of cascading it. The gateway translates HTTP into NATS rather than proxying, so everything internal speaks one protocol and gets buffering and replay for free. The support domain keeps local read models, because a ticket query should never block on another service — the cost is reconciliation, paid deliberately. MinIO over S3 directly, because sensitive documents stay inside the cluster boundary while the S3 API keeps storage swappable.
For clients
Information security management systems are document-heavy, evidence-heavy, deadline-driven work, and most organizations run them on spreadsheets and shared drives. This platform turns that into tracked work: standards decompose into projects, projects into tasks and required documents, and every action leaves an audit trail. Multi-tenancy means a consultancy can run many client organizations from one deployment without their data ever touching.
The engagement started agile: weekly meetings, progress reviewed. Over time the client handed me the decisions and I led the build my own way, with a casual session when a design changed or a feature was added. By the final iteration the brief had widened beyond ISO tooling toward general project management, and the platform's workspace reflects that. The weekly reviews stopped because they stopped being needed.
Architecture
Why the gateway boundary matters
The front end has no knowledge of the microservices or the broker. It talks only to the gateway, which means services can be split, merged, or rewritten without a single front-end change. This is what the extra complexity buys.
system monitoring — 7 services healthy
multi-tenant workspace
ISO 27001 project — controls & compliance
workspace entryThe hard problem
Six services, consistent, without distributed transactions
The support domain needs user and project data to render a ticket, but calling the user and core domains synchronously would couple all three — one slow service degrades the other two, and any outage cascades. The system instead has it subscribe to user.* and project.* events and maintain its own local read model. It answers every query from local state and never blocks on another service.
The cost is eventual consistency, which has to be designed for up front: events must be idempotent, ordering can't be assumed, and a service restarting needs to catch up on everything it missed. That last requirement is why NATS runs in JetStream mode with a persistent FileStore — with a memory store, a pod restart silently loses the event log and consumers desynchronize permanently. That failure never shows up in development, and it can't be repaired in production.
The product
Twelve modules
Twelve modules: Dashboard, Projects, Tasks, Documents, Meetings, Audits, Teams, Trainings, Templates, Support, Directory, Organization. Dark and light themes, and an EN/AR language toggle.
The Documents module is where the domain expertise shows. It models real ISO 27001 artefacts — ISMS scope and boundaries, risk assessment methodology, statement of applicability mapping Annex A controls, access control procedures, incident management and business continuity plans — typed as Core Document, Methodology, Procedure, Plan, Guideline or Record, each moving through Draft → Review → Approved/Rejected. That taxonomy comes from four years inside the standard.
Three primary flows: authentication and organization setup with 2FA and CASL-based abilities; document management from upload through virus scan, object storage and versioning; and audit management — create an audit, assign controls, attach evidence, export the report.
Where it stands
Feature-complete and demonstrably running with seeded data as of March 2026 — and stood up again in July 2026 on a local Kubernetes cluster via the platform's own Helm charts, multi-tenant seed data, monitoring and all. Still never deployed to production.
In February 2026 I ran an agent-assisted production-readiness audit across all seven services — agentic tooling driving the codebase analysis and remediation planning under my direction. What it audited was my local development environment, measured against production standards, and it mapped the gap precisely: development defaults like single replicas and non-persistent stores, expired local certificates, secrets sitting in config. Remediation closed the part of that gap worth closing before a deployment exists — per-service secrets templated into each chart, the event store moved to persistent storage, certificates renewed. Auditing a dev environment against production standards is how you know the distance before you ship.
Delivery engineering
120 seconds to 1.2
Alongside the architecture, a Docker build overhaul: multi-stage production builds, layer-cache mounts for npm, non-root container users, and Node 20. Measured result — incremental builds dropped from 120 seconds to 1.2 seconds, production images shrank 60–70%, and the frontend image shrank roughly 90% by serving through nginx instead of Node.
Trade-offs
What it cost
| Decision | Bought | Paid |
|---|---|---|
| Event-driven over synchronous REST | Loose coupling; services survive each other's outages | Eventual consistency everywhere; no read-your-writes guarantee; debugging spans multiple logs |
| Gateway translates HTTP→NATS | One ingress, one auth boundary, services never exposed | Gateway becomes a single point of failure and a deployment bottleneck |
| MongoDB across all services | One operational skill set; fast iteration | No cross-service joins, and compliance data is relational, which document modelling works against |
| MinIO in-cluster over managed S3 | Evidence never leaves the cluster boundary | Object storage becomes mine to operate — backups, capacity, upgrades |
| Kubernetes from the start | Real horizontal scaling; declarative infrastructure | Heavy operational overhead |
The platform's architecture was sound and its infrastructure ambition exceeded the environment available to run it. Given the same brief again, the right call is probably a modular monolith with the event boundaries drawn but not yet distributed — same design thinking, a fraction of the operational cost, and it would have shipped.