Sharing a single document from the vault minted a full-record share: the
create form always defaulted `resourceTypes` to ["Patient","Observation"]
and never signalled a documents-only intent, so the served /c/<token> view
aggregated the whole doctor report — every vital, lab, medication and
wellness figure — alongside the attached file. An empty section blob was
indistinguishable from "defaults", so the report always resolved to the
full record.
Introduce an explicit documents-only share:
- add a `documentOnly` flag to the create payload; when set the server
forces an empty report scope (all-off sections, no FHIR resource types,
FHIR API off) and requires at least one document, so a document link can
never widen into a record — whatever the body sends.
- gate the clinician-view aggregation on an enabled section: a share with
no section on never calls the report aggregator, so no health metric
leaves the database. The recipient sees only the attached document(s).
- the document detail Share action opens the create form in documents-only
mode: hide the FHIR toggle, the FHIR resource-type checkboxes and the
history-range selector, keep the picker/label/expiry/passphrase, and
always carry the launched document into the created link.
- Settings sharing keeps the full record-share form unchanged.
Extract the create-payload builder as a pure function and cover the scope
contract, the empty-scope data load, and the served-view metric-free
guarantee with tests; refresh the share e2e and regenerate the OpenAPI
contract.
Unit: the shared ShareLinkCreateForm mounts bare (Settings default) and
seeded (document flow) — a pre-attached document rides in as a chip with
the label pre-filled. e2e: the document detail Share action opens the
create flow with that document pre-attached and reaches the one-time QR
reveal; marked slow (two stacked sheets + a real create).
Both are legitimately long end-to-end flows — the share test spans two
browser contexts (owner create + picker, recipient unlock, multiple
document serves, revoke), and the med wizard gates its Next button on
per-step validation. On a loaded CI runner the default 30s timeout races
the settle; test.slow() triples it so transient runner contention stops
flaking green flows.
Adds a Playwright spec that drives the public sharing surface against the
production server and a real Postgres: the owner picks documents into a new
link through the Settings picker, a recipient unlocks it with the passphrase
and pulls each blob through the token-scoped serve route, and a revoke closes
it. Pins the load-bearing guarantees end to end — frozen-set confinement (an
owned but un-attached document 404s), the serving posture (Class A inline with
true type + nosniff + no-store, Class B opaque octet-stream attachment), the
EXIF/GPS strip on the shared image, revocation enforced at serve time, and the
scannable QR promotion at the mobile width.
Seeds a fixed share trio (inline PDF, Exif-bearing JPEG, download-only text)
through the same Postgres transport the vault fixture already uses.