Files
web/apps/scandic-web/docs/DTMC_FLOW.md
Chuma Mcphoy (We Ahead) 7abe190bed Merged in chore/LOY-445-remove-dtmc-flag (pull request #3043)
chore(LOY-445): remove ENABLE_DTMC flag & add documentation

* chore(LOY-445): remove ENABLE_DTMC flag & add documentation


Approved-by: Matilda Landström
2025-10-31 08:39:13 +00:00

7.0 KiB

DTMC (Digital Team Member Card) Flow Documentation

Overview

The DTMC feature allows existing Scandic Friends members to link their employee status to their account by authenticating with Microsoft Entra ID. This provides employees access to additional benefits.

Current Implementation Architecture

Separate Auth Configuration Approach

We use a completely separate auth configuration to avoid session conflicts between:

  • Curity: auth.ts
    • Regular user authentication.
  • DTMC Auth: auth.dtmc.ts
    • Short-lived (10min) session specifically for employee verification.

Key Files & Responsibilities

Flow Handlers

  • app/[lang]/(live)/(public)/dtmc/route.ts
    • Microsoft auth initiation.
  • app/api/web/auth/dtmc/route.ts
    • Employee linking callback handler with API integration.

Core Authentication

  • auth.dtmc.ts
    • Microsoft Entra ID provider configuration, JWT/session callbacks.
  • app/api/web/auth/[...nextauth]/route.ts
    • Routes Microsoft requests to DTMC handlers.

API Integration

  • packages/trpc/lib/api/endpoints.ts
    • API endpoint definitions including TeamMemberCard.
  • server/routers/user/output.ts
    • Profile schema with employmentDetails.
  • utils/user.ts
    • Employment utility functions.

UI Components

  • apps/scandic-web/components/MyPages/DigitalTeamMemberCard/index.tsx
    • Main card component.
  • apps/scandic-web/components/MyPages/DigitalTeamMemberCard/Alert/index.tsx
    • Banner shown on the overview page for employee's who have just linked their account.

Configuration

  • constants/routes/dtmc.ts - Route definitions
  • components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/index.tsx
    • "Link Employment" buttons used within the Employee Benefits page (a Contentstack "content page") to initiate the linking process.

Technical Flow

1. User Journey

User (Curity authenticated) → Employee Benefits page → "Link Employment" button →
Microsoft Auth → Employee ID extraction → API linking → Success redirect

2. Detailed Technical Sequence

sequenceDiagram
    participant U as User
    participant C as Curity Session
    participant D as DTMC Route
    participant M as Microsoft Auth
    participant J as JWT Callback
    participant S as Session Callback
    participant H as DTMC Handler
    participant A as Employee API

    U->>C: Already authenticated (Curity)
    U->>D: Click "Link Employment" → /[lang]/dtmc
    D->>M: signIn("microsoft-entra-id")
    M->>U: Microsoft login prompt
    U->>M: Authenticate with corporate credentials
    M->>J: Profile with user.employeeid
    J->>J: Store employeeId directly in token
    J->>S: Expose as session.employeeId
    S->>H: Callback to /api/web/auth/dtmc
    H->>H: Validate both Curity + DTMC sessions
    H->>A: Call linkEmployeeToUser(employeeId)
    A->>H: Success response
    H->>U: Redirect to overview with success banner

3. Code Implementation Details

DTMC Auth Configuration (auth.dtmc.ts)

// Separate session cookie to avoid conflicts
cookies: {
  sessionToken: {
    name: "dtmc.session-token",
  },
}

// Short-lived session for security
session: {
  strategy: "jwt",
  maxAge: 10 * 60, // 10 minutes
}

// Storage of employeeId
jwt({ account, profile, token }) {
  if (account?.provider === "microsoft-entra-id") {
    const employeeId = profile["user.employeeid"]
    return {
      access_token: "", // Empty to save cookie size
      loginType: "dtmc",
      employeeId,
    }
  }
}

Route Routing ([...nextauth]/route.ts)

Routes Microsoft requests to DTMC handlers by checking if the pathname contains "microsoft-entra-id".

Auth Initiation (/dtmc/route.ts)

// Starts Microsoft signin with callback redirect
const redirectUrl = await signIn(
  "microsoft-entra-id",
  {
    redirectTo: `${env.PUBLIC_URL}${dtmcApiCallback}`,
    redirect: false,
  },
  {
    prompt: "login",
  }
)

Callback Handler (/api/web/auth/dtmc/route.ts)

// Validates dual sessions and processes linking
const dtmcSession = await dtmcAuth() // Microsoft session
const session = await auth() // Curity session

// Both sessions required for security
if (!isValidSession(session) || !isValidSession(dtmcSession)) {
  // Redirect to error page
}

const employeeId = dtmcSession.employeeId
await linkEmployeeToUser(employeeId, accessToken)

Routes & URLs

User-Facing Routes

  • /[lang]/dtmc - Microsoft auth initiation
  • /[lang]/link-employment-error - Error handling page
  • /[lang]/employee-benefits - Employee benefits overview

API Routes

  • /api/web/auth/dtmc - Employee linking callback handler
  • /api/web/auth/[...nextauth] - NextAuth routing (handles Microsoft provider)

API Integration Details

TeamMemberCard Endpoint

// Added to packages/trpc/lib/api/endpoints.ts
export namespace v2 {
  export namespace Profile {
    export function teamMemberCard(employeeId: string) {
      return `${profile}/${employeeId}/TeamMemberCard`
    }
  }
}

Profile Schema Extension

// Added to server/routers/user/output.ts
export const employmentDetailsSchema = z
  .object({
    employeeId: z.string(),
    location: z.string(),
    country: z.string(),
    retired: z.boolean(),
  })
  .optional()

Employee Utility Functions

// Added to utils/user.ts
export function isEmployeeLinked(user: User): boolean
export function getEmployeeInfo(user: User)
export function canUseEmployeeBenefits(user: User): boolean

Status Code Handling

  • 200/202: Success → Continue to overview page
  • 400/404: Client errors → "unable_to_verify_employee_id" error page
  • 500: Server error → Default error message
  • Network errors: → Default error message

Digital Team Member Card Behavior

// Current implementation
const hasEmploymentData = isEmployeeLinked(user)

if (!hasEmploymentData) {
  return null
}
return <DigitalTeamMemberCardClient user={user} />

Testing Checklist

Happy Path

  • User has valid Curity session
  • Microsoft auth extracts employee ID successfully
  • Both sessions validated in callback handler
  • Employee linking API call succeeds
  • User redirected to overview with success banner
  • Original Curity session remains functional
  • Digital Team Member Card displays with employment data

Error Scenarios

  • Missing Curity session during flow
  • Microsoft auth failure/cancellation
  • Missing employee ID in Microsoft profile
  • Employee API failure scenarios
  • DTMC session expiration
  • Status code mapping (400/404/500/network errors)

Security Validation

  • No employee ID in browser network logs
  • No employee ID in URL parameters
  • Dual session architecture working
  • Proper session validation in callback
  • Short-lived DTMC session (10 minutes) for security

UI/UX Validation

  • Card shows real data when employment details exist
  • Proper fallbacks for missing employment data fields