Skip to content
Deze documentatie wordt actief uitgebreid — kom regelmatig terug.

Cloud Tower (CDA App) — Migration Assessment onto the CTN Stack

Scope note. This document assesses re-platforming the existing Cloud Tower / CDA app — the implementation of the 2026 use case “Visibility Achterland Containerlogistiek” — from its current Supabase backend onto the CTN preferred stack (Quarkus, PostgreSQL, Keycloak). It is a pre-scoping assessment, not a committed plan; effort figures are order-of-magnitude pending detailed estimation by the implementing team. The app currently lives in a separate (private) repository, Basic-Data-Infrastructure/cloud-tower-beginnings.

The Cloud Tower app already realises the 2026 use case — combining Portbase data with inland-terminal data into a dashboard for import containers moving over barge into the hinterland. It was originally generated on Supabase (PostgREST data API, Supabase Auth, Deno Edge Functions, Supabase Realtime, ~53 Row-Level-Security policies). Porting it onto the CTN stack converges the use-case dashboard with the target architecture and lets it consume the Association Register (ASR) and endpoint registration as a first-class data consumer.

CTN concept (see System Scope and Context)Cloud Tower mapping
Use case “Visibility Achterland Containerlogistiek”This app — the import-container hinterland dashboard
Data consumerThe app — it consumes Portbase (CargoController) and inland-terminal (ITV / Van Berkel) data
Data custodians / providersPoort8 CargoController function (Portbase), Van Berkel ITV (via iSHARE)
Association Register (ASR)Participant onboarding, authentication of authorised representatives, M2M-credential issuance — the app’s external calls should obtain credentials this way instead of hardcoded keys
Endpoint registrationWhere the app registers as a consumer, obtains OAuth client credentials, and discovers provider endpoints
Keycloak (IAM)Replaces Supabase Auth for human login
Local authorisation (VAD-only, 2026)The app enforces authorisation locally — exactly where the current RLS logic must move (into the Quarkus app layer). No central PDP/OPA in 2026 scope.

Porting is feasible and medium-sized — a backend re-platform, not a rewrite. The database is already PostgreSQL, and the heavy business logic (demurrage/detention calculation, Excel import/deduplication, release tri-state) lives in the React frontend, so both move almost for free. Effort concentrates in three areas:

  1. Data API (🔴 largest). Replace the auto-generated Supabase PostgREST API with hand-written Quarkus REST endpoints (quarkus-rest + Hibernate ORM/Panache) and rewrite the frontend data hooks to call them. Frontend data access is centralised in a handful of hooks/pages, which bounds the surface.
  2. Security / authorisation (🔴 highest risk). ~53 Postgres RLS policies are silently bypassed the moment a Quarkus service connects with a privileged role. They must be re-expressed in the app layer (JAX-RS @RolesAllowed + service-layer visibility/ownership checks), with parity tests asserting each former RLS rule before cutover. This matches the CTN 2026 “local authorisation at the data provider” model.
  3. Realtime (🔴). Supabase postgres_changes channels (live per-row sync spinners, live navigation counts) → Quarkus SSE/WebSocket backed by Postgres LISTEN/NOTIFY (or CDC).

Several remaining concerns are net simplifications on the CTN stack:

  • The custom branded-auth-email function is deleted — Keycloak renders branded auth emails via themes (the repo’s keycloak-theme/ module can be reused).
  • Human login moves to Keycloak OIDC (quarkus-oidc), backed by eHerkenning per the CTN model; OTP / magic-link are native Keycloak features.
  • Roles (user_roles + a has_role() DB function) become Keycloak realm/client roles carried in the token.
  • External-API credentials (today hardcoded Portbase key + iSHARE client credentials) become M2M credentials issued via the ASR, with endpoints discovered via endpoint registration — removing hardcoded secrets and aligning with CTN.
  • The sync edge functions (portbase-sync, itv-sync, scheduled-sync, queue/trigger functions) become Quarkus @Scheduled jobs + MicroProfile REST clients; logic ports cleanly (Deno-TS → Java is mechanical).
  • Email decouples from the current third-party (Lovable) email API to a standard provider via quarkus-mailer.
  • Telemetry moves from a hardcoded Azure App Insights connection string to native OpenTelemetry/Micrometer.

A strangler-fig migration keeps the dashboard shippable throughout:

  1. Phase 0 — Stand up the Quarkus service alongside Supabase; Liquibase owns a copy of the schema (TDR-0001); read-only containers endpoints; validate Keycloak login against a CTN realm.
  2. Phase 1 — Auth cutover to Keycloak/OIDC; migrate roles into Keycloak. (Lowest-risk visible change; unblocks the rest.)
  3. Phase 2 — Move reads (dashboards, counts, tracking) to Quarkus REST + SSE; re-implement visibility/role checks with RLS-parity tests.
  4. Phase 3 — Move writes and the sync jobs; switch external calls to ASR-issued M2M credentials; retire the third-party email path.
  5. Phase 4 — Decommission Supabase; final data cutover.

Order of magnitude: a few weeks for an experienced Quarkus team, gated by Phases 2–3 (data API + RLS parity + realtime). The repo’s asr-service provides a working Quarkus + Keycloak template to clone conventions from.

  • 🔴 Invisible RLS. Most access control is currently enforced in the database, not in code. Migrating to a privileged Quarkus DB connection removes that protection unless re-implemented and parity-tested first. This is the item most likely to introduce a security gap if rushed.
  • 🔴 Realtime is a feature, not polish. Per-row sync feedback and live counts depend on it; the SSE + LISTEN/NOTIFY replacement needs deliberate design (reconnection, fan-out, stream auth).
  • 🟡 auth.uid() coupling. Migrations/policies reference Supabase’s auth schema; these must be translated to app-supplied identity during the Liquibase port.
  • 🟡 Two identity models. Human representatives (eHerkenning via Keycloak) vs. machine sync (M2M via ASR) — keep them distinct in the token/authorisation design.
  • 🟡 iSHARE specifics carry over. The inland-terminal sync already tolerates iSHARE 403 "No Policy"; preserve that when re-issuing the call via ASR-managed credentials.
  • Confirm the CTN model for this app: data-consumer registration + M2M credentials via the ASR for the Portbase / inland-terminal (iSHARE) calls.
  • Confirm Keycloak handles human login (eHerkenning-backed) for the dashboard’s operator/admin roles.
  • Confirm Liquibase ownership of the ported schema (TDR-0001).
  • Decide timing relative to the 2026 ASR / endpoint-registration deliverables.

In samenwerking met

Connected Trade NetworkConclusionData in LogisticsContargoInland Terminals GroupVan Berkel