All work
browser CAD · drawing engine

Floor Plan Creator System

A web-based editor for architectural floor plans on a custom SVG + Canvas engine — grid snapping, undo/redo, rotation and multi-floor layers over a 1,100+ component catalogue, with lossless XML import/export and PNG/JPEG output. A Turborepo monorepo whose drawing engine is shared with a DDD/CQRS NestJS API, plus real-time single-session security over SSE.

role
Technical Leader
team
12 engineers
timeline
2025 → now
domain
PropTech / CAD

Overview

The client's teams designed architectural floor plans in a slow, single-user desktop program with a rigid file format. We rebuilt it as a web-based editor: a custom drawing engine renders plans as SVG in the browser and rasterises them to PNG/JPEG with Canvas, users place components from a large catalogue across multiple floors, and every plan round-trips losslessly through the client's XML format — all in a Turborepo monorepo with a DDD/CQRS NestJS API and an admin suite for master data.

The problem

The hardest problems

Architecture

The editor is a React shell around a framework-agnostic drawing engine. The engine renders the live editing surface as an SVG scene and mutates it imperatively, so React never re-renders on each edit — drawing stays responsive as a plan grows. Canvas 2D owns the raster side: exporting plans to PNG/JPEG, generating thumbnails, and measuring real glyph widths for pixel-accurate labels. The whole system is a Turborepo monorepo — the engine (geometry, snapping, undo/redo across floors, rotation/flip, multi-floor layers) and the domain core are one shared package consumed by both the client and the backend, so there is a single source of truth for geometry and types. The NestJS API is organised with DDD + CQRS; XML import/export is an isolated, lossless module.

client — React shell · UI · property panels · toolbars
  ├── SVG engine     live editor · geometry · snap · undo/redo · multi-floor
  └── Canvas 2D      PNG/JPEG export · thumbnails · glyph metrics
        ↕   Turborepo monorepo — shared engine + domain core   ↕
server
  ├── NestJS · DDD/CQRS   drawings · master data · admin
  ├── Auth + SSE          JWT · single active session · real-time logout
  ├── Asset pipeline      private S3 · signed URLs · CDN (CloudFront)
  └── XML import/export   isolated, lossless
        ↕
data
  └── PostgreSQL  plans · master data        ·        S3  assets

Auth & real-time session security

Auth is JWT-based, but the interesting part is enforcing a single active session in real time. Each signed-in client opens a Server-Sent Events (SSE) stream, tagged with the session's token version:

SSE (one-way server→client) was the right primitive: the only real-time need is the server pushing session events, so a full WebSocket layer would have been more infrastructure for no extra capability.

Asset pipeline (private by default)

Plan assets (reference images, thumbnails) are kept private — the storage bucket is never public. The backend signs each object URL at response time, so an API response hands the client a short-lived link instead of a durable public URL; the link expires and the object stays protected.

Two performance moves sit alongside it:

Key decisions & trade-offs

Results

ReactJSRedux ToolkitSVGCanvasTypeScriptTurborepoNestJSDDD/CQRSPostgreSQLSSECloudFront