@@ -22,8 +22,9 @@ The LFX Survey Service acts as a lightweight proxy to the ITX Survey API service
2222
23231 . ** Authentication Translation** - JWT (Heimdall) → OAuth2 M2M (Auth0)
24242 . ** Authorization** - OpenFGA fine-grained access control
25- 3 . ** Field Mapping** - LFX v2 conventions → ITX conventions
26- 4 . ** Stateless Proxy** - No local persistence, all data managed by ITX
25+ 3 . ** ID Mapping** - V2 UUIDs → V1 Salesforce IDs (via NATS)
26+ 4 . ** Field Mapping** - LFX v2 conventions → ITX conventions
27+ 5 . ** Stateless Proxy** - No local persistence, all data managed by ITX
2728
2829---
2930
@@ -45,7 +46,8 @@ The LFX Survey Service acts as a lightweight proxy to the ITX Survey API service
4546│ ┌────────────────────────────────────────────────────────┐ │
4647│ │ Service Layer (Proxy Logic) │ │
4748│ │ - JWT Authentication via Heimdall │ │
48- │ │ - Field mapping (project_uid ↔ project_id) │ │
49+ │ │ - ID mapping (V2 UIDs ↔ V1 SFIDs via NATS) │ │
50+ │ │ - Field mapping (committee_uid → committees array) │ │
4951│ │ - Request/response transformation │ │
5052│ └────────────────────┬───────────────────────────────────┘ │
5153│ │ │
@@ -146,15 +148,16 @@ func (s *SurveyService) ScheduleSurvey(ctx context.Context, p *survey.ScheduleSu
146148 return nil , &survey.UnauthorizedError {...}
147149 }
148150
149- // 2. Map v2 project UID to v1 project ID (if ID mapping enabled )
150- v1ProjectID , err := s.idMapper .MapProjectV2ToV1 (ctx, p.ProjectUID )
151+ // 2. Map v2 committee UID to v1 committee SFID (via NATS )
152+ committeeV1 , err := s.idMapper .MapCommitteeV2ToV1 (ctx, p.CommitteeUID )
151153 if err != nil {
152154 return nil , mapDomainError (err)
153155 }
154156
155- // 3. Build ITX request (field mapping: project_uid → project_id)
156- itxRequest := &itx.SurveyScheduleRequest {
157- ProjectID: v1ProjectID,
157+ // 3. Build ITX request (field mapping: committee_uid → committees array)
158+ committees := []string {committeeV1}
159+ itxRequest := &itx.ScheduleSurveyRequest {
160+ Committees: committees,
158161 CreatorID: p.CreatorID ,
159162 SurveyTitle: p.SurveyTitle ,
160163 // ... other fields are identical
@@ -166,8 +169,11 @@ func (s *SurveyService) ScheduleSurvey(ctx context.Context, p *survey.ScheduleSu
166169 return nil , mapDomainError (err)
167170 }
168171
169- // 5. Convert ITX response to Goa result
170- result := mapITXResponseToResult (itxResponse)
172+ // 5. Convert ITX response to Goa result (maps V1 IDs back to V2 UIDs)
173+ result , err := s.mapITXResponseToResult (ctx, itxResponse)
174+ if err != nil {
175+ return nil , mapDomainError (err)
176+ }
171177
172178 return result, nil
173179}
@@ -231,14 +237,14 @@ func (c *Client) ScheduleSurvey(ctx context.Context, req *itx.SurveyScheduleRequ
231237 POST /surveys
232238 Authorization: Bearer <jwt_token>
233239 {
234- "project_uid ": "v2-project -uuid",
240+ "committee_uid ": "v2-committee -uuid",
235241 "survey_title": "Q1 Survey",
236242 ...
237243 }
238244 ↓
2392452. Heimdall Authorization
240246 - Validates JWT
241- - Checks OpenFGA: user has "writer" permission on project
247+ - Checks OpenFGA: user has "writer" permission on committee
242248 - Adds JWT to context
243249 ↓
2442503. API Handler (api.go)
@@ -247,8 +253,8 @@ func (c *Client) ScheduleSurvey(ctx context.Context, req *itx.SurveyScheduleRequ
2472534. Service Layer (survey_service.go)
248254 ScheduleSurvey()
249255 ├─→ Parse JWT and extract principal
250- ├─→ Map v2 project UID to v1 project ID (via NATS)
251- ├─→ Build ITX request (field mapping)
256+ ├─→ Map v2 committee UID to v1 committee SFID (via NATS)
257+ ├─→ Build ITX request (field mapping: committee_uid → committees array )
252258 └─→ Call proxy client
253259 ↓
2542605. Proxy Client (infrastructure/proxy/itx_client.go)
@@ -262,7 +268,7 @@ func (c *Client) ScheduleSurvey(ctx context.Context, req *itx.SurveyScheduleRequ
262268 POST /v2/surveys/schedule
263269 Authorization: Bearer <oauth2_m2m_token>
264270 {
265- "project_id ": "v1-project-id" ,
271+ "committees ": [ "v1-committee-sfid"] ,
266272 "survey_title": "Q1 Survey",
267273 ...
268274 }
@@ -274,13 +280,17 @@ func (c *Client) ScheduleSurvey(ctx context.Context, req *itx.SurveyScheduleRequ
274280 ↓
2752819. Service Layer
276282 - Converts ITX response to Goa result
277- - No field mapping needed (response fields identical)
283+ - Maps V1 committee/project SFIDs back to V2 UIDs
278284 ↓
27928510. API Response
280286 201 Created
281287 {
282288 "id": "survey-uuid",
283- "project_uid": "v2-project-uuid",
289+ "committees": [{
290+ "committee_uid": "v2-committee-uuid",
291+ "project_uid": "v2-project-uuid",
292+ ...
293+ }],
284294 "survey_title": "Q1 Survey",
285295 ...
286296 }
@@ -313,8 +323,17 @@ type AuthenticationService interface {
313323
314324``` go
315325type IDMapper interface {
326+ // MapCommitteeV2ToV1 maps LFX v2 committee UID to v1 Salesforce ID
327+ MapCommitteeV2ToV1 (ctx context.Context , v2UID string ) (string , error )
328+
329+ // MapCommitteeV1ToV2 maps v1 committee SFID to LFX v2 UID
330+ MapCommitteeV1ToV2 (ctx context.Context , v1SFID string ) (string , error )
331+
316332 // MapProjectV2ToV1 maps LFX v2 project UID to v1 Salesforce ID
317- MapProjectV2ToV1 (ctx context.Context , v2ID string ) (string , error )
333+ MapProjectV2ToV1 (ctx context.Context , v2UID string ) (string , error )
334+
335+ // MapProjectV1ToV2 maps v1 project SFID to LFX v2 UID
336+ MapProjectV1ToV2 (ctx context.Context , v1SFID string ) (string , error )
318337}
319338```
320339
@@ -360,33 +379,42 @@ type ITXProxyClient interface {
360379
361380### Request Field Mapping (Proxy → ITX)
362381
363- Only one field differs between Proxy API and ITX API:
382+ Field differences between Proxy API and ITX API:
364383
365384| Proxy API (LFX) | ITX API | Notes |
366385| -----------------| ---------| -------|
367- | ` project_uid ` | ` project_id ` | V2 UUID → V1 Salesforce ID (mapped via NATS) |
386+ | ` committee_uid ` (single string) | ` committees ` (array of strings) | Proxy accepts single committee UID, converted to array for ITX |
387+ | Committee/Project values | Mapped values | V2 UUIDs → V1 Salesforce IDs (mapped via NATS) |
368388| All other fields | Same | Identical field names |
369389
370390** Example** :
371391
372392``` go
373393// Proxy API request
374394{
375- " project_uid " : " 7cad5a8d-19d0-41a4-81a6-043453daf9ee " , // V2 UUID
395+ " committee_uid " : " qa1e8536-a985-4cf5-b981-a170927a1d11 " , // V2 UUID (single)
376396 " survey_title" : " Q1 Survey"
377397}
378398
379399// After ID mapping and field conversion
380400// ITX API request
381401{
382- " project_id " : " a0A1700000DxYzEEAV " , // V1 Salesforce ID
402+ " committees " : [ " a0C17000000abcDEF " ] , // V1 Salesforce ID (array)
383403 " survey_title" : " Q1 Survey"
384404}
385405```
386406
387407### Response Field Mapping (ITX → Proxy)
388408
389- No field mapping required for responses - all field names are identical between ITX API and Proxy API.
409+ Response IDs are mapped from V1 to V2:
410+
411+ | ITX API Response | Proxy API Response | Notes |
412+ | -----------------| -------------------| -------|
413+ | ` committee_id ` | ` committee_uid ` | V1 Salesforce ID → V2 UUID (mapped via NATS) |
414+ | ` project_id ` | ` project_uid ` | V1 Salesforce ID → V2 UUID (mapped via NATS) |
415+ | All other fields | Same | Identical field names |
416+
417+ ** Fallback Strategy** : If V1→V2 mapping fails, the service falls back to returning V1 IDs with warning logs rather than failing the request.
390418
391419### Path Mapping
392420
0 commit comments