fix(read-only-view): serve completed contract PDF via provider (fixes fleet-wide /pdf 500) - #60
Conversation
getCompletedReadOnlyViewPDF read the sealed PDF from storage by a key
derived from CompletedPDFURL, but the Documenso adapter records a URL
there (completedDocumentUrl) and completedPDFStorageKey() returns "" for
URLs, so every completed document returned
errors.New("signed PDF not available for this document") -> not in
isPublicUserError -> HTTP 500. This broke the read-only contract PDF
view fleet-wide since the feature shipped.
Fall back to downloading the sealed PDF from the signing provider (the
same path /public/sign/{token}/download already uses) when there is no
storage key, and map the not-available error to a 4xx instead of a 500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Follow-up pushed at
Validated locally with |
|
Ownership update: this PR head now comes from |
|
Status note (2026-07-19): this fix has been running in production since 2026-07-17 via the org-fork pin ( |
Impact (prod, ongoing)
Every completed contract's read-only PDF view returns HTTP 500. In the CRM this is the "Unable to load this PDF" screen, so schools/staff cannot view any signed contract. It fires many times per hour across all schools and has been broken since the read-only view shipped (~#888–#900). Signing itself works; only viewing the completed PDF fails.
Root cause
GET /public/view/{token}/pdf→ReadOnlyViewService.getCompletedReadOnlyViewPDFreads the sealed PDF from storage by a key derived fromdoc.CompletedPDFURL:But the Documenso adapter records a URL there (
result.CompletedPDFURL = &envResp.CompletedDocumentURL), andcompletedPDFStorageKey()deliberately returns""for anyhttp(s)://value — it expects a storage key. No step persists the sealed PDF to storage, so the key is always empty for provider-completed docs. That error string isn't inisPublicUserError, so it falls through to the default 500.Confirmed in prod logs (
tether-digital-signature-prod):The sibling
GET /public/sign/{token}/downloadworks precisely because it already falls back to downloading the sealed PDF from the provider when there is no storage key.Fix
getCompletedReadOnlyViewPDFnow mirrors that working/downloadpath: when there is no storage key it downloads the sealed PDF from the signing provider (via an injected provider + attempt repo — wired through a newSetCompletedPDFProvider). Also maps"signed PDF not available for this document"to a clean 4xx instead of a 500.Longer term the sealed PDF should be persisted to GCS on completion, so this serves from storage without a per-view provider round-trip (noted in a code comment).
Verification
go build ./core/...✓go test ./core/internal/core/service/document/... ./core/internal/adapters/primary/http/controller/...✓tools-doc-assembly) builds against this change ✓@rendis — please merge + cut a release
This is prod-down for contract viewing across every school, so it needs a merge + release so
tools-doc-assemblycan bump the pin and deploy.Process flag:
doc-assemblylives under a personal account (github.com/rendis/…), so everyone else has read-only and literally cannot land a fix here — this prod-critical bug is currently single-owner-gated on you. Strongly recommend moving the repo to theTetherEducationorg so urgent fixes and rollbacks aren't blocked on one person.🤖 Generated with Claude Code