fix(import): stop the per-file model pass and parallelize underlag-to-verifikat attach (#2188) (#2229)

Linking migrated underlag to verifikat by filename ran one request per
file, strictly in sequence, and each request awaited a vision-model
extraction through document.uploaded even though the file lands on an
already-posted verifikat. A few hundred files took ten-plus minutes in
the foreground.

- The attach route passes extractionOwner: 'none' to uploadDocument: the
  booking is already known, so the model pass bought nothing. Same opt-out
  the provider underlag sweep took in #1783.
- The wizard runs the attach step through mapWithConcurrency with a pool
  of 4 instead of one-after-another; the per-file counter still ticks and
  the outcome list keeps plan order.

The per-file re-plan (planPermitsAttach) still costs two DB round trips
per file; it is bounded now that the pool overlaps them, and left as is.

Closes #2188


Claude-Session: https://claude.ai/code/session_01QPQLwHNEiQfiCNLSMzXMiQ

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-09-03 17:16:50 +02:00
committed by GitHub
co-authored by Jakob Wennberg Claude Fable 5.1
parent bc5da12372
commit 9a25672dcb
3 changed files with 32 additions and 10 deletions
@@ -312,6 +312,8 @@ describe('POST /api/import/documents/attach', () => {
// key is the entry, not the bytes.
idempotency_key: TARGET_ID,
upload_source: 'file_upload',
// The verifikat is already booked: no per-file model pass (#2188).
extractionOwner: 'none',
})
})
+7
View File
@@ -177,6 +177,13 @@ export const POST = withRouteContext(
{
upload_source: 'file_upload',
journal_entry_id: journalEntryId,
// The file lands on a posted verifikat by construction, so the
// booking is already known and a model pass per file buys nothing.
// Run inline through document.uploaded (the bus awaits its
// handlers), that pass was the bulk of a 10-minute foreground wait
// on a few hundred migrated files (#2188). Same opt-out as the
// provider underlag sweep (#1783), for the same reason.
extractionOwner: 'none',
// Scope the deterministic id to the target verifikat: the same
// receipt may legitimately back several verifikat, so content alone
// must not dedupe across them.