subdocument-splitting-plan
This commit is contained in:
1 parent
f09384d2e6
commit
ca06ca2050
47 files changed
+4097
-136
No files matched your search
@@ -3,8 +3,9 @@
|
||||
## Project overview
|
||||
|
||||
This repository contains **juri-merger**, a German-language SvelteKit application branded as
|
||||
**beA-Edit**. Users add one or more ZIP archives in the browser, inspect and reorder supported
|
||||
attachments, optionally group attachments into named sub-documents, and export merged PDFs.
|
||||
**beA-Edit**. Users add one or more beA ZIP archives or PDF files in the browser, inspect and
|
||||
reorder supported attachments, group attachments into named sub-documents (including page-level
|
||||
PDF splitting), and export merged PDFs.
|
||||
Nested ZIP archives and XJustiz metadata are handled client-side; there is no upload, server-side
|
||||
archive processing, database, analytics, or persistence of case data.
|
||||
|
||||
@@ -69,10 +70,12 @@ src/
|
||||
│ ├── assets/ # Favicon and local Nunito fonts
|
||||
│ ├── components/
|
||||
│ │ ├── AttachmentPreview.svelte # Browser-rendered PDF/image thumbnails
|
||||
│ │ ├── AttachmentMenu.svelte # Per-attachment dropdown menu (move, split, remove)
|
||||
│ │ ├── BatchFileList.svelte # Shared batch rows: status chips, downloads, retry
|
||||
│ │ ├── BeaArchiveProcessing.svelte
|
||||
│ │ ├── BeaWorkspaceControls.svelte # beA workspace toolbar, settings popover, dialogs
|
||||
│ │ ├── ProcessedZipArchiveEditor.svelte
|
||||
│ │ ├── PdfSplitDialog.svelte # Page-level PDF splitting into Teildokumente
|
||||
│ │ ├── SubDocumentEditor.svelte
|
||||
│ │ ├── FileDropzone.svelte # Shared PDF/image/ZIP file picker and drop target
|
||||
│ │ ├── ZipFilePicker.svelte # Compact ZIP picker button with hidden resettable input
|
||||
@@ -142,8 +145,8 @@ committed.
|
||||
|
||||
## Application flow and state
|
||||
|
||||
- `/` is the toolbox hub. A ZIP dropped anywhere on that route is queued in memory and forwarded to
|
||||
`/tools/bea`; the file is not uploaded or persisted.
|
||||
- `/` is the toolbox hub. A beA ZIP or PDF dropped anywhere on that route is queued in memory and
|
||||
forwarded to `/tools/bea`; the file is not uploaded or persisted.
|
||||
- `/tools/metadata` is a single-PDF inspection tool. `src/lib/pdf-metadata.ts` reads document
|
||||
properties with pdf-lib only (no rasterization), returns a discriminated `{ status: 'encrypted' }`
|
||||
result for password-protected files, and detects embedded-file markers by scanning raw bytes.
|
||||
@@ -153,41 +156,61 @@ committed.
|
||||
thumbnail-width preference. Thumbnail width is the only persisted UI setting and uses localStorage.
|
||||
- The loaded workspace renders `BeaWorkspaceControls.svelte`, a top-aligned toolbar with the
|
||||
workspace status and two archive lifecycle actions:
|
||||
- **“Neue ZIP bearbeiten”** (replace) opens a ZIP picker and, after the user confirms the
|
||||
- **“Neue Datei bearbeiten”** (replace) opens a file picker and, after the user confirms the
|
||||
replacement dialog, calls `replaceWithZipFiles(files)` which resets the workspace and enqueues the
|
||||
new files against the incremented generation. Files picked for replacement stay in temporary
|
||||
component state until confirmation; cancelling the picker or the dialog must never mutate the
|
||||
current workspace.
|
||||
- **“Weitere ZIP hinzufügen”** (append) lives in the settings popover, uses the plain append path
|
||||
- **“Weitere Datei hinzufügen”** (append) lives in the settings popover, uses the plain append path
|
||||
(`handleFilesSelected`), and never clears current archives. Keep the two labels distinct:
|
||||
replace is “Neue ZIP bearbeiten”, append is “Weitere ZIP hinzufügen”.
|
||||
replace is “Neue Datei bearbeiten”, append is “Weitere Datei hinzufügen”.
|
||||
- `BeaWorkspaceControls.svelte` owns only ephemeral UI state (popover/dialog open state and pending
|
||||
replacement files). The route remains the source of truth for files, jobs, archives, and the
|
||||
persisted thumbnail width.
|
||||
- `resetWorkspace()` is the single teardown helper: it increments `archiveGeneration` and clears
|
||||
selected files, processed archives, and jobs. Never clear those arrays without going through it.
|
||||
- Accepted ZIP types and the file filter for the dropzone and both compact pickers are centralized in
|
||||
`src/lib/zip-selection.ts`; `ZipFilePicker.svelte` resets its input after every selection so the
|
||||
- Accepted file types for the workspace (beA ZIP **and** PDF) are centralized in
|
||||
`src/lib/zip-selection.ts` and shared by the dropzone, the start-page drop target, and both
|
||||
compact pickers; `ZipFilePicker.svelte` resets its input after every selection so the
|
||||
same file can be chosen again.
|
||||
- ZIP files are processed concurrently. `archiveGeneration` prevents results from an old batch from
|
||||
reappearing after the user deletes all archives **or** confirms a replacement.
|
||||
- Workspace files are processed concurrently. PDF files become single-attachment archives via
|
||||
`pdfFileToArchive`; ZIP files go through `extractZipArchives`. `archiveGeneration` prevents
|
||||
results from an old batch from reappearing after the user deletes all archives **or** confirms a
|
||||
replacement.
|
||||
- `ProcessedZipArchiveEditor.svelte` edits one archive and emits immutable replacements through
|
||||
`onArchiveChange`; the route-level archive array remains the source of truth.
|
||||
- Attachments may remain loose or belong to exactly one sub-document. Drag-and-drop supports
|
||||
reordering and moving attachments between lists, while sub-document headers can be reordered.
|
||||
- Selection mode creates sub-documents from loose attachments. Exiting with **Fertig** or Escape
|
||||
clears the pending selection.
|
||||
- **Gruppieren** (grouping mode) offers archive-wide multi-select over loose and sub-document
|
||||
attachments: create a new Teildokument from the selection, move the selection into an existing
|
||||
Teildokument, select all/none. Exiting with **Fertig** or Escape clears the pending selection.
|
||||
New Teildokumente are numbered via `nextSubDocumentNumber` (max existing trailing number, not
|
||||
list length), and the created block's name input is focused and scrolled into view.
|
||||
- Each attachment card has an **“⋯” menu** (`AttachmentMenu.svelte`) as the keyboard/touch path:
|
||||
move into an existing or new Teildokument, move back to the loose list, split PDFs, and remove
|
||||
(with confirmation). It must never become the only way to perform an action that drag-and-drop
|
||||
also covers.
|
||||
- **PDF splitting**: `PdfSplitDialog.svelte` opens per PDF attachment, renders pages through
|
||||
`loadPdfDocument` + `PdfPageGrid`, and assigns page sets to named groups (manual selection,
|
||||
“Jede Seite einzeln”, or “Alle N Seiten”). Cut is the default; “Seiten im Original behalten”
|
||||
switches to copy. `applyPdfSplit` replaces the source with the remaining pages (or removes it),
|
||||
inserts the new Teildokumente after the source's parent block, and the synthetic attachments
|
||||
get unique `#seiten-…` path suffixes because `path` is the identity for keyed lists, drag
|
||||
payloads, and selection.
|
||||
- Per-archive export supports one flattened PDF or separate PDFs for sub-documents. Each
|
||||
sub-document also has its own direct download action that exports only that sub-document's
|
||||
attachments. Bulk export from the page always creates one flattened PDF per archive.
|
||||
|
||||
When changing archive transforms, preserve these invariants:
|
||||
|
||||
- An attachment move must not duplicate or discard data.
|
||||
- An attachment move must not duplicate or discard data. Splitting cuts pages by default and only
|
||||
duplicates them when the user explicitly chooses copy mode.
|
||||
- Sub-document IDs remain stable across edits and reordering.
|
||||
- Single-PDF order is all sub-documents in order, each attachment in order, followed by loose
|
||||
attachments in order.
|
||||
- Dissolving a sub-document appends its attachments to the loose list.
|
||||
- Splitting inserts the new Teildokumente directly after the source's parent block (loose source:
|
||||
appended at the end) so the reading order is preserved.
|
||||
- State helpers in `zip-processing.ts` should return new archive/list objects rather than mutating
|
||||
component-owned state.
|
||||
|
||||
@@ -205,6 +228,9 @@ All case-file processing is intentionally local to the browser.
|
||||
extension classification and downstream preview/export behavior together when adding formats.
|
||||
- PDF attachments are copied with pdf-lib. JPEG and PNG files can be embedded directly; other image
|
||||
formats are decoded through browser image/canvas APIs and converted to PNG first.
|
||||
- Page-set copies (separate/extract tools, PDF splitting) share
|
||||
`copyPagesToNewPdf(sourceBytes, pageIndexes)` in `src/lib/pdf-processing.ts` so the copy
|
||||
semantics cannot drift apart.
|
||||
- `AttachmentPreview.svelte` dynamically loads pdfjs-dist in `onMount`, copies PDF bytes before
|
||||
rendering, and revokes object URLs during cleanup. Preserve those memory and data-integrity
|
||||
safeguards.
|
||||
|
||||
Reference in new issue
Block a user