11// Copyright The Linux Foundation and each contributor to LFX.
22// SPDX-License-Identifier: MIT
33
4- import { AddEmailRequest , CombinedProfile , ProfileUpdateRequest , UpdateEmailPreferencesRequest , UserMetadataUpdateRequest } from '@lfx-one/shared/interfaces' ;
4+ import {
5+ AddEmailRequest ,
6+ CombinedProfile ,
7+ ProfileUpdateRequest ,
8+ UpdateEmailPreferencesRequest ,
9+ UserMetadata ,
10+ UserMetadataUpdateRequest ,
11+ } from '@lfx-one/shared/interfaces' ;
512import { NextFunction , Request , Response } from 'express' ;
613
714import { AuthenticationError , AuthorizationError , MicroserviceError , ResourceNotFoundError , ServiceValidationError } from '../errors' ;
@@ -41,7 +48,27 @@ export class ProfileController {
4148
4249 let combinedProfile : CombinedProfile | null = null ;
4350
44- // Get combined profile using JOIN
51+ // Step 1: Try to get user metadata from NATS first (authoritative source)
52+ let natsUserData : UserMetadata | null = null ;
53+ try {
54+ const natsResponse = await this . userService . getUserInfo ( req , userId ) ;
55+ req . log . info ( { userId, natsSuccess : natsResponse . success } , 'Fetched user data from NATS' ) ;
56+
57+ if ( natsResponse . success && natsResponse . data ) {
58+ natsUserData = natsResponse . data ;
59+ }
60+ } catch ( error ) {
61+ // Log but don't fail - we'll fall back to Supabase
62+ req . log . warn (
63+ {
64+ userId,
65+ error : error instanceof Error ? error . message : error ,
66+ } ,
67+ 'Failed to fetch user data from NATS, will use Supabase as fallback'
68+ ) ;
69+ }
70+
71+ // Step 2: Get user from Supabase
4572 const user = await this . supabaseService . getUser ( userId ) ;
4673
4774 if ( ! user ) {
@@ -54,12 +81,20 @@ export class ProfileController {
5481 return next ( validationError ) ;
5582 }
5683
84+ // Step 3: Merge NATS data into Supabase user if available
85+ if ( natsUserData ) {
86+ // Merge fields from NATS, preferring NATS data when available
87+ if ( natsUserData . given_name ) user . first_name = natsUserData . given_name ;
88+ if ( natsUserData . family_name ) user . last_name = natsUserData . family_name ;
89+ // Note: email and username are not part of UserMetadata, they come from the user table
90+ }
91+
5792 combinedProfile = {
5893 user,
5994 profile : null ,
6095 } ;
6196
62- // Get profile details
97+ // Step 4: Get profile details from Supabase
6398 const profile = await this . supabaseService . getProfile ( user . id ) ;
6499
65100 // If no profile details exist, create them
@@ -72,9 +107,38 @@ export class ProfileController {
72107 combinedProfile . profile = profile ;
73108 }
74109
110+ // Step 5: Merge NATS metadata into profile if available
111+ if ( natsUserData && combinedProfile . profile ) {
112+ // Merge all available fields from NATS into the profile
113+ const fieldsToMerge : ( keyof UserMetadata ) [ ] = [
114+ 'name' ,
115+ 'given_name' ,
116+ 'family_name' ,
117+ 'picture' ,
118+ 'phone_number' ,
119+ 'address' ,
120+ 'city' ,
121+ 'state_province' ,
122+ 'postal_code' ,
123+ 'country' ,
124+ 'organization' ,
125+ 'job_title' ,
126+ 't_shirt_size' ,
127+ 'zoneinfo' ,
128+ ] ;
129+
130+ const natsData = natsUserData ;
131+ fieldsToMerge . forEach ( ( field ) => {
132+ if ( natsData [ field ] !== undefined && natsData [ field ] !== null ) {
133+ ( combinedProfile . profile as UserMetadata ) [ field ] = natsData [ field ] ;
134+ }
135+ } ) ;
136+ }
137+
75138 Logger . success ( req , 'get_current_user_profile' , startTime , {
76139 user_id : user . id ,
77140 has_profile_details : ! ! combinedProfile . profile ,
141+ used_nats_data : ! ! natsUserData ,
78142 } ) ;
79143
80144 res . json ( combinedProfile ) ;
0 commit comments