Files
bea-edit/plan/done/batch-processing-plan.md
2026-10-06 22:52:35 +02:00

6.4 KiB
Raw Permalink Blame History

Plan: Batch-Verarbeitung in den Einzel-PDF-Tools

Goal

Several tools process exactly one PDF at a time, but real legal work is repetitive: compress ten scans, watermark five drafts, encrypt three exhibits. This plan generalizes the single-file tools to accept multiple files, process them sequentially with per-file status, and download results individually or as one ZIP.


Open decisions (defaults marked ✅)

D1 — Rollout scope

  • ✅ A. Phased rollout, starting with compress. Compress is the highest-repetition tool and already has the cleanest input→output shape. Phase 2: watermark (needs option application per file), stamp/page-numbers (same pattern). Phase 3: encrypt/decrypt (decrypt needs a password for all files — one shared password input).
  • B. All tools at once. Too much surface; the shared pattern should prove itself first.

D2 — UX model

  • ✅ A. Always multi-file. The dropzone accepts multiple PDFs from day one; a single dropped file simply renders a one-row list. No mode switch. Download: one button per finished row plus "Alle als ZIP", which appears once ≥2 files are done.
  • B. Explicit "Batch-Modus" toggle. Extra clicks and duplicated code paths.

D3 — Failure behavior

  • ✅ Continue on error. A failing file is marked with a German error message in its row; the queue keeps processing the rest. "Erneut versuchen" per failed row. This matches how lawyers will use it (one broken scan must not kill the run).

UX

Per retrofitted tool page:

  1. PdfDropzone with multiple enabled; dropping more files appends to the current list (does not replace it) — matches how the start page queues ZIPs.
  2. File list below the options card: one row per file — name, size, status chip (Wartet / Verarbeite… / Fertig ✓ mit neuer Größe / Fehler), per-row download button (enabled when done), per-row remove, "Erneut versuchen" on error.
  3. Progress line during a run: "Datei 3 von 7 wird verarbeitet…".
  4. Footer actions: "Alle herunterladen" (ZIP via fflate, named {toolname}_{date}.zip, e.g. komprimiert_2026-02-12.zip) visible when ≥2 results exist.
  5. Options (preset, watermark settings, password…) apply to all files in the run; changing options while a run is active affects only subsequent files (documented in helper text).

Technical approach

Shared batch engine (src/lib/components/BatchFileList.svelte + src/lib/batch.ts)

// src/lib/batch.ts
export type BatchItemStatus = 'pending' | 'processing' | 'done' | 'error';
export type BatchItem = {
 id: string; // crypto.randomUUID()
 file: File;
 status: BatchItemStatus;
 resultBytes?: Uint8Array;
 resultName?: string;
 errorMessage?: string | null;
};

export const runBatch = async (
 items: BatchItem[],
 process: (file: File) => Promise<{ bytes: Uint8Array; name: string }>,
 update: (id: string, patch: Partial<BatchItem>) => void
): Promise<void>;
  • runBatch iterates sequentially (memory protection: only one PDF in flight), calls update per lifecycle step so the component re-renders status chips, and never throws — per-item errors are caught and written to the item.
  • BatchFileList.svelte renders rows, emits callbacks (onDownload(item), onRemove(id), onRetry(id)); row buttons are real buttons with accessible labels including the file name.
  • Result bytes stay in memory until downloaded or removed; revocation concerns don't apply (downloads use the existing downloadBlob object-URL pattern with timeout revocation). A summary line shows total result size so users notice runaway memory situations.
  • Very large runs: warn (>20 files or >25 MB per file in rasterizing tools) with a German note; do not hard-block.

Retrofit pilot: compress

  • Extract per-file compression into compressWithPreset (already planned in bea-size-limit-plan.md — coordinate: whichever ships first creates pdf-compression.ts).
  • Page state becomes items = $state<BatchItem[]>([]) + options; the old single-result UI (compressedBytes etc.) is replaced by the list. Zielgröße mode + batch: each file runs the preset loop independently.
  • Rasterization guards apply per file: files >100 MB are immediately marked as error rows with the rasterization message instead of blocking the whole batch.

Rollout pattern for later tools

  • Watermark/stamp/page-numbers: identical wiring; the pdf-lib overlay loop is already per-page and per-file load is isolated.
  • Encrypt: one password for all files (password inputs stay at the top); per-file failure shows which file broke.
  • Decrypt: one shared password input + rasterization caveat once, per-file status as above.

Files changed

  • src/lib/batch.ts — new batch engine.
  • src/lib/components/BatchFileList.svelte — new shared list component.
  • src/routes/tools/compress/+page.svelte — pilot retrofit.
  • (Phase 2/3) watermark/stamp/page-numbers/encrypt/decrypt pages.
  • tests/e2e/toolbox.spec.ts — spec blocks per retrofitted tool.
  • agents.md — document the batch pattern for future tools.

Implementation phases

  1. batch.ts + BatchFileList.svelte (build against a mock process function first).
  2. Compress pilot retrofit (depends on pdf-compression.ts extraction).
  3. E2E for compress batch: 2 PDFs → both done, ZIP contains 2 entries; one corrupt file → error row, other still succeeds; retry works.
  4. Phase 2 tools, Phase 3 tools (separate PRs).
  5. Polish: copy, memory summary line, warning thresholds.

Verification

  • Single file dropped → identical outcome to today's single-file flow (same output bytes for the same preset).
  • Mixed success/failure batch: statuses correct, ZIP includes only successful results.
  • Remove a finished row → its bytes freed (no download offered afterwards).
  • Option change mid-run affects only following files.
  • pnpm check, pnpm lint, pnpm build, pnpm test:e2e pass.

Risks

  • Memory with many results held simultaneously: 30 compressed PDFs × several MB can strain low-end machines. Mitigations: per-row remove, total-size summary, and a follow-up "download and clear" convenience. Do not stream to disk (browser constraint).
  • Sequential processing is slow for many large files — inherent to memory safety; progress line sets expectations.

Out of scope

  • Parallel processing.
  • Cross-tool pipelines (compress → watermark in one run) — separate roadmap item.
  • Per-file option overrides (v1 applies one option set to the whole batch).