Commit Graph

112 Commits

Author SHA1 Message Date
Marcel
50e3f948c7 fix(upload): use border-ink/20 and primary color for drop zone visibility
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Failing after 1m59s
CI / Backend Unit Tests (pull_request) Successful in 2m16s
CI / E2E Tests (pull_request) Failing after 30m10s
In light mode, border-line-2 (#eeede8) was nearly invisible and
accent (#a1dcd8, mint) was too light for hover text. Switch to:
- border-ink/20 — navy-tinted dashed border, readable in both modes
- hover:border-primary / hover:text-primary — navy in light, mint in dark

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 10:09:17 +01:00
Marcel
bbfef9a22d feat(upload): add drag-and-drop bulk upload zone to home page
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m25s
CI / Backend Unit Tests (push) Successful in 2m26s
CI / E2E Tests (push) Has started running
CI / Unit & Component Tests (pull_request) Failing after 1m49s
CI / Backend Unit Tests (pull_request) Successful in 2m2s
CI / E2E Tests (pull_request) Failing after 30m19s
Adds a compact, unobtrusive drop zone between the search card and the
document list. Only visible to users with WRITE_ALL permission.

- Drag-and-drop or click-to-select multiple files at once
- Client-side MIME type validation with per-file error messages
- POSTs to /api/documents/quick-upload; refreshes list via invalidateAll()
- Inline feedback: success count + per-file errors
- i18n keys added to de/en/es message files

Closes #66 (frontend part)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 10:00:19 +01:00
Marcel
29a71f4421 fix(login): remove py-6 padding from layout on auth pages to prevent scrolling
Some checks failed
CI / Unit & Component Tests (pull_request) Successful in 2m25s
CI / Backend Unit Tests (pull_request) Successful in 2m10s
CI / E2E Tests (pull_request) Failing after 29m35s
CI / Unit & Component Tests (push) Successful in 2m27s
CI / Backend Unit Tests (push) Successful in 2m17s
CI / E2E Tests (push) Failing after 30m42s
The global layout wrapped all pages in <main class="py-6">, adding 48px
of vertical padding. Combined with min-h-screen on the login page div,
the total height exceeded 100vh and made the page scrollable.

Auth pages (/login, /forgot-password, /reset-password) now get no
padding from the layout — the same path check already used to hide
the nav header.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:47:56 +01:00
Marcel
eade2aa48a fix(login): use bg-canvas instead of bg-surface for page background
The login page used bg-surface (white) as its outer background.
The global layout already has bg-canvas (sand), so using bg-surface
created a visible white layer with a mismatched color.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:47:56 +01:00
Marcel
1765ffce01 fix(conversations): use text-primary-fg instead of text-white on sender bubbles
In dark mode --c-primary is mint (#a1dcd8), a light colour, making hardcoded
white text barely readable. Replacing text-white/text-blue-100 with
text-primary-fg (white in light, navy in dark) restores contrast in both modes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:47:56 +01:00
Marcel
51a0eb76de fix(css): set form control bg/color to surface tokens in base layer
Browser-default form controls (input, textarea, select) render with a white
background that ignores CSS custom properties in dark mode. Adding bg-surface
and text-ink to the base layer ensures they theme correctly without touching
every component.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:47:56 +01:00
Marcel
162c58e8c5 fix(components): replace remaining unthemed gray classes with semantic tokens
Replace text-gray-*, bg-gray-*, border-gray-*, divide-gray-*, placeholder-gray-*,
focus:border-blue-*, focus:ring-blue-*, hover:bg-blue-*, and ring-brand-mint with
their semantic-token equivalents (text-ink, bg-muted, border-line, etc.) across
all pages and shared components so dark mode renders correctly everywhere.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:47:56 +01:00
Marcel
e4539ed0f0 refactor(components): replace all hardcoded colors with semantic tokens
Replaces bg-white, text-brand-navy, border-brand-sand, text-gray-*, bg-[#2A2A2A],
bg-brand-purple/15, hover:bg-brand-sand, etc. across all 35 .svelte files with
semantic token utilities (bg-surface, text-ink, border-line, bg-pdf-bg, bg-nav-active,
bg-muted, text-accent, bg-primary, ...).

Also adds CSS filter: invert(1) in layout.css for De Gruyter <img> icons in dark mode,
excluding icons that carry .invert already (to prevent double-inversion).

Closes #64
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:47:56 +01:00
Marcel
caba89dacc feat(nav): add ThemeToggle component with moon/sun icons and no-flash script
- Inline <script> in app.html applies saved localStorage theme before first
  paint to prevent flash of wrong theme
- ThemeToggle.svelte: moon/sun button, localStorage persistence, sets
  data-theme on <html>, defaults to system preference on first visit
- Placed in +layout.svelte between language selector and user menu
- E2E tests cover visibility, toggle, reverse toggle, persistence, and
  no-flash behaviour — all 6 passing

Refs #64
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:47:56 +01:00
Marcel
e83ba9b681 style(frontend): apply Prettier formatting to 26 pre-existing files
No logic changes — whitespace and indentation only. These were flagged
by the pre-commit hook when running lint after layout.css was modified.

Refs #64
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:47:56 +01:00
Marcel
9aa98b4fb6 merge(frontend): resolve conflicts with main — integrate fileHash feature into panel architecture
Some checks failed
CI / Unit & Component Tests (pull_request) Successful in 2m21s
CI / Backend Unit Tests (pull_request) Successful in 2m11s
CI / E2E Tests (pull_request) Failing after 28m37s
CI / Unit & Component Tests (push) Successful in 2m26s
CI / Backend Unit Tests (push) Successful in 2m14s
CI / E2E Tests (push) Has started running
Keep the new bottom-panel / AnnotationSidePanel architecture from this branch
while pulling in the documentFileHash / visibleAnnotations filter that was added
on main. Thread documentFileHash through DocumentViewer so outdated-annotation
filtering works end-to-end.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 11:20:48 +01:00
Marcel
f71712ab4b feat(frontend): move annotation comments to right-side panel
Annotation threads now open in a slide-in side panel (320 px, right
edge of the PDF viewer) instead of expanding the bottom drawer.
The PDF stays visible while the user reads and writes annotation
comments.

- Add AnnotationSidePanel component (absolute-positioned, CSS slide
  transition, keyed CommentThread, close via X or Escape)
- Remove the $effect that opened the bottom drawer on annotation click
- Simplify PanelDiscussion back to document-level thread only (no
  annotation sub-tabs)
- Remove annotation-related props from DocumentBottomPanel and
  PanelDiscussion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 07:23:20 +01:00
Marcel
10783fdb55 fix(frontend): always start with panel closed on document open
Removed localStorage persistence for the open/closed state so the PDF
is always visible first when navigating to a document. Height and active
tab are still remembered across visits.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 07:04:20 +01:00
Marcel
5ea5590c89 fix(frontend): restore global nav bar on document detail page
The document viewer container was using fixed inset-0 z-50 which
covered the sticky global nav bar. Now measures nav height at mount
and offsets the container top accordingly, dropping z-index to z-40.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 23:26:29 +01:00
Marcel
142f296255 feat(frontend): close bottom panel when entering annotate mode
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 23:21:38 +01:00
Marcel
1eb2659ba0 fix(frontend): open bottom panel to full height below the document header
Instead of an arbitrary 80 % cap, the panel now measures the actual
DocumentTopBar height at open time and fills the remaining viewport
exactly — so the PDF is fully covered and the drawer reaches right up
to the header. Drag-to-shrink still works as before.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 23:10:26 +01:00
Marcel
f18649fb79 feat(frontend): open bottom panel at full height (80vh) by default
Panel now opens to 80 % of the viewport height so the user can immediately
read comments and metadata without having to drag it up first.
The user can drag the top handle down to make it smaller; that size is
persisted to localStorage and restored on the next visit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 23:06:42 +01:00
Marcel
8519fbb48a fix(frontend): lock document page to viewport with position: fixed
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Successful in 2m20s
CI / Backend Unit Tests (pull_request) Successful in 2m11s
CI / E2E Tests (pull_request) Failing after 26m7s
The global layout wraps pages in min-h-screen + main.py-6, which pushed
the h-screen document container below the sticky nav and caused page-level
scrolling. Switching to fixed inset-0 z-50 fully escapes the layout flow:

- DocumentTopBar always visible (no scrolling it away)
- PDF controls always visible
- Only the PDF canvas area scrolls
- DocumentBottomPanel moved inside the fixed container (logically grouped)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:53:02 +01:00
Marcel
ee85ce4668 feat(frontend): keep annotation tab after switching to document discussion
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / E2E Tests (pull_request) Failing after 26m48s
CI / Unit & Component Tests (pull_request) Successful in 2m29s
CI / Backend Unit Tests (pull_request) Successful in 2m16s
Clicking the Diskussion sub-tab no longer deselects the active annotation,
so the Annotation tab stays visible and accessible for easy toggling back.

The annotation is cleared only via Escape or clicking elsewhere on the PDF.
Removes the now-unused onClearAnnotation callback chain.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:49:44 +01:00
Marcel
ecfd80bf9a feat(frontend): add discussion sub-tab navigation for annotation threads
Some checks failed
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Successful in 2m34s
CI / Backend Unit Tests (pull_request) Successful in 2m16s
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (pull_request) Failing after 24m11s
Within the Diskussion panel tab, show two sub-tabs when an annotation is
active: «Diskussion» (document-level thread, with comment-count badge) and
«Annotation · Seite N» (annotation-specific thread).

Behaviour:
- Clicking an annotation auto-switches to the Annotation sub-tab
- Clicking the Diskussion sub-tab deselects the annotation and returns to
  the document thread
- Escape clears the active annotation (or collapses the panel if none)
- activeAnnotationPage is now lifted from PdfViewer → DocumentViewer →
  page → DocumentBottomPanel → PanelDiscussion so the tab label shows the
  correct page number

Closes #60
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:45:35 +01:00
Marcel
8c2bdbd777 feat(frontend): add floating bottom panel to document detail page
Some checks failed
CI / Unit & Component Tests (push) Successful in 4m47s
CI / Backend Unit Tests (push) Successful in 2m20s
CI / E2E Tests (push) Failing after 24m42s
Replaces the left sidebar layout with:
- Full-viewport PDF/image viewer (never resizes, position: absolute)
- Fixed floating bottom panel with tabs: Metadaten, Transkription,
  Diskussion, Verlauf
- Compact top bar with title, date · sender → receivers row, and
  Annotieren / Edit / Download actions
- Drag-to-resize panel with localStorage persistence of open/height/tab
- Panel opens automatically to Diskussion when an annotation is clicked
- Documents without a file default to showing the Metadaten tab

New components: DocumentTopBar, DocumentViewer, DocumentBottomPanel,
PanelMetadata, PanelTranscription, PanelDiscussion, PanelHistory

PdfViewer: annotateMode and activeAnnotationId lifted to bindable props;
AnnotationCommentPanel removed (discussion moves to the Diskussion tab).

Closes #62
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:35:28 +01:00
Marcel
9e2419a48e feat(frontend): remove document status pills
Status badges (UPLOADED, PLACEHOLDER, etc.) provided no real value
to users and have been removed from the document list and document
detail header.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 17:55:53 +01:00
Marcel
0ec86220d3 feat(backend): add POST /api/admin/backfill-file-hashes endpoint
- DocumentRepository: findByFileHashIsNullAndFilePathIsNotNull()
- AnnotationRepository: findByDocumentIdAndFileHashIsNull()
- FileService: downloadFileBytes() downloads raw bytes from S3 for hashing
- AnnotationService: backfillAnnotationFileHashForDocument() sets hash on null-hash annotations
- DocumentService: backfillFileHashes() iterates documents with null hash,
  downloads bytes, computes SHA-256, saves doc, then propagates hash to annotations
- AdminController: POST /api/admin/backfill-file-hashes delegates to DocumentService

Closes #56

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 17:32:29 +01:00
Marcel
7fbc33b32d feat(frontend): hide outdated annotations when file version changes
Some checks failed
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (push) Has started running
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
- Regenerate API types with fileHash on Document and DocumentAnnotation
- PdfViewer accepts documentFileHash prop; filters visibleAnnotations to
  those whose hash matches (or is null) and shows an amber notice banner
  when any annotations are hidden due to a hash mismatch
- Document detail page passes doc.fileHash to PdfViewer
- Add i18n key annotation_outdated_notice in de/en/es
- E2E: two new tests covering hide-on-reupload and restore-on-original-reupload
  scenarios; add minimal2.pdf fixture for a different-hash upload

Closes #55

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 17:09:26 +01:00
Marcel
34c66f80fc fix(e2e): fix annotation delete test and harden comments fetch
Some checks failed
CI / E2E Tests (pull_request) Has been cancelled
CI / Unit & Component Tests (push) Successful in 2m30s
CI / Backend Unit Tests (push) Successful in 2m15s
CI / E2E Tests (push) Successful in 22m47s
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
- Add aria-label="Kommentare anzeigen" to annotation container div so
  getByRole('button', { name: /annotation löschen/i }) no longer
  matches the container (its name was previously inherited from the
  child delete button, causing the test to click the wrong element)
- Wrap the server-side comments fetch in a .catch and try/catch so a
  network error or non-JSON response never crashes the document load

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 12:27:15 +01:00
Marcel
1070e6e9ec feat(comments): add CommentThread, annotation panel, Diskussion section, and i18n keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 11:02:38 +01:00
Marcel
b45ec744b2 feat: add PDF annotation feature (#40)
Backend:
- Add ANNOTATE_ALL permission
- Add ANNOTATION_NOT_FOUND and ANNOTATION_OVERLAP error codes
- V10 migration: document_annotations table with page/rect/color/owner
- DocumentAnnotation entity, AnnotationRepository, CreateAnnotationDTO
- AnnotationService: overlap detection (rectangle intersection), ownership enforcement on delete
- AnnotationController: GET (authenticated), POST/DELETE (ANNOTATE_ALL)
- 15 new tests (AnnotationServiceTest, AnnotationControllerTest) — TDD red/green

Frontend:
- AnnotationLayer.svelte: pointer-event drawing, colored rect overlays, delete buttons
- PdfViewer.svelte: annotate toggle, color picker, loads/saves/deletes annotations via API
- Disabled annotate button with tooltip for users without ANNOTATE_ALL
- canAnnotate exposed from layout server, passed to PdfViewer
- errors.ts + de/en/es translations for new error codes
- 3 new unit tests for AnnotationLayer — TDD red/green

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 23:27:21 +01:00
Marcel
5fb6a1eec0 feat(frontend): replace iframe with PDF.js viewer (#39)
- Install pdfjs-dist v5 and add optimizeDeps pre-bundle config
- New PdfViewer.svelte component: renders each page on a <canvas> with
  correct device-pixel-ratio scaling, overlays a text layer (enables
  text selection; foundation for annotations in #40), prev/next
  navigation, zoom controls, and lazy page rendering (only current ±1
  pre-fetched — avoids freezing on multi-page documents)
- Replace the <iframe> in documents/[id]/+page.svelte with PdfViewer;
  image attachments continue to use <img>; detection now uses
  doc.contentType instead of filename extension
- Unit tests for navigation controls and page counter (pdfjs mocked)
- E2E tests: PDF renders as canvas (not iframe), nav controls visible,
  image fallback stays as <img>; minimal.pdf fixture for upload tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 19:10:02 +01:00
Marcel
d84b997965 fix(frontend): show version numbers oldest-first (1 = oldest)
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Successful in 2m11s
CI / E2E Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 13:05:31 +01:00
Marcel
8c86beb9f9 feat(frontend): add expandable text component for long fields
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
Adds ExpandableText.svelte which clamps text to 10 lines and shows a
toggle button only when the content actually overflows. Applied to the
summary and transcription fields on the document detail page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 12:53:04 +01:00
Marcel
0020d1e773 fix(frontend): improve PDF zoom and diff readability
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
- PDF viewer: append #zoom=page-width to iframe src so A4 letters fill
  the panel width instead of leaving large grey gutters
- Diff view: trim unchanged context to 4 words either side of each
  change, replacing long runs with '…' so edits are easy to spot

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 12:46:56 +01:00
Marcel
47b8cc9340 feat(frontend): add System tab to admin panel with backfill-versions action
Some checks failed
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Successful in 2m13s
CI / Backend Unit Tests (pull_request) Successful in 2m17s
CI / E2E Tests (pull_request) Failing after 22m45s
Admin can trigger an initial history snapshot for all documents without
version history. Shows count of backfilled documents after completion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 12:33:39 +01:00
Marcel
f32ed32f67 fix(frontend): correct diff direction in history panel
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Successful in 2m9s
CI / Backend Unit Tests (pull_request) Successful in 2m4s
CI / E2E Tests (pull_request) Failing after 22m54s
versions array is ascending (oldest first), so the previous version
is at idx-1, not idx+1. Using idx+1 caused added/removed to be swapped,
showing new text as red and old text as green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 12:13:11 +01:00
Marcel
4a0d3b3bea test(e2e): add history panel playwright spec
Some checks failed
CI / Unit & Component Tests (push) Successful in 2m19s
CI / Backend Unit Tests (push) Successful in 2m11s
CI / E2E Tests (push) Has started running
CI / Unit & Component Tests (pull_request) Successful in 2m7s
CI / Backend Unit Tests (pull_request) Successful in 2m0s
CI / E2E Tests (pull_request) Failing after 21m58s
Three scenarios: versions list appears after edits, diff shows changed
field, compare mode displays diff between two selected versions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 11:59:43 +01:00
Marcel
d4b1a709d7 feat(frontend): add document history panel with diff and compare mode
Adds a collapsible history section to the document detail view, showing
all saved versions with changed-field labels, word-level diff between
adjacent versions, and a compare mode for any two arbitrary versions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 11:57:33 +01:00
Marcel
17db73d900 fix(frontend): hide nav header on forgot-password and reset-password routes
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 09:28:03 +01:00
Marcel
908221f04d feat(frontend): add forgot-password and reset-password pages
Some checks failed
CI / Unit & Component Tests (push) Successful in 2m7s
CI / Backend Unit Tests (push) Successful in 2m3s
CI / E2E Tests (push) Failing after 14m54s
CI / Unit & Component Tests (pull_request) Successful in 2m4s
CI / E2E Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
- /forgot-password: email form → sends POST /api/auth/forgot-password → success banner
- /reset-password: password form reads token from URL → sends POST /api/auth/reset-password
- Login page: add "Passwort vergessen?" link
- hooks.server.ts: add /forgot-password and /reset-password to PUBLIC_PATHS; skip auth
  injection for public auth API endpoints
- errors.ts: add INVALID_RESET_TOKEN error code
- i18n: add all new message keys in de/en/es
- playwright.config.ts: use E2E_BASE_URL for webServer check URL (allows reusing docker
  dev server at port 5173 locally)
- ci.yml: pass E2E_BACKEND_URL=http://localhost:8080 to E2E test step
- e2e/password-reset.spec.ts: 5 tests (4 pass locally, full flow requires e2e profile in CI)
- Regenerated OpenAPI types including new /api/auth/* endpoints

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 07:26:35 +01:00
Marcel
f98792f10b fix(permissions): redirect read-only users from /documents/new to home
Some checks failed
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
CI / Unit & Component Tests (push) Successful in 2m5s
CI / Backend Unit Tests (push) Successful in 2m0s
CI / E2E Tests (push) Failing after 21m36s
throw error(403) kept the URL at /documents/new (the error page renders
in-place). Changed to throw redirect(303, '/') so the URL actually changes,
matching the E2E test expectation that a read-only user is redirected away.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 23:01:45 +01:00
Marcel
70d858b65a fix(tests): add missing user/canWrite/form props to admin spec fixtures
After the layout load function started injecting user+canWrite into all
page data, the admin spec files failed svelte-check with missing property
errors. Add user:undefined, canWrite:true, and form:null to all fixture
data objects.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 23:01:25 +01:00
Marcel
fb4f8e820c feat(admin): add dedicated routes for admin user management (#37)
Some checks failed
CI / Unit & Component Tests (push) Successful in 2m4s
CI / Backend Unit Tests (push) Successful in 1m59s
CI / E2E Tests (push) Failing after 18m4s
CI / Unit & Component Tests (pull_request) Successful in 2m2s
CI / Backend Unit Tests (pull_request) Successful in 2m0s
CI / E2E Tests (pull_request) Failing after 16m10s
- New GET /admin/users/new page: create user with all profile fields
  (login, password, firstName, lastName, birthDate, email, contact, groups)
- New GET /admin/users/[id] page: edit user profile, groups, and
  optional password change without requiring current password
- New PUT /api/users/{id} backend endpoint (ADMIN_USER permission)
  with AdminUpdateUserRequest DTO for admin-override user updates
- Refactored admin users tab: replaced inline editing with edit links
  to dedicated routes; create button now links to /admin/users/new
- Extended CreateUserRequest with profile fields so new users can be
  created with full profile data in a single request
- Added 28 component tests across 3 new spec files (TDD)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 16:33:50 +01:00
Marcel
f6634f1d00 fix(tests): fix Svelte 5 event delegation not firing via Playwright locator clicks
Replace Playwright locator .click() calls with native DOM element.click()
for all tests that trigger Svelte 5 delegated onclick handlers ($.delegated).
Playwright's CDP-based synthetic events don't propagate through Svelte 5's
document-level handle_event_propagation delegation mechanism, while native
DOM .click() does.

Also replace locator.click() with element.focus() for onfocus handler tests,
and add cleanup() to afterEach in all spec files missing it to prevent test
pollution between runs. Fix TagInput.svelte to use untrack() when reading
bindable state after an await to avoid track_reactivity_loss errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 12:34:56 +01:00
Marcel
18601db4f8 fix(profile): use dd.mm.yyyy date input for birth date field
Some checks failed
CI / Unit & Component Tests (pull_request) Successful in 2m4s
CI / Backend Unit Tests (pull_request) Successful in 1m57s
CI / E2E Tests (pull_request) Failing after 13m53s
CI / Unit & Component Tests (push) Successful in 2m35s
CI / E2E Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
Replace the browser-native type="date" picker with a text input using
the same german format (dd.mm.yyyy with auto-dot insertion) as the
document date fields. A hidden input sends the ISO value to the server.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:40 +01:00
Marcel
a65c69b0ce fix(tests): fix type errors in spec files after adding user to App.PageData
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Successful in 1m57s
CI / Backend Unit Tests (pull_request) Successful in 1m55s
CI / E2E Tests (pull_request) Failing after 14m6s
Add user: undefined to baseData in conversations and documents/new specs.
Change null to undefined for filePath/transcription in makeDoc fixture.
Add form: null to render calls missing it.
Fix birthYear conversion from string to number in persons/[id] server action.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:05:08 +01:00
Marcel
168225d67c feat(frontend): add profile page and public user profile page
/profile: two-card layout with personal info form (name, birth date,
email, contact) and password change form, each with independent actions.
/users/[id]: read-only public view showing name, username, email, contact
with avatar circle initials.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:04:10 +01:00
Marcel
401a1f359f feat(frontend): replace logout button with user avatar dropdown in nav
Show user initials (e.g. MM) in a circular button when name is set,
or a fallback person icon. Clicking opens a dropdown with links to
/profile and a logout form.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:03:42 +01:00
Marcel
da0d5495d0 fix(persons): prevent stale navigation from clobbering focused search input
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 2m12s
CI / Backend Unit Tests (pull_request) Successful in 1m58s
CI / E2E Tests (pull_request) Successful in 17m40s
CI / Unit & Component Tests (push) Successful in 1m58s
CI / Backend Unit Tests (push) Successful in 1m59s
CI / E2E Tests (push) Successful in 14m56s
The persons list search input used value={data.q || ''} bound directly to
server data, so every navigation completion would reset it to the URL value
mid-typing, dropping keystrokes just like issue #34 on the home page.

Apply the same focus-guard fix: introduce local `q` state, a `qFocused`
flag, and a guarded $effect that only syncs URL → state when the input is
not focused. Adds a regression test matching the home-page pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 21:54:56 +01:00
Marcel
513a7290b0 fix(conversations): keep swap button in DOM to prevent grid column width shift
All checks were successful
CI / Unit & Component Tests (push) Successful in 1m56s
CI / Backend Unit Tests (push) Successful in 1m53s
CI / E2E Tests (push) Successful in 16m37s
CI / Unit & Component Tests (pull_request) Successful in 2m2s
CI / Backend Unit Tests (pull_request) Successful in 2m2s
CI / E2E Tests (pull_request) Successful in 16m55s
The swap button was conditionally removed from the DOM with {#if}, which
caused the receiver input to collapse into the narrow auto column of the
grid-cols-[1fr_auto_1fr] layout on desktop when no persons were selected.

The button is now always rendered. On desktop it becomes invisible
(visibility:hidden) when no persons are selected, preserving the middle
column width so both 1fr columns stay equal. On mobile it remains hidden
(display:none) via the hidden class so no empty gap appears between the
stacked inputs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 21:32:23 +01:00
Marcel
0f8b582813 test(documents): add component tests for sender/receiver URL prefill on new document page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 21:32:23 +01:00
Marcel
4026bb9003 feat(documents): prefill sender and receiver from URL params on new document page
When navigating from the conversations page via the 'New document in this
correspondence' link, the senderId and receiverId query params are now read
in the server load, resolved to person names, and used to pre-populate the
sender typeahead and receiver multi-select on the form.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 21:32:23 +01:00
Marcel
f2f9a1bf03 test(conversations): add component tests for new features
Covers: empty state, swap button (visible/hidden, goto called with
swapped params), summary content, year dividers, and new document link
visibility gated by canWrite.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 21:32:23 +01:00