# 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 ```mermaid 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`) ```typescript // 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`) ```typescript // 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`) ```typescript // 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 ```typescript // 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 ```typescript // 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 ```typescript // 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 ```typescript // Current implementation const hasEmploymentData = isEmployeeLinked(user) if (!hasEmploymentData) { return null } return ``` ## Testing Checklist ### Happy Path - [x] User has valid Curity session - [x] Microsoft auth extracts employee ID successfully - [x] Both sessions validated in callback handler - [x] Employee linking API call succeeds - [x] User redirected to overview with success banner - [x] Original Curity session remains functional - [x] Digital Team Member Card displays with employment data ### Error Scenarios - [x] Missing Curity session during flow - [x] Microsoft auth failure/cancellation - [x] Missing employee ID in Microsoft profile - [x] Employee API failure scenarios - [x] DTMC session expiration - [x] Status code mapping (400/404/500/network errors) ### Security Validation - [x] No employee ID in browser network logs - [x] No employee ID in URL parameters - [x] Dual session architecture working - [x] Proper session validation in callback - [x] Short-lived DTMC session (10 minutes) for security ### UI/UX Validation - [x] Card shows real data when employment details exist - [x] Proper fallbacks for missing employment data fields