subdocument-splitting-plan

This commit is contained in:
rehlert committed 2026-10-06 22:52:35 +02:00
1 parent f09384d2e6
commit ca06ca2050
47 files changed
+4097 -136

No files matched your search

+143
View File
@@ -0,0 +1,143 @@
# 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`)
```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).