Skip to content
Build 9234610

The DeLorean

Internal tooling platform for the Integrations Engineering and Doc Control teams. Two self-serve applications are served from a single Spring Boot process, both protected by Azure AD SSO.

Jira: CI-394 | Port: 8081 | Java 21 / Spring Boot 3.2.5 | Repo: the-delorean

App Path Purpose
The DeLorean / /queues/** /topics/** Azure Service Bus Dead Letter Queue manager
SKUdo /skudo/** SKU resubmission through the Arena sync pipeline

Users land on /home after login and navigate into either app. Tiles are shown only for apps the user has access to (controlled by Azure AD App Roles).


The DeLorean — DLQ Manager

Enables the Integrations Engineering team to browse Azure Service Bus queues and topics, inspect dead-letter messages, and repush or delete them — without needing direct Azure Portal access.

Features

Queue & Topic Browser

The left sidebar lists all queues and topics fetched from Azure Service Bus at startup. Selecting a queue or topic opens the Dead Letter sub-queue for that entity.

Dead Letter Message Inspector

Each DLQ entry shows:

  • Message ID, sequence number, and enqueue time
  • Dead-letter reason and error description
  • Full message body (formatted JSON where applicable)
  • Application properties

Repush

Repush sends the original message body back to the entity's primary queue/topic, preserving application properties. Available to ROLE_ADMIN users only.

  • Repush single — repush one message
  • Repush all — repush every message currently in the DLQ

Delete

Permanently removes a message from the DLQ without reprocessing it. Available to ROLE_ADMIN users only.

  • Delete single — delete one message
  • Delete all — purge every message in the DLQ

The Bootstrap-based navbar shows the authenticated user's display name, their role badge (ADMIN / USER), an All Apps link back to /home, and a logout button.

Tech Stack

  • Java 21 (Amazon Corretto 21)
  • Spring Boot 3.2.5
  • Thymeleaf 3.1 (server-side HTML rendering)
  • Azure Service Bus SDK (azure-messaging-servicebus)
  • Spring Security OAuth2 Client (Azure AD SSO via OIDC)
  • Spring Data JPA + PostgreSQL
  • Bootstrap 5

Configuration

# application.properties
spring.application.name=dlq-manager
server.port=8081

azure.servicebus.connection-string=<service-bus-connection-string>

Environment-specific connection strings are stored in the Spring Cloud Config Server.


SKUdo — SKU Resubmission

Enables the Doc Control team to resubmit one or more SKUs through the full Arena sync pipeline — covering OMS, Batching, Jackyun, and NAV — without escalating to the Integrations Engineering team.

Call Chain

The DeLorean / SKUdo UI (the-delorean :8081, path /skudo)
  --> cm-int-service-exp  (Spring Boot + Apache Camel passthrough)
        --> cm-product-prc  (core processing)
              --> Arena API          (item fetch)
              --> OMS                (cache invalidation)
              --> Batching           (BOM update)
              --> Jackyun            (product upsert)
              --> NAV                (NAV sync)

Component Responsibilities

Component Responsibility
the-delorean (/skudo) Thymeleaf UI. Handles Azure AD auth, collects SKUs & system checkboxes, calls exp layer via RestTemplate, renders results and repush history.
cm-int-service-exp Passthrough API layer. Validates APIM key, routes request via Apache Camel to cm-product-prc.
cm-product-prc Core sync engine. Fetches each SKU from Arena and fans out to OMS, Batching, Jackyun, and/or NAV.
Spring Cloud Config Server Provides environment-specific properties (URLs, APIM keys) at startup.

Features

Environment Tabs

Tabs are driven by the active Spring profile:

  • nonprod profile → DEV, QA, STAGE tabs
  • prod profile → PROD tab only

Each tab is colour-coded (DEV = blue, QA = green, STAGE = amber, PROD = red). Selecting a tab switches the target URL and APIM key.

SKU Input

Accepts flexible input formats:

  • One SKU per line
  • Comma-separated values
  • JSON array (e.g. ["703434", "807718"])

SKUs are deduplicated and stripped of surrounding quotes automatically. Maximum 5 SKUs per request (enforced server-side in SkuDoController).

Per-System Targeting

Checkboxes allow Doc Control to target individual downstream systems:

System Operation
OMS Cache invalidation
Batching BOM update
Jackyun Product upsert
NAV NAV sync

All systems are checked by default. Unchecking a system excludes it from the fan-out — useful when only one system failed and needs to be retried independently.

Repush History Panel

A history panel is shown to the right of the submission form, scoped to the active environment tab. It displays the last 30 resubmission entries for that environment, stored in PostgreSQL.

Each history entry shows:

  • Timestamp of the submission
  • SKUs that were submitted
  • Target systems
  • Per-SKU per-system result (OK / FAILED) shown as expandable badges
  • Success and failure counts
  • Name of the user who submitted

History is recorded automatically on every API call and trimmed to the most recent 30 entries per environment.

Results Table

After submission, a per-SKU results table is shown. Columns are rendered conditionally based on which systems were selected. Each cell shows OK (green) or FAILED (red) with the error message on failure. A summary badge at the top shows total SKUs, successes, and failures.

Submit Button Validation

  • Disabled until at least one SKU is entered and at least one system checkbox is checked.
  • Disables and shows Processing... on submit to prevent double-submission.

SKUdo API Contract

POST /sku/resync on cm-int-service-exp:

POST /sku/resync
Ocp-Apim-Subscription-Key: <apim-key>
Content-Type: application/json
{
  "skus": ["703434", "807718"],
  "systems": ["OMS", "BATCHING", "JACKYUN", "NAV"]
}
{
  "703434": { "oms": "OK", "batching": "OK", "jackyun": "OK" },
  "807718": { "oms": "FAILED: HTTP 500 Internal Server Error", "batching": "OK", "jackyun": "OK" }
}
  • "OK" — system processed the SKU successfully.
  • "FAILED: <reason>" — system returned an error; reason contains HTTP status or exception message.

SKUdo Configuration

Properties stored in the Spring Cloud Config Server:

# dlq-manager-nonprod.yml
exp:
  service:
    environments:
      DEV:
        url: http://<cm-int-service-exp-dev-host>/sku/resync
        apimKey: <nonprod-apim-key>
      QA:
        url: http://<cm-int-service-exp-qa-host>/sku/resync
        apimKey: <nonprod-apim-key>
      STAGE:
        url: http://<cm-int-service-exp-stage-host>/sku/resync
        apimKey: <nonprod-apim-key>
    connectTimeout: 5000
    readTimeout: 30000

Shared Platform

Authentication

Both apps use Azure AD SSO via Spring Security OAuth2 / OIDC. There is no local username/password login. Users click Sign in with Microsoft and authenticate with their PopSockets Microsoft account.

The login page is at /login. After successful authentication, users land on /home (the app selector).

Azure AD configuration (per profile):

spring:
  security:
    oauth2:
      client:
        registration:
          azure:
            client-id: <app-registration-client-id>
            client-secret: <client-secret>
            scope: openid, profile, email
            redirect-uri: "http://<host>/login/oauth2/code/azure"
            authorization-grant-type: authorization_code
        provider:
          azure:
            issuer-uri: "https://login.microsoftonline.com/<tenant-id>/v2.0"

Access Management

Access to The DeLorean platform is controlled entirely through Azure AD App Roles, assigned per user in the Azure Portal App Registration. No credentials, roles, or user records are stored in the application — the app reads the roles claim from the OIDC token on every login.

The two apps are managed independently. A user can have access to one app, both apps, or neither. Within each app, the role (Admin vs User) is also managed independently — a user can be an Admin in one app and a regular User in the other.

App Roles Overview

Azure AD App Role App Role Level Spring Authorities
DeLorean.Admin The DeLorean Admin ROLE_ADMIN + APP_DELOREAN
DeLorean.User The DeLorean User ROLE_USER + APP_DELOREAN
SkuDo.Admin SKUdo Admin ROLE_ADMIN + APP_SKUDO
SkuDo.User SKUdo User ROLE_USER + APP_SKUDO

The DeLorean — Role Permissions

Action DeLorean.User DeLorean.Admin
Browse queues and topics
View DLQ messages and message body
Repush single message
Repush all messages in a DLQ
Delete single message
Delete all messages in a DLQ

SKUdo — Role Permissions

Action SkuDo.User SkuDo.Admin
View the SKU resubmission form
Submit SKUs for resubmission
View repush history panel
Access all environments (DEV / QA / STAGE / PROD)

Access Rules

  • A user with no recognised role is rejected at login with: "Sign-in failed. You may not have access. Contact your admin."
  • App tiles on /home are only visible for apps the user has access to. A user with only SkuDo.User will not see The DeLorean tile and cannot access /queues/** or /topics/**.
  • A user may hold roles for both apps simultaneously — for example DeLorean.User + SkuDo.Admin. Each app's role level is independent.
  • Admin in one app does not grant admin in the other. DeLorean.Admin has no effect on SKUdo, and vice versa.

How to Assign Roles (Azure Portal)

  1. Go to Azure PortalAzure Active DirectoryApp registrations
  2. Open the popsockets-internal-tools app registration
  3. Go to App roles — confirm the four roles are defined (DeLorean.Admin, DeLorean.User, SkuDo.Admin, SkuDo.User)
  4. Go to Enterprise applications → find the same app → Users and groups
  5. Click Add user/group → select the user → select the desired role → Assign
  6. To assign multiple roles to one user, repeat step 5 for each role

Note

A user must sign out and sign back in for role changes to take effect — the roles are read from the OIDC token issued at login time.

How Role Mapping Works (Technical)

AzureAdOAuth2UserService extends Spring Security's OidcUserService. After Azure AD authenticates the user, it reads the roles claim (a JSON array of role name strings) from the ID token and maps each to Spring Security GrantedAuthority objects:

DeLorean.Admin  →  ROLE_ADMIN  +  APP_DELOREAN
DeLorean.User   →  ROLE_USER   +  APP_DELOREAN
SkuDo.Admin     →  ROLE_ADMIN  +  APP_SKUDO
SkuDo.User      →  ROLE_USER   +  APP_SKUDO

SecurityConfig then enforces these authorities at the URL level:

/skudo/**                         → requires  APP_SKUDO
/ , /queues/**, /topics/**        → requires  APP_DELOREAN
POST repush/delete endpoints      → requires  ROLE_ADMIN  (DeLorean only)
/home                             → requires  authenticated

No database lookup is performed during authentication.

Database

PostgreSQL, shared between both apps. JPA ddl-auto=update — tables are auto-created on first startup, no migration scripts needed for additive changes.

Table App Purpose
skudo_history SKUdo Last 30 repush entries per environment. Columns: id, environment, skus (JSON), systems, results (JSON), success_count, fail_count, pushed_at, pushed_by.

Spring Profiles

Profile Purpose
local Local dev. Disables Spring Cloud Config, sets DB / Service Bus directly, dummy Azure AD placeholders.
nonprod Pulls config from Spring Cloud Config Server. Shows DEV / QA / STAGE environments.
prod Production. Shows PROD environment only.

Project Structure

the-delorean/
+-- pom.xml
+-- src/main/java/com/popsockets/dlqmanager/
|   +-- config/
|   |   +-- SecurityConfig.java              (OAuth2 login, URL → authority rules)
|   |   +-- SkuDoProperties.java             (@ConfigurationProperties env map)
|   +-- controller/
|   |   +-- DlqController.java               (DeLorean queue/topic/DLQ actions)
|   |   +-- HomeController.java              (/home app selector)
|   |   +-- SkuDoController.java             (GET /skudo, POST /skudo/resync)
|   |   +-- ProfileController.java           (/profile — user info)
|   +-- model/
|   |   +-- SkuDoHistory.java                (JPA entity — repush history)
|   +-- repository/
|   |   +-- SkuDoHistoryRepository.java      (top-30-per-env query)
|   +-- security/
|   |   +-- AzureAdOAuth2UserService.java    (reads AD App Roles, builds authorities)
|   +-- service/
|       +-- DlqService.java                  (Azure Service Bus operations)
|       +-- SkuDoService.java                (RestTemplate call, history save/fetch)
+-- src/main/resources/
|   +-- application.properties              (base config)
|   +-- application-local.yml               (local dev overrides)
|   +-- application-nonprod.yml             (nonprod Azure AD config)
|   +-- application-prod.yml                (prod Azure AD config)
+-- src/main/resources/templates/
    +-- login.html                           (Azure AD sign-in button)
    +-- home.html                            (app selector — DeLorean + SKUdo tiles)
    +-- layout.html                          (Bootstrap navbar used by DeLorean pages)
    +-- skudo/
        +-- index.html                       (two-column: form + history panel)
        +-- results.html                     (per-SKU results table)

Key Class Descriptions

Class Responsibility
AzureAdOAuth2UserService Extends OidcUserService. Reads roles claim from AD token, maps App Roles to Spring Security authorities. Rejects users with no recognised role.
SecurityConfig Configures OAuth2 login (no form login). Maps URL patterns to required authorities.
DlqService Wraps Azure Service Bus SDK. Browse entities, peek/receive DLQ messages, repush, delete.
SkuDoController GET /skudo renders form + history. POST /skudo/resync validates (max 5 SKUs, ≥1 system), calls service, renders results. Gets logged-in user from @AuthenticationPrincipal OidcUser.
SkuDoService Calls cm-int-service-exp via RestTemplate. Saves repush history to DB. Fetches history per environment.
SkuDoHistoryRepository JPA repository. findTop30ByEnvironmentOrderByPushedAtDesc returns the last 30 entries per environment.
SkuDoHistory JPA entity mapping to skudo_history. Stores SKUs and results as JSON strings.
SkuDoProperties @ConfigurationProperties bean. Loads the environments map (URL + APIM key per env). Insertion order preserved via LinkedHashMap so tab order matches config order.

How to Run Locally

Warning

Must use Amazon Corretto 21. Lombok's annotation processor crashes on other JDKs.

export JAVA_HOME=/Users/dahamindrajith/Library/Java/JavaVirtualMachines/corretto-21.0.11/Contents/Home

Warning

VPN must be connected for Spring Cloud Config Server and internal service endpoints.

# Build (skip tests — no test suite exists yet)
mvn clean package -DskipTests

# Run nonprod
mvn spring-boot:run -Dspring-boot.run.profiles=nonprod

# Run local (no Config Server required)
mvn spring-boot:run -Dspring-boot.run.profiles=local

For full SKUdo testing, also start:

  1. Spring Cloud Config Server (cm-spring-cloud-config-server) on port 8888
  2. cm-product-prc on port 8088 with the dev profile
  3. cm-int-service-exp on port 8081 with the dev profile

Then navigate to http://localhost:8081/login, click Sign in with Microsoft, and authenticate with your PopSockets Microsoft account. The DeLorean and SKUdo tiles appear based on your Azure AD App Roles.


Future Expansion Options

Option 1 — Power Automate: Auto-Resync from Teams Failure Alerts

When SKUdo sends a failure alert to a Teams channel, a Power Automate flow can detect that message and automatically trigger the resync API for the failed SKUs — without any manual intervention.

Attribute Detail
Effort Low — no code changes required; built entirely in Power Automate
Risk Medium — risk of retry loop if alert format is inconsistent or cooldown is not applied
Prerequisites Teams Incoming Webhook configured, APIM key available, Power Automate license
Priority Medium

Option 2 — Sync Status Dashboard

A read-only view showing the last known sync status for one or more SKUs across OMS, Batching, and Jackyun. Useful for verifying state before deciding whether to resubmit.

Attribute Detail
Effort Medium — requires status query endpoints in cm-product-prc
Risk Very low — read-only
Priority High — pairs naturally with SKU resubmission