|
1371 | 1371 | "title": "AssetSummaryDTO", |
1372 | 1372 | "type": "object" |
1373 | 1373 | }, |
| 1374 | + "AssignAssetPersistentIdRequest": { |
| 1375 | + "description": "Body for `POST /assets/{asset_id}/assign-persistent-identifier`.\n\n`scheme` selects the PID scheme; v1 supports DOI and HANDLE.\n`suffix` is the optional operator-supplied local part; when absent\nthe configured `DoiMinter` adapter auto-generates one. No `value`\nfield per the server-mint posture (Lock 12).", |
| 1376 | + "properties": { |
| 1377 | + "scheme": { |
| 1378 | + "$ref": "#/components/schemas/PersistentIdentifierScheme", |
| 1379 | + "description": "Closed PIDINST Property 1 scheme: DOI or HANDLE." |
| 1380 | + }, |
| 1381 | + "suffix": { |
| 1382 | + "anyOf": [ |
| 1383 | + { |
| 1384 | + "maxLength": 200, |
| 1385 | + "minLength": 1, |
| 1386 | + "type": "string" |
| 1387 | + }, |
| 1388 | + { |
| 1389 | + "type": "null" |
| 1390 | + } |
| 1391 | + ], |
| 1392 | + "description": "Optional operator-supplied local part. When absent, the configured DoiMinter adapter auto-generates the suffix; the bare-request flow is the common case for retrospective bulk-mint per F1.4.", |
| 1393 | + "title": "Suffix" |
| 1394 | + } |
| 1395 | + }, |
| 1396 | + "required": [ |
| 1397 | + "scheme" |
| 1398 | + ], |
| 1399 | + "title": "AssignAssetPersistentIdRequest", |
| 1400 | + "type": "object" |
| 1401 | + }, |
| 1402 | + "AssignAssetPersistentIdResponse": { |
| 1403 | + "description": "Response body for `POST /assets/{asset_id}/assign-persistent-identifier`.\n\nEchoes the server-minted `(scheme, value)` pair so the operator\nlearns the assigned identifier without a follow-up GET. Per Lock\n17, this is the only Asset POST that returns a structured body;\nthe deviation is justified because the value is server-minted and\nnot derivable from the request alone.", |
| 1404 | + "properties": { |
| 1405 | + "scheme": { |
| 1406 | + "description": "Assigned PIDINST Property 1 scheme value (DOI or Handle).", |
| 1407 | + "title": "Scheme", |
| 1408 | + "type": "string" |
| 1409 | + }, |
| 1410 | + "value": { |
| 1411 | + "description": "Authority-assigned persistent identifier string.", |
| 1412 | + "title": "Value", |
| 1413 | + "type": "string" |
| 1414 | + } |
| 1415 | + }, |
| 1416 | + "required": [ |
| 1417 | + "scheme", |
| 1418 | + "value" |
| 1419 | + ], |
| 1420 | + "title": "AssignAssetPersistentIdResponse", |
| 1421 | + "type": "object" |
| 1422 | + }, |
1374 | 1423 | "AttachAssetToFixtureRequest": { |
1375 | 1424 | "description": "Body for `POST /assets/{asset_id}/attach-to-fixture`.", |
1376 | 1425 | "properties": { |
|
7108 | 7157 | "title": "PermitSummaryDTO", |
7109 | 7158 | "type": "object" |
7110 | 7159 | }, |
| 7160 | + "PersistentIdentifierScheme": { |
| 7161 | + "description": "Closed PIDINST v1.0 Property 1 identifier-type vocabulary (subset).\n\nValues match `PidinstIdentifierType.DOI.value` and\n`PidinstIdentifierType.HANDLE.value` byte-for-byte so the\nserializer swap (URN to DOI / Handle) does not need a translation\nmap. URN and URL members of `PidinstIdentifierType` are\nintentionally NOT mirrored here: `Asset.persistent_id` is an\nassigned-by-operator persistent identifier, not a runtime fallback\nor a content URL.\n\nAdding a fourth member (for example ARK or PURL) is an additive\nenum change at a future migration boundary, gated on operator\ndemand. The closed-enum stance mirrors `AlternateIdentifierKind`\nand `ManufacturerIdentifierType`.", |
| 7162 | + "enum": [ |
| 7163 | + "DOI", |
| 7164 | + "Handle" |
| 7165 | + ], |
| 7166 | + "title": "PersistentIdentifierScheme", |
| 7167 | + "type": "string" |
| 7168 | + }, |
7111 | 7169 | "PidinstAlternateIdentifierDTO": { |
7112 | 7170 | "description": "PIDINST v1.0 Property 13: an alternate identifier under a known scheme.", |
7113 | 7171 | "properties": { |
@@ -16024,6 +16082,123 @@ |
16024 | 16082 | ] |
16025 | 16083 | } |
16026 | 16084 | }, |
| 16085 | + "/assets/{asset_id}/assign-persistent-identifier": { |
| 16086 | + "post": { |
| 16087 | + "operationId": "post_assets_assign_persistent_identifier_assets__asset_id__assign_persistent_identifier_post", |
| 16088 | + "parameters": [ |
| 16089 | + { |
| 16090 | + "description": "Target asset's id.", |
| 16091 | + "in": "path", |
| 16092 | + "name": "asset_id", |
| 16093 | + "required": true, |
| 16094 | + "schema": { |
| 16095 | + "description": "Target asset's id.", |
| 16096 | + "format": "uuid", |
| 16097 | + "title": "Asset Id", |
| 16098 | + "type": "string" |
| 16099 | + } |
| 16100 | + }, |
| 16101 | + { |
| 16102 | + "description": "Legacy principal-id header (trust-the-proxy shape). When IDENTITY_PROVIDERS is configured (bearer-auth mode), this header is IGNORED and the verified bearer token from `BearerAuthMiddleware` (Authorization: Bearer) sets the principal. When no IdPs are configured (legacy mode), the application TRUSTS this header (no cryptographic verification) -- production deployments in legacy mode MUST front the API with an auth proxy that strips any client-supplied X-Principal-Id and sets it to the verified principal UUID. Behavior when absent: see Settings.require_authenticated_principal.", |
| 16103 | + "in": "header", |
| 16104 | + "name": "X-Principal-Id", |
| 16105 | + "required": false, |
| 16106 | + "schema": { |
| 16107 | + "anyOf": [ |
| 16108 | + { |
| 16109 | + "format": "uuid", |
| 16110 | + "type": "string" |
| 16111 | + }, |
| 16112 | + { |
| 16113 | + "type": "null" |
| 16114 | + } |
| 16115 | + ], |
| 16116 | + "description": "Legacy principal-id header (trust-the-proxy shape). When IDENTITY_PROVIDERS is configured (bearer-auth mode), this header is IGNORED and the verified bearer token from `BearerAuthMiddleware` (Authorization: Bearer) sets the principal. When no IdPs are configured (legacy mode), the application TRUSTS this header (no cryptographic verification) -- production deployments in legacy mode MUST front the API with an auth proxy that strips any client-supplied X-Principal-Id and sets it to the verified principal UUID. Behavior when absent: see Settings.require_authenticated_principal.", |
| 16117 | + "title": "X-Principal-Id" |
| 16118 | + } |
| 16119 | + } |
| 16120 | + ], |
| 16121 | + "requestBody": { |
| 16122 | + "content": { |
| 16123 | + "application/json": { |
| 16124 | + "schema": { |
| 16125 | + "$ref": "#/components/schemas/AssignAssetPersistentIdRequest" |
| 16126 | + } |
| 16127 | + } |
| 16128 | + }, |
| 16129 | + "required": true |
| 16130 | + }, |
| 16131 | + "responses": { |
| 16132 | + "201": { |
| 16133 | + "content": { |
| 16134 | + "application/json": { |
| 16135 | + "schema": { |
| 16136 | + "$ref": "#/components/schemas/AssignAssetPersistentIdResponse" |
| 16137 | + } |
| 16138 | + } |
| 16139 | + }, |
| 16140 | + "description": "Successful Response" |
| 16141 | + }, |
| 16142 | + "400": { |
| 16143 | + "content": { |
| 16144 | + "application/json": { |
| 16145 | + "schema": { |
| 16146 | + "$ref": "#/components/schemas/ErrorResponse" |
| 16147 | + } |
| 16148 | + } |
| 16149 | + }, |
| 16150 | + "description": "PersistentIdentifier VO validation failed: empty or whitespace-only value, or value over the max-length bound (InvalidPersistentIdentifierValueError)." |
| 16151 | + }, |
| 16152 | + "403": { |
| 16153 | + "content": { |
| 16154 | + "application/json": { |
| 16155 | + "schema": { |
| 16156 | + "$ref": "#/components/schemas/ErrorResponse" |
| 16157 | + } |
| 16158 | + } |
| 16159 | + }, |
| 16160 | + "description": "Authorize policy denied the command." |
| 16161 | + }, |
| 16162 | + "404": { |
| 16163 | + "content": { |
| 16164 | + "application/json": { |
| 16165 | + "schema": { |
| 16166 | + "$ref": "#/components/schemas/ErrorResponse" |
| 16167 | + } |
| 16168 | + } |
| 16169 | + }, |
| 16170 | + "description": "No asset exists with the given id." |
| 16171 | + }, |
| 16172 | + "409": { |
| 16173 | + "content": { |
| 16174 | + "application/json": { |
| 16175 | + "schema": { |
| 16176 | + "$ref": "#/components/schemas/ErrorResponse" |
| 16177 | + } |
| 16178 | + } |
| 16179 | + }, |
| 16180 | + "description": "Asset cannot accept the persistent identifier under current conditions: the asset is Decommissioned (AssetPersistentIdAssignmentForbiddenError), OR the asset already carries a persistent_id (set-once: AssetPersistentIdAlreadyAssignedError), OR a concurrent write to the same asset stream conflicted (optimistic concurrency)." |
| 16181 | + }, |
| 16182 | + "422": { |
| 16183 | + "description": "Path parameter or request body failed schema validation (missing field, malformed UUID, scheme outside the closed enum, suffix length out of bounds at the wire layer)." |
| 16184 | + }, |
| 16185 | + "502": { |
| 16186 | + "content": { |
| 16187 | + "application/json": { |
| 16188 | + "schema": { |
| 16189 | + "$ref": "#/components/schemas/ErrorResponse" |
| 16190 | + } |
| 16191 | + } |
| 16192 | + }, |
| 16193 | + "description": "The external mint authority (DataCite or Handle.net) failed to assign a persistent identifier (PersistentIdentifierMintError)." |
| 16194 | + } |
| 16195 | + }, |
| 16196 | + "summary": "Assign a PIDINST persistent identifier to an existing Asset", |
| 16197 | + "tags": [ |
| 16198 | + "equipment" |
| 16199 | + ] |
| 16200 | + } |
| 16201 | + }, |
16027 | 16202 | "/assets/{asset_id}/attach-to-fixture": { |
16028 | 16203 | "post": { |
16029 | 16204 | "operationId": "post_assets_attach_to_fixture_assets__asset_id__attach_to_fixture_post", |
|
0 commit comments