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

266 lines
7.0 KiB
Markdown

# 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 <DigitalTeamMemberCardClient user={user} />
```
## 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