Lets the EnWella EHR mount <docuseal-builder> (and -form) without a
paid Pro license. Upstream's `EmbedScriptsController` returns an
"Upgrade to Pro" stub; we override it via the static-asset path so the
real shim wins without touching the controller.
JS shim (public/js/builder.js)
- Web component that decodes the JWT minted by the embedder (`name`,
`document_urls`, `external_id`, optional `template_id`).
- Iframes /templates/:id/edit for existing templates, /new?... for the
upload-from-URL flow.
- Relays a `save` postMessage from the inner builder up as a DOM
`CustomEvent('save')` on the outer element so @docuseal/react's
onSave callback fires.
- Discovers host from its own <script src> so embedders don't have to
set data-host. JWT signature not re-verified (session cookies +
shared HMAC at the calling app are authoritative).
Builder (app/javascript/template_builder/builder.vue)
- isEmbedded computed (window.parent !== window).
- Hide #title_container in embed (sheet already shows the consent name).
- Fire the `save` postMessage at the end of the manual SAVE handler so
the outer shim can dispatch the DOM event.
Rails glue
- application_controller.rb / config/application.rb: when
EMBED_ALLOWED_ORIGIN is set, add `frame-ancestors 'self' <origin>`
to the per-request CSP and drop the default `X-Frame-Options:
SAMEORIGIN` header (different scheme/host/port = different origin,
so SAMEORIGIN blocks the EHR's iframe even in same-domain prod).
- templates_uploads_controller.rb: persist `external_id` from the
upload params so the host app can later look the template up via
`GET /api/templates?external_id=...` (deterministic fallback link
path when the `template.created` webhook doesn't reach us).
- templates_uploads_controller.rb: skip the SSRF guard when fetching
documents in development — it rejects http / non-443 / localhost,
which is exactly the Active Storage URLs the EHR sends from
https://localhost:3000.
- templates_uploads/show.html.erb: carry `external_id` through the
resubmit form (used on the encrypted-PDF prompt path).
Local HTTPS dev (puma.rb, Procfile.dev, .env.example)
- Bind ssl://0.0.0.0:PORT when LOCAL_HTTPS_CERT/KEY are set (wired by
../bin/docuseal-dev to ../.certs/lvh.me.pem). EHR runs HTTPS too,
so HTTPS iframe avoids mixed-content blocking.
- Procfile.dev runs `puma -C config/puma.rb` directly so the ssl bind
applies.
- SSL_CERT_FILE example for trusting the mkcert root so DocuSeal's
outbound HTTPS to Rails (Active Storage downloads) verifies.