Skip to content

feat: storage for partner-lab imports on both backends (2.1.0) - #11

Merged
BackStacked merged 1 commit into
mainfrom
claude/project-thread-86xth5
Nov 9, 2026
Merged

BackStacked merged 1 commit into
mainfrom
claude/project-thread-86xth5

Conversation

@BackStacked

Copy link
Copy Markdown
Contributor

Requested by Himanshu · project thread

What and why

The api is getting partner-lab PDF imports (@mgpl-diagnostics/report-reader). This PR adds their storage, on PostgreSQL and MongoDB, behind the same repository interface:

repository table / collection notes
externalReports external_reports one row per uploaded PDF. sourceSha256 is unique per org. extracted holds the ExtractedReport unchanged, plus status and warnings
externalReportFiles external_report_files the PDF bytes (id = the external report's id)
externalSignatories external_signatories the partner signature registry. listForOrg(orgId, lab?) is cached per org (Redis cache layer) and cleared on create, update and delete
externalSignatures external_signatures one PNG per (org, sourceSha256, sha), unique
reportProvenance report_provenance one per report (unique reportId): performed by, medical signatories, NABL text, the partner's test name, and the results as imported

Differences from the brief:

  • The PDF bytes sit in their own table. If they were a column on external_reports, every list query would load the PDFs.
  • Provenance is its own table, not a JSON column on reports. sync() creates new tables but never alters existing ones, so nothing needs a migration script. The new tables are created by repos.sync() / npm run db:sync.

Bytes go in as Uint8Array and come out as Buffer on both drivers. Sequelize had been stringifying a bare Uint8Array, and Mongo's lean reads had been returning BSON Binary.

Details are in docs/EXTERNAL-REPORTS.md. AGENTS.md has a new rule 11 (this data is private).

Type

  • Feature

Checklist

  • npm run typecheck passes
  • Tests: 13 new contract checks per backend and 1 cache check. Locally only PostgreSQL ran (TEST_BACKENDS=pg npm test: 99 passed, 0 failed). This session can't download MongoDB binaries (403), so CI's MongoDB run is the first real check of the Mongo side. TEST_BACKENDS is new and defaults to both.
  • Docs updated (README, AGENTS.md, docs/EXTERNAL-REPORTS.md, llms-full.txt)
  • No real patient data, contact details or signatures (fictional values only)

Release: after merge, tag v2.1.0 on the merge commit so the api can depend on ^2.1.0.


Generated by Claude Code

Five new repositories, on PostgreSQL and MongoDB, for the api's report-reader imports:

- externalReports (external_reports): one row per partner PDF, sourceSha256 unique per
  organisation, the ExtractedReport JSON as is, status, warnings
- externalReportFiles (external_report_files): the PDF bytes, apart so lists never load them
- externalSignatories (external_signatories): the partner signature registry; listForOrg is
  cached per organisation through the cache layer and cleared on every write
- externalSignatures (external_signatures): the PNG per (organisation, PDF, signature)
- reportProvenance (report_provenance): one per report, where its results came from

Bytes go in as Uint8Array and come out as Buffer on both drivers. New tables and
collections only; sync() creates them. Contract tests on both backends; TEST_BACKENDS=pg
runs PostgreSQL only. docs/EXTERNAL-REPORTS.md describes the storage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018jBohmYiwjQLWmN2duiZcA
@BackStacked BackStacked self-assigned this Nov 9, 2026
@BackStacked
BackStacked merged commit 5959c35 into main Nov 9, 2026
1 check passed
@BackStacked
BackStacked deleted the claude/project-thread-86xth5 branch November 9, 2026 11:56
BackStacked added a commit that referenced this pull request Nov 9, 2026
## What and why

In 2.1.0, `external_report_files.id` was a foreign key to
`external_reports`. The api stores the partner PDF **first** and creates
the external report with the file's id only after extraction. Extraction
runs inline, or in a worker job whose payload carries just the file id.
On PostgreSQL, every import therefore fails with
`external_report_files_id_fkey`. This shows up on api#23's CI.

Two separate pushes made 2.1.0 miss the fix: the fix (b30ee5e) landed on
the branch after #11 had already merged.

- `src/pg/models.ts`: `id` is now a plain UUID primary key with no
foreign key. Mongo never had one.
- `src/core/types.ts` and `docs/EXTERNAL-REPORTS.md`: document that the
file is stored before its report.
- `scripts/test.ts`: a new contract check stores a PDF before its report
exists, on both backends. This check would have caught the bug.
- Version 2.1.1.

`TEST_BACKENDS=pg npm test`: 100 passed, 0 failed. Mongo is not run
locally; CI runs it.

A database that already ran `sync()` on 2.1.0 keeps the constraint, so
drop it by hand: `ALTER TABLE external_report_files DROP CONSTRAINT
external_report_files_id_fkey;`. None should exist yet, because the api
has not been deployed with 2.1.0.

Release: after merge, tag `v2.1.1`.

---
_Generated by [Claude
Code](https://claude.ai/code/session_018jBohmYiwjQLWmN2duiZcA)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants