Delete Staged Attachment

Best-effort cleanup of a staged file. 401 when unauthenticated, 400 on malformed inputs, 204 otherwise (including when the storage delete itself fails - that's the genuine best-effort case).

Storage RLS gates the actual delete, and for a STAGED key exactly one actor gets through: the care-team WORKER who uploaded it. Workers can delete own documents (20260523002437) is the bucket's only DELETE policy with no documents-row predicate - it keys on owner = auth.uid(), and upload_to_staged_storage puts through the caller's client (src/upload.py), so the stager owns the object.

Everyone else is denied, because a staged object has no documents row by construction - the same premise list_orphaned_staged_objects relies on to sweep it. The clinician and family DELETE policies both require EXISTS (SELECT 1 FROM documents d WHERE d.file_url = 'documents/' || name). That includes the PARENT: the path-scoped policy that once let them through was dropped in 20260114100000 and replaced by the row-scoped Family members can delete own documents.

So a clinician or parent unstaging their own upload gets a 204 that deleted nothing, on the Supabase backend; R2 has no RLS and does delete. Closing it means mirroring the worker policy for the other two stagers - the same shape with its access predicate swapped, not unexplored ground - which still widens DELETE on a PHI bucket and wants its own review. Filed as #7943 with the policy in it; until it lands the 24h worker sweep (#5092) is the backstop.

Inputs are validated to stop staged_id=../source-style traversal at the route layer - RLS would still bound the blast radius, but explicit format checks keep the intent legible.

delete/attachments/staged

Request

  • Base URL
    https://api.projectindi.com (the document declares no server; this is the origin it was published from)
  • Auth
    none declared

Query parameters

staged_idstring required
filenamestring required
child_idstring required

Response

Successful Response

unknown required

Changes

No recorded changes to this operation across all 2 revisions of this API.