Skip to main content
This page lives in the Developers section and is also referenced from Deployment. If you arrived from there, your sidebar has switched to Developers.

Architecture Overview

How CDT's frontend, backend, and data layers connect to form a collaborative digital twin platform.

Overview

CDT is a full-stack Next.js 15 application that combines three specialized visualization engines — maps, BIM/IFC models, and point clouds — with a REST API layer and a PostgreSQL + MinIO storage backend. The entire application, from server-side rendering to API routes, lives in a single Next.js deployment, which keeps infrastructure simple while still supporting a rich, interactive browser experience. Authentication, RBAC authorization, and multi-tenant organization support are built in at the framework level.

High-Level Architecture

Hover any node to highlight its connections. Toggle flow categories in the legend to focus on a single data path.

Frontend

The browser layer is built on Next.js 15 with React 19, using the App Router for both server-side rendering and client-side navigation. Turbopack drives the development server, making incremental rebuilds fast. Styling is handled by Tailwind CSS with Radix UI primitives — unstyled, accessible components that CDT's design system builds on top of.

Visualization engines

CDT ships three distinct viewers, each optimized for a different type of spatial data:

  • MapLibre GL (maplibre-gl) — renders 2D and 3D maps, vector tiles from Martin, and satellite/basemap layers. Includes measurement tools via maplibre-gl-measures and geospatial operations via Turf.js.
  • That Open Company (@thatopen/components) — a WebGL-based BIM viewer that parses and displays IFC files (the open standard for building models) directly in the browser using web-ifc. Supports fragment-based streaming for large models.
  • Potree (potree-cdt) — renders massive point cloud datasets (LiDAR scans and photogrammetry) using a level-of-detail octree structure so only visible geometry is loaded.

State management

Application state is organized into React Context providers, composed together at the app root. Each provider owns a focused slice of state with its own reducer:

ProviderOwns
AppConfigProviderOrganization config, feature flags, map defaults
BimProviderIFC viewer engine state, loaded fragments
MapProviderMapLibre map instance, active layers, viewport
MenusProviderSidebar and toolbar menu state
ToolsProviderActive tool selection per viewer
ContentProviderCurrent content panel and view mode
DatasetsProviderCKAN / open-data dataset state
FilesProviderFile upload queue and metadata
BuildingsProviderSelected building and property cache
PointCloudProviderPotree viewer instance, loaded scenes
PermissionsProviderCASL ability instance for the current user

Data fetching uses SWR for cache-aware client-side requests and a thin HTTP adapter that normalizes all calls through /api. Charts are rendered with Recharts.

Internationalization

CDT ships with English, French, and Spanish translations via next-intl, including locale-aware routing. The locale is derived from the URL segment and organization configuration.

Backend

CDT's backend is a single Core API that lives entirely inside Next.js API routes — there is no separate server process. The Core API hosts the business logic and CRUD endpoints, and delegates to two cross-cutting services on every request: Authentication and Authorization. A scheduled External Open Data integration sits alongside the Core API to pull and proxy public datasets.

Authentication

NextAuth v5 handles authentication. Sign-in requires a multi-factor code delivered by email; codes expire after 5 minutes. Sessions are JWT-based, valid for 8 hours, and are not refreshed on activity.

Authorization

Role-Based Access Control (RBAC) is enforced via CASL. Roles are stored per-organization in PostgreSQL as (action, subject) permission sets. The PermissionsProvider builds an Ability instance from the current user's Role at session time. API routes check this ability before mutating data, and the frontend uses it to conditionally render controls.

Data Layer

Database (PostgreSQL via Prisma)

All structured data lives in PostgreSQL. Prisma ORM provides a type-safe query client and handles migrations. The core models are:

  • Organization — top-level tenant; owns users, buildings, sites, sensors, files, and roles
  • User — belongs to an organization, assigned a role; can have linked OAuth accounts
  • Role — named permission set scoped to an organization
  • Account — OAuth provider tokens, linked to a user (NextAuth pattern)
  • Building — the primary asset entity; holds rich attribute data (address, geometry, energy, funding, compliance) and belongs to one or more organizations via BuildingOnOrganizations
  • Site — a geographic grouping of buildings; belongs to an organization
  • File — metadata record for any uploaded binary; references a MinIO object key
  • Sensor — IoT sensor linked to a building or organization
  • SensorType — sensor category and unit definitions
  • Infrastructure — non-building infrastructure assets
  • Comment — threaded annotation on buildings or organizations
  • OpenDataPortal — registered CKAN or Opendatasoft portal endpoints

Buildings carry PostGIS-compatible coordinates (buildingLatitude, buildingLongitude, featureId).

Spatial Database (PostGIS + Martin)

Geospatial data lives in PostGIS, the PostgreSQL spatial extension that adds geometry, raster, and spatial indexing. Martin is a tile server that reads directly from PostGIS and serves the results as Mapbox Vector Tiles. MapLibre consumes those tiles to render building footprints and site boundaries on the map without transferring full GeoJSON payloads. PostGIS + Martin together act as the platform's spatial store and tile-serving pipeline.

Unstructured Files (MinIO / S3)

Binary assets — IFC building models, glTF, DXF, LAS/LAZ point cloud tiles, PDFs, images, video, CSV — are stored in MinIO (S3-compatible). The API issues presigned URLs so the browser uploads and downloads directly to storage, keeping large files out of the Next.js process. The @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner packages handle all S3 operations.

External Integrations

ServicePurpose
CKANOpen data portal API — proxied through /api/ckanProxy and /api/opendatasoftProxy to avoid CORS and hide credentials
Google reCAPTCHA v3Bot protection on the sign-in form
Geocode EarthForward and reverse geocoding for address search (NEXT_PUBLIC_GEOCODE_EARTH_API_KEY)
NRCan elevation servicesCanadian elevation and hillshade raster tiles, proxied via rewrites in next.config.ts
Google OAuthOptional social sign-in via NextAuth (AUTH_GOOGLE_ID / AUTH_GOOGLE_SECRET)

In this section