department-of-veterans-affairs / va.gov-team

Public resources for building on and in support of VA.gov. Visit complete Knowledge Hub:
https://depo-platform-documentation.scrollhelp.site/index.html
283 stars 204 forks source link

Discovery: NoK/EC edit architecture (VA Profile API) #89208

Closed fmccaf1 closed 1 month ago

fmccaf1 commented 3 months ago

Description

User story

As a Cartographer, I want to document any issues with the back-end architecture around contacts, so that we can kick off development to make updates to health-care contacts.

Notes

Possible tasks:

Acceptance criteria

dcloud commented 2 months ago

Per my comments on the vets-api discovery ticket:

The VA Profile Health Benefit Service has 3 endpoints, and the VAProfile::HealthBenefit::Service in vets-api currently implements the /read endpoint but not the /update or /notification endpoint. The example in the VA Profile health-benefit swagger docs shows a complex JSON body with a wide range of attributes in addition to the associatedPersons array.

The /notification endpoint doc mentions a vaProfileTxAuditId as a parameter, though the /update endpoint doesn't appear to promise to return a transaction audit id in the HealthBenefitUpdateResponse. **We should find out if we would get a vaProfileTxAuditId from a HealthBenefit update API call, despite the documentation

Possible Qs

dcloud commented 2 months ago

Schema for HealthBenefit update endpoint below. Note the "QOther Next of KinE" has either a Q/E or \Q/\E thing going on. The escaped chars appear in the AP023 description for the contactType field…

{
  "identity": {
    "sourceDate": "2024-09-03T17:16:51.873Z",
    "originatingSourceSystem": "string",
    "sourceSystemUser": "string",
    "sensitivityInformation": {
      "sourceDate": "2024-09-03T17:16:51.873Z",
      "originatingSourceSystem": "string",
      "sourceSystemUser": "string",
      "sensitivityFlag": true,
      "sensitivityChangeDate": "2024-09-03T17:16:51.873Z",
      "sensitivityChangeSource": "QVBAE",
      "sensitivityChangeSite": "string"
    }
  },
  "associatedPersons": [
    {
      "sourceDate": "2024-09-03T17:16:51.873Z",
      "originatingSourceSystem": "string",
      "sourceSystemUser": "string",
      "contactType": "QOther Next of KinE",
      "prefix": "string",
      "givenName": "string",
      "middleName": "string",
      "familyName": "string",
      "suffix": "string",
      "relationship": "string",
      "addressLine1": "string",
      "addressLine2": "string",
      "addressLine3": "string",
      "city": "string",
      "state": "string",
      "county": "string",
      "zipCode": "string",
      "zipPlus4": "string",
      "postalCode": "string",
      "provinceCode": "string",
      "country": "string",
      "primaryPhone": "string",
      "alternatePhone": "string",
      "effectiveEndDate": "2024-09-03T17:16:51.873Z"
    }
  ],
  "healthCareCoverages": [
    {
      "sourceDate": "2024-09-03T17:16:51.873Z",
      "originatingSourceSystem": "string",
      "sourceSystemUser": "string",
      "planType": "QMajor Medical Expense InsuranceE",
      "insuredRelationship": "QOtherE",
      "companyName": "string",
      "groupName": "string",
      "groupNumber": "string",
      "enrolledInPartA": true,
      "enrolledInPartB": true,
      "partAEffectiveDate": "string",
      "policyEffectiveDate": "string",
      "partBEffectiveDate": "string",
      "policyExpirationDate": "string",
      "policyHolderName": "string",
      "policyNumber": "string",
      "preadmitCertification": true,
      "lastEditedDate": "2024-09-03T17:16:51.873Z",
      "addressLine1": "string",
      "addressLine2": "string",
      "addressLine3": "string",
      "city": "string",
      "state": "st",
      "county": "string",
      "zipCode": "strin",
      "zipPlus4": "stri",
      "provinceCode": "string",
      "postalCode": "string",
      "country": "string",
      "addressChangeDateTime": "2024-09-03T17:16:51.873Z",
      "addressChangeSite": "string",
      "addressChangeSource": "string",
      "addressChangeEffectiveDate": "string",
      "effectiveEndDate": "2024-09-03T17:16:51.873Z",
      "insurancePhones": [
        {
          "sourceDate": "2024-09-03T17:16:51.873Z",
          "originatingSourceSystem": "string",
          "sourceSystemUser": "string",
          "phoneNumber": "string",
          "phoneType": "QFaxE"
        }
      ]
    }
  ],
  "healthCareEligibilityFactors": {
    "sourceDate": "2024-09-03T17:16:51.873Z",
    "originatingSourceSystem": "string",
    "sourceSystemUser": "string",
    "enrollmentDate": "2024-09-03T17:16:51.873Z",
    "enrollmentPriorityGroup": "string",
    "enrollmentPrioritySubGroup": "string",
    "enrollmentEffectiveDate": "2024-09-03T17:16:51.873Z",
    "enrollmentEndDate": "2024-09-03T17:16:51.873Z",
    "eligibleForClassIIDental": true,
    "classIIDentalApplicationDueBefore": "2024-09-03T17:16:51.873Z",
    "ineligibleDate": "2024-09-03T17:16:51.873Z",
    "ineligibleReason": "string",
    "ineligibleRecordCreateDate": "2024-09-03T17:16:51.873Z",
    "incomeYear": 0,
    "hardshipGrantedIndicator": true,
    "hardshipGrantedReason": "string",
    "hardshipEffectiveDate": "2024-09-03T17:16:51.873Z",
    "hardshipReviewDate": "2024-09-03T17:16:51.873Z",
    "siteGrantingHardship": "string",
    "eligibleForMedicaid": {
      "sourceDate": "2024-09-03T17:16:51.873Z",
      "originatingSourceSystem": "string",
      "sourceSystemUser": "string",
      "eligibleForMedicaid": true,
      "medicaidLastModifiedDate": "2024-09-03T17:16:51.873Z",
      "medicaidEligibilityReportDate": "2024-09-03T17:16:51.873Z"
    },
    "combatVeteranEligibilityEndDate": "2024-09-03T17:16:51.873Z",
    "clinicalDecisions": {
      "sourceDate": "2024-09-03T17:16:51.874Z",
      "originatingSourceSystem": "string",
      "sourceSystemUser": "string",
      "catastrophicDisability": {
        "sourceDate": "2024-09-03T17:16:51.874Z",
        "originatingSourceSystem": "string",
        "sourceSystemUser": "string",
        "catastrophicDisabilityIndicator": true,
        "catastrophicDisabilityDecisionDate": "2024-09-03T17:16:51.874Z",
        "catastrophicDisabilityReviewDate": "2024-09-03T17:16:51.874Z",
        "catastrophicDisabilityDeterminationFacility": "string",
        "catastrophicDisabilityDeterminedBy": "string",
        "catastrophicDisabilityDeterminationMethod": "QPhysical ExaminationE",
        "catastrophicDisabilityDescriptors": [
          {
            "sourceDate": "2024-09-03T17:16:51.874Z",
            "originatingSourceSystem": "string",
            "sourceSystemUser": "string",
            "descriptor": "string"
          }
        ],
        "effectiveEndDate": "2024-09-03T17:16:51.874Z"
      },
      "militarySexualTrauma": {
        "sourceDate": "2024-09-03T17:16:51.874Z",
        "originatingSourceSystem": "string",
        "sourceSystemUser": "string",
        "militarySexualTraumaStatus": "QScreened, Reports MSTE",
        "militarySexualTraumaStatusChangeDate": "2024-09-03T17:16:51.874Z",
        "militarySexualTraumaDeterminationFacility": "string",
        "effectiveEndDate": "2024-09-03T17:16:51.874Z"
      },
      "spinalCordInjury": {
        "sourceDate": "2024-09-03T17:16:51.874Z",
        "originatingSourceSystem": "string",
        "sourceSystemUser": "string",
        "spinalCordInjuryType": "QNOT APPLICABLEE",
        "effectiveEndDate": "2024-09-03T17:16:51.874Z"
      },
      "noseThroatRadium": {
        "sourceDate": "2024-09-03T17:16:51.874Z",
        "originatingSourceSystem": "string",
        "sourceSystemUser": "string",
        "noseThroatRadiumIndicator": true,
        "noseThroatRadiumDeterminationFacility": "string",
        "noseThroatRadiumFromAviatorServiceBefore1955": true,
        "noseThroatRadiumFromSubmarinerServiceBefore1965": true,
        "noseThroatRadiumReceivingTreatment": "QUnknownE",
        "noseThroatRadiumVerificationDate": "2024-09-03T17:16:51.874Z",
        "noseThroatRadiumVerificationFacility": "string",
        "noseThroatRadiumVerificationMethod": "QMilitary RecordE",
        "effectiveEndDate": "2024-09-03T17:16:51.874Z"
      }
    },
    "specialAuthority": {
      "sourceDate": "2024-09-03T17:16:51.874Z",
      "originatingSourceSystem": "string",
      "sourceSystemUser": "string",
      "agentOrangeIndicator": true,
      "agentOrangeEligibilityReportDate": "2024-09-03T17:16:51.874Z",
      "agentOrangeLocation": "string",
      "campLejeuneIndicator": true,
      "campLejeuneEligibilityReportDate": "2024-09-03T17:16:51.874Z",
      "environmentalContaminantsIndicator": true,
      "environmentalContaminantsEligibilityReportDate": "2024-09-03T17:16:51.874Z",
      "radiationExposureIndicator": true,
      "radiationExposureEligibilityReportDate": "2024-09-03T17:16:51.874Z",
      "shipboardHazardAndDefenseIndicator": true,
      "shipboardHazardAndDefenseEligibilityReportDate": "2024-09-03T17:16:51.874Z",
      "vhaToxicExposureRiskActivityInd": true
    }
  },
  "healthCare": {
    "sourceDate": "2024-09-03T17:16:51.874Z",
    "originatingSourceSystem": "string",
    "sourceSystemUser": "string",
    "appointmentRequestResponse": true,
    "appointmentRequestDate": "2024-09-03T17:16:51.874Z",
    "appointmentRequestChangeDate": "2024-09-03T17:16:51.874Z",
    "originalAppointmentRequestDate": "2024-09-03T17:16:51.874Z",
    "originalAppointmentRequestChangeDate": "2024-09-03T17:16:51.874Z",
    "originalAppointmentRequestResponse": true,
    "visitSummaries": [
      {
        "sourceDate": "2024-09-03T17:16:51.874Z",
        "originatingSourceSystem": "string",
        "sourceSystemUser": "string",
        "incomeYear": 0,
        "visitSummaries": [
          {
            "sourceDate": "2024-09-03T17:16:51.874Z",
            "originatingSourceSystem": "string",
            "sourceSystemUser": "string",
            "hospitalInpatientDays": 0,
            "hospitalLastVisitDate": "2024-09-03T17:16:51.874Z",
            "hospitalOutpatientDays": 0,
           "facilityVisited": "string"
          }
        ]
      }
    ],
    "preferredFacilities": [
      {
        "sourceDate": "2024-09-03T17:16:51.874Z",
        "originatingSourceSystem": "string",
        "sourceSystemUser": "string",
        "preferredFacility": "string",
        "assignmentDate": "2024-09-03T17:16:51.874Z",
        "unassignmentDate": "2024-09-03T17:16:51.874Z"
      }
    ]
  }
}
dcloud commented 2 months ago

According to Health-Benefits-Service docs on SP, the Administrative Data Repository (ADR) is the "authoritative source" for Health Benefits data. In a "big picture" graphic, ADR appears as VES/ADR, indicating a possible relationship between that two. From searching around, it sounds like ADR is a product in the VES portfolio, though at least some of the ADR docs appear to have been archived

wesrowe commented 2 months ago

Through an unplanned conversation with Travis (Profile team) we learned that associated persons has a relationship field which defaults to Unrelated Friend. We now intend to ask the user for that value and need to find out what values the API will accept.

dcloud commented 2 months ago

Through an unplanned conversation with Travis (Profile team) we learned that associated persons has a relationship field which defaults to Unrelated Friend. We now intend to ask the user for that value and need to find out what values the API will accept.

The relationship is not indicated as required or having any expectation about values for that field, according to the Swagger docs for the Health Benefit API endpoints.

Here's a screenshot of the schema for an associated person:

Screenshot of a portion of a webpage describing the Associated Person Schema

dcloud commented 2 months ago

Per a Slack thread with some VA Profile folks:

Is there a status check endpoint like other APIs?

No, there is no status endpoint for checking Health Benefit updates.

It will be a success or not a success right away, you will only be able to rely on the response status from us in the response message.

ES currently does update us with a status on if that update was received or not. That status does not tell you if it is mastered/etc.

What does success look like?

If you receive a 200, then your request was successful. In that requests response you will see a Code, Key, & text value that will provide additional information.

Note that the example says "sucessfully received", which is not exactly the same as "this is received, saved, and available". We may need to be cautious about how we present success to the veteran.

{
  "messages": [
    {
      "code": "HB204",
      "key": "_VHA_ES_UPDATE_SERVICE_INFO",
      "text": "VHA ES Update Service returned message: mdm.cuf.core.messages.Message@70365e72[code=200,key=sucessfully received,text=<null>,severity=<null>,potentiallySelfCorrectingOnRetry=<null>]",
      "severity": "INFO",
      "potentiallySelfCorrectingOnRetry": false
    }
  ]
}

Can we send only associated persons data to the Health Benefit API?

Yes, you can send only associatedPersons

How do you remove associatedPersons?

You should provide the EndDate for the associated person you want to "remove"

This is a little confusing, and raises other questions such as how this would be done as an update to an existing person. Also, what does the value need to be for a new associatedPerson?

wesrowe commented 2 months ago

Re the EndDate – I feel like I've seen this pattern before. it's a date-time (now) for the end of that associated person's relevance. It's used to preserve an auditable record.

My guess: I wouldn't think a new entry would need an EndDate.

dcloud commented 1 month ago

Posed some follow up questions that have not been answered, posting in this ticket so we can bring them up again:

I have a few follow-up questions:

  1. If we need to remove a person by setting an effectiveEndDate, is there a unique identifier we’d use to indicate which associatedPerson to remove? Or do we have to GET the associatedPersons object from the /read endpoint in order to send back a matching object with an updated effectiveEndDate? Or is there another mechanism?

  2. The swagger docs make it seem like most fields for an associatedPerson can be empty… it looks like contactType needs to be set, as does the sourceDate, originatingSourceSystem and sourceSystemUser (though swagger says those last two can be 0 length strings)? Am I reading that correctly? Are there other fields that need to be non-empty?

dcloud commented 1 month ago

Noting that breakers aren't implemented for the V3 Profile in vets-api/config/initializers/breakers.rb

carlosfelix2 commented 1 month ago

Still have questions out to VA Profile team. Need answers to complete this and may need VA Profile onboarding approval.

dcloud commented 1 month ago

Looking around for the meaning of \Q and \E I found that in Perl programming, those can be used when interpolating strings into regular expressionssimilarly for Java.

I haven't seen that in programming languages I've used, and it seems like an unusual things to include in your web API

dcloud commented 1 month ago

Given we've heard that the 1010 team submits directly to the HCA enrollment system (and can submit only one EC), I went looking for some references in vets-api and found lib/va1010_forms/utils.rb, which shows a service that makes SOAP API requests to 'http://va.gov/schema/esr/voa/v1', with retries via sidekiq.

This is the 1010ezr form fixture used in tests, though that shows both primary and other for EC/NoK. So the restriction of one of each appears to truly be related to the paper 1010ezr form

dcloud commented 1 month ago

Given our meeting with VES and the 1010 team, it sounds like we'll be looking for a different API for editing associated persons (EC, NoK). We'd either be using a VES service directly, or via a new VA Profile endpoint for associated persons.

During the meeting, we learned that the existing health-benefit endpoint of VA Profile was intended for bulk requests from Cerner systems, and is not recommended for use by teams with our use case.

wesrowe commented 1 month ago

Michael Richard deferred to Josh Faulkner on what API we should use. Closing this ticket.