External Documents Viewer | Canvas Medical

kevincareycanvas/external-documents-viewer

External Documents Viewer

What it does

Adds a patient-scoped External Documents application to the right chart pane. For the open patient it fetches a per-patient document index from Amazon S3 and renders a searchable, sortable list of historical documents grouped by category. Clicking a row opens that document through a short-lived presigned S3 URL, so the underlying bucket never has to be public.

It's built for surfacing historical records that live outside Canvas — for example, documents migrated from a legacy EMR — without importing them into the chart.

Reference plugin

This is a reference implementation. It ships with no customer or patient data; every example value is synthetic. Adapt the S3 layout, secrets, and data-prep scripts to your own environment before deploying.

How it works

  1. ExternalDocumentsViewerApp (applications/external_documents_app.py) — an Application handler. On open it resolves the patient, downloads that patient's index JSON from S3, generates presigned URLs for each document, and renders templates/document_viewer.html into a LaunchModalEffect targeting the right chart pane.
  2. ExternalDocumentsAPI (applications/external_documents_api.py) — a staff-session-authenticated SimpleAPI exposing GET /document-url/<s3_key>, which returns a fresh presigned URL for a given document key. Used to refresh links that may have expired while the pane is open.

Expected S3 layout

s3://<S3_BUCKET>/<S3_PREFIX>/patient-indices/<canvas_patient_uuid>.json
s3://<S3_BUCKET>/<S3_PREFIX>/<document s3_key from the index>

Each per-patient index JSON has the shape:

{
  "documents": [
    {
      "title": "Sample Lab Result",
      "category": "Lab",
      "date": "2025-02-10",
      "s3_key": "PATIENT_DIR_12345/sample_lab_result.pdf"
    }
  ]
}

How to install

canvas install external-documents-viewer

After install, configure the secrets below at <instance>/admin/plugin_io/plugin/<plugin_id>/change/.

Configuration (secrets)

Secret Description
S3_KEY AWS Access Key ID
S3_SECRET AWS Secret Access Key
S3_REGION AWS region (e.g., us-west-2)
S3_BUCKET S3 bucket name
S3_PREFIX Optional key prefix within the bucket

Use an IAM principal scoped to read-only access on the document bucket/prefix.

Preparing document data

Two reference scripts under resources/scripts/ help you build and upload the per-patient index files. Adapt them to your own document export.

  1. Generate indexes from a flat CSV (one row per document):
uv run python resources/scripts/generate_patient_indices.py \
       --csv document_index.csv \
       --out-dir patient-indices
  1. Upload the generated indexes (and your document files) to S3:
uv run python resources/scripts/upload_indices_to_s3.py \
       --bucket <your-bucket> \
       --prefix <your-prefix> \
       --region us-west-2 \
       --indices-dir patient-indices

Security & privacy

Testing

uv run pytest

License

MIT — see LICENSE.