-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cleanup JSON schemas and add ADR (#174)
* Cleanup JSON schemas and add ADR `lpa.json` is now the full LPA structure. `submitted-lpa.json` is the subset of fields that should initially be initially submitted from MRLPA or scanning. Create `translation.*.json` to indicated what translation files might look like/contain. Add an ADR documenting how we will use, host and version our JSON schemas. #minor * PR feedback - Use date-time in schema to reflect existing code - Use "donorTerms" rather than "terms" #patch * Rename "submitted-lpa" to "donor-details" Aligns better with MRLPA and Sirius language, and is a bit clearer about it contents. #patch * Only require email for online CPs #patch * Key the terms translation strings For easier management between languages #patch * Expand on consequences #patch * Update refrence in OpenAPI override file "InitialLpa" -> "DonorDetails" #patch * Fix name of $id to match file #patch
- Loading branch information
Showing
7 changed files
with
376 additions
and
253 deletions.
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
docs/architecture/decisions/0004-use-json-schemas-to-define-lpa-structure.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# 4. Use JSON schemas to define LPA structure | ||
|
||
Date: 2024-04-22 | ||
|
||
## Status | ||
|
||
Accepted | ||
|
||
## Context | ||
|
||
When a donor signs their LPA online, or the OPG receives it on paper, it is stored in the LPA Store as a golden copy of the record. As well as storing the data that the donor submitted, we also need to store the context in which is was executed: the agreed-upon conditions and the meaning of their choices. | ||
|
||
This context needs to live with the LPA for its entire lifetime, which is likely to be decades, even if the context of new LPAs changes in the future (for example, if OPG updates the wording of the confirmation statement). | ||
|
||
## Decision | ||
|
||
To ensure we capture and preserve the context of LPAs, each LPA will be associated with a JSON schema at point of execution (online) or ingestion (paper). That schema will document the shape of the LPA's data. | ||
|
||
The schema file will be mapped to translation files that contain any important text associated with the LPA, such as the terms the donor agreed to. There will be a file for each language a donor can use (currently English or Welsh). | ||
|
||
The schema file, and translation files, will live in the opg-data-lpa-store repository. | ||
|
||
The schemas will be hosted on [the OPG's data dictionary](https://data-dictionary.opg.service.justice.gov.uk/) website to ensure they have a fully resolvable URI under our control. | ||
|
||
As the schema changes, it will be versioned by year and month (YYYY-MM). If multiple releases are made within the same month, an increasing integer will be appended to the end (YYYY-MM-N) to differentiate further. | ||
|
||
The JSON schema associated with the LPA will be stored inside the LPA (JSON) document itself, in a `$schema` field. It will point to the resolvable URI of the JSON schema noted above. | ||
|
||
## Consequences | ||
|
||
As validation is currently done manually, there is a risk that the structure of the LPA will not match the JSON schema. We should introduce schema validation when storing an LPA to ensure this is not the case. | ||
|
||
We need to ensure that any changes to the structure of the data are properly updated in the schema, managed through pull requests to this repository that need cross-team ratification. Non essential changes will likely be delayed and grouped to minimise the number of active schemas. An exception to this is before the start of private beta, since we will only be working with test data and can more easily change the schema. | ||
|
||
Services that display an LPA may need to pull content from the translation files to ensure they are presenting accurate information. | ||
|
||
The JSON schemas will need to be kept (and preferably be resolvable at their URI) for as long as we have any LPAs using them. This could be mitigated in the future by migrating older LPAs to a future structure. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
openapi: "3.0.3" | ||
components: | ||
schemas: | ||
InitialLpa: | ||
DonorDetails: | ||
$ref: "#/components/schemas/Empty" | ||
Lpa: | ||
$ref: "#/components/schemas/Empty" | ||
Empty: | ||
type: object |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
{ | ||
"$schema": "https://json-schema.org/draft/2020-12/schema", | ||
"$id": "https://data-dictionary.opg.service.justice.gov.uk/schema/lpa/2024-04/donor-details.json", | ||
"description": "The data that should be provided when an LPA is executed", | ||
"type": "object", | ||
"required": [ | ||
"lpaType", | ||
"donor", | ||
"attorneys", | ||
"certificateProvider", | ||
"signedAt" | ||
], | ||
"properties": { | ||
"lpaType": { | ||
"type": "string", | ||
"enum": ["property-and-affairs", "personal-welfare"] | ||
}, | ||
"donor": { | ||
"allOf": [ | ||
{ | ||
"$ref": "#/$defs/Person" | ||
} | ||
], | ||
"type": "object", | ||
"required": ["dateOfBirth", "email"], | ||
"properties": { | ||
"dateOfBirth": { | ||
"type": "string", | ||
"format": "date" | ||
}, | ||
"email": { | ||
"type": "string", | ||
"x-faker": "internet.email" | ||
}, | ||
"otherNamesKnownBy": { | ||
"type": "string", | ||
"x-faker": "name.findName" | ||
}, | ||
"contactLanguagePreference": { | ||
"type": "string", | ||
"enum": ["en", "cy"] | ||
} | ||
} | ||
}, | ||
"attorneys": { | ||
"type": "array", | ||
"items": { | ||
"$ref": "#/$defs/Attorney" | ||
}, | ||
"minLength": 1 | ||
}, | ||
"trustCorporations": { | ||
"type": "array", | ||
"items": { | ||
"$ref": "#/$defs/TrustCorporation" | ||
} | ||
}, | ||
"certificateProvider": { | ||
"allOf": [ | ||
{ | ||
"$ref": "#/$defs/Person" | ||
} | ||
], | ||
"type": "object", | ||
"required": ["phone", "channel"], | ||
"if": { | ||
"required": ["channel"], | ||
"properties": { | ||
"channel": { "const": "online" } | ||
} | ||
}, | ||
"then": { | ||
"required": ["email"] | ||
}, | ||
"properties": { | ||
"email": { | ||
"type": "string", | ||
"x-faker": "internet.email" | ||
}, | ||
"phone": { | ||
"type": "string", | ||
"x-faker": "phone.number" | ||
}, | ||
"channel": { | ||
"type": "string", | ||
"enum": ["paper", "online"] | ||
} | ||
} | ||
}, | ||
"peopleToNotify": { | ||
"type": "array", | ||
"items": { | ||
"$ref": "#/$defs/PersonToNotify" | ||
} | ||
}, | ||
"howAttorneysMakeDecisions": { | ||
"type": "string", | ||
"enum": [ | ||
"jointly", | ||
"jointly-and-severally", | ||
"jointly-for-some-severally-for-others" | ||
] | ||
}, | ||
"howAttorneysMakeDecisionsDetails": { | ||
"type": "string" | ||
}, | ||
"howReplacementAttorneysMakeDecisions": { | ||
"type": "string", | ||
"enum": [ | ||
"jointly", | ||
"jointly-and-severally", | ||
"jointly-for-some-severally-for-others" | ||
] | ||
}, | ||
"howReplacementAttorneysMakeDecisionsDetails": { | ||
"type": "string" | ||
}, | ||
"howReplacementAttorneysStepIn": { | ||
"type": "string", | ||
"enum": ["all-can-no-longer-act", "one-can-no-longer-act", "another-way"] | ||
}, | ||
"howReplacementAttorneysStepInDetails": { | ||
"type": "string" | ||
}, | ||
"whenTheLpaCanBeUsed": { | ||
"type": "string", | ||
"enum": ["when-capacity-lost", "when-has-capacity"] | ||
}, | ||
"lifeSustainingTreatmentOption": { | ||
"type": "string", | ||
"enum": ["option-a", "option-b"] | ||
}, | ||
"restrictionsAndConditions": { | ||
"type": "string" | ||
}, | ||
"signedAt": { | ||
"type": "string", | ||
"format": "date-time" | ||
} | ||
}, | ||
"additionalProperties": false, | ||
"$defs": { | ||
"Address": { | ||
"type": "object", | ||
"required": ["line1", "town", "country"], | ||
"properties": { | ||
"line1": { | ||
"type": "string", | ||
"x-faker": "address.streetAddress" | ||
}, | ||
"line2": { | ||
"type": "string", | ||
"x-faker": "address.streetName" | ||
}, | ||
"line3": { | ||
"type": "string", | ||
"x-faker": "address.cityName" | ||
}, | ||
"town": { | ||
"type": "string", | ||
"x-faker": "address.cityName" | ||
}, | ||
"postcode": { | ||
"type": "string", | ||
"x-faker": { | ||
"helpers.replaceSymbols": "??# #??" | ||
} | ||
}, | ||
"country": { | ||
"type": "string", | ||
"format": "ISO-3166-1", | ||
"minLength": 2, | ||
"maxLength": 2, | ||
"x-faker": "address.countryCode" | ||
} | ||
}, | ||
"additionalProperties": false, | ||
"example": { | ||
"line1": "Flat 3", | ||
"line2": "42 Primrose Lane", | ||
"line3": "Greenfields", | ||
"town": "Manchester", | ||
"postcode": "M17 2XY", | ||
"country": "GB" | ||
} | ||
}, | ||
"Person": { | ||
"type": "object", | ||
"required": ["uid", "firstNames", "lastName", "address"], | ||
"properties": { | ||
"uid": { | ||
"type": "string", | ||
"format": "uuid" | ||
}, | ||
"firstNames": { | ||
"type": "string", | ||
"x-faker": "name.firstName" | ||
}, | ||
"lastName": { | ||
"type": "string", | ||
"x-faker": "name.lastName" | ||
}, | ||
"address": { | ||
"$ref": "#/$defs/Address" | ||
} | ||
} | ||
}, | ||
"Attorney": { | ||
"allOf": [ | ||
{ | ||
"$ref": "#/$defs/Person" | ||
} | ||
], | ||
"type": "object", | ||
"required": ["dateOfBirth", "email", "status"], | ||
"properties": { | ||
"dateOfBirth": { | ||
"type": "string", | ||
"format": "date" | ||
}, | ||
"email": { | ||
"type": "string", | ||
"x-faker": "internet.email" | ||
}, | ||
"status": { | ||
"type": "string", | ||
"enum": ["active", "replacement", "removed"] | ||
} | ||
} | ||
}, | ||
"TrustCorporation": { | ||
"type": "object", | ||
"required": ["name", "companyNumber", "email", "address", "status"], | ||
"properties": { | ||
"name": { | ||
"type": "string" | ||
}, | ||
"companyNumber": { | ||
"type": "string" | ||
}, | ||
"email": { | ||
"type": "string", | ||
"x-faker": "internet.email" | ||
}, | ||
"address": { | ||
"$ref": "#/$defs/Address" | ||
}, | ||
"status": { | ||
"type": "string", | ||
"enum": ["active", "replacement", "removed"] | ||
} | ||
} | ||
}, | ||
"PersonToNotify": { | ||
"allOf": [ | ||
{ | ||
"$ref": "#/$defs/Person" | ||
} | ||
], | ||
"type": "object" | ||
} | ||
} | ||
} |
Oops, something went wrong.