mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 22:26:13 +00:00
fix(medications): accept an Idempotency-Key on the three replayed creates
The native client replays its offline outbox with the same Idempotency-Key on every attempt, and `POST /api/medications`, the side-effect log and the inventory register ran the handler again on the replay: after a lost success response the account was left with a duplicate medication, a duplicate symptom entry or a second pen in the supply count. The dedupe on `(externalSource, externalId)` only ever covered a MIRRORED create; a manually entered medication carries neither field and had nothing to collapse a retry onto. All three wrap in `withIdempotency`, the composition the batch ingest already ships, and the three operations publish the header so a client generated against the contract can tell that a retry is safe. Zod parsing and `requireRecordAuth` are untouched. An integration test drives each route twice against real Postgres and asserts what a status check cannot: one row in the table, and a replayed 201 carrying `X-Idempotent-Replay: true`.
This commit is contained in:
1 parent
1d372df3a0
commit
6fe1897941
6 files changed
+464
-187
No files matched your search
@@ -575,6 +575,7 @@ export const medicationPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
},
|
||||
},
|
||||
post: {
|
||||
parameters: [idempotencyKeyParameter],
|
||||
tags: ["Medications"],
|
||||
summary: "Log a side effect",
|
||||
description:
|
||||
@@ -585,6 +586,7 @@ export const medicationPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
content: { "application/json": { schema: createSideEffectRequest } },
|
||||
},
|
||||
responses: {
|
||||
...idempotentWrite(),
|
||||
...recordRefusal(),
|
||||
"201": {
|
||||
description: "The created entry, with its note decrypted.",
|
||||
@@ -912,6 +914,7 @@ export const medicationPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
},
|
||||
},
|
||||
post: {
|
||||
parameters: [idempotencyKeyParameter],
|
||||
tags: ["Medications"],
|
||||
summary: "Create a medication with at least one schedule",
|
||||
description:
|
||||
@@ -921,6 +924,7 @@ export const medicationPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
content: { "application/json": { schema: createMedicationSchema } },
|
||||
},
|
||||
responses: {
|
||||
...idempotentWrite(),
|
||||
...recordRefusal(),
|
||||
"201": {
|
||||
description: "Created medication with its schedules.",
|
||||
@@ -1220,6 +1224,7 @@ export const medicationPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
},
|
||||
},
|
||||
post: {
|
||||
parameters: [idempotencyKeyParameter],
|
||||
tags: ["Medications"],
|
||||
summary: "Register a new supply container",
|
||||
description:
|
||||
@@ -1234,6 +1239,7 @@ export const medicationPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
...idempotentWrite(),
|
||||
...recordRefusal(),
|
||||
"201": {
|
||||
description: "Created inventory item.",
|
||||
|
||||
Reference in new issue
Block a user