refactor: move lib-root files to lib/shared/ and finalize domain structure

- Move api.server.ts, errors.ts, types.ts, utils.ts, relativeTime.ts to lib/shared/
- Move person relationship components to lib/person/relationship/
- Move Stammbaum components to lib/person/genealogy/
- Move HelpPopover to lib/shared/primitives/
- Update all import paths across routes, specs, and lib files
- Update vi.mock() paths in server-project test files
- Remove now-empty legacy directories (components/, hooks/, server/, etc.)
- Update vite.config.ts coverage include paths for new structure
- Update frontend/CLAUDE.md to reflect domain-based lib/ layout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-05 14:53:31 +02:00
parent efcc347c00
commit 567612761d
119 changed files with 186 additions and 167 deletions

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import * as m from '$lib/paraglide/messages.js';
import { relativeTimeDe } from '$lib/relativeTime';
import { relativeTimeDe } from '$lib/shared/relativeTime';
type IncompleteDoc = {
id: string;

View File

@@ -3,7 +3,7 @@ import { m } from '$lib/paraglide/messages.js';
import { formatDate } from '$lib/shared/utils/date';
import { formatDocumentStatus } from '$lib/document/documentStatusLabel';
import { getInitials, personAvatarColor } from '$lib/person/personFormat';
import RelationshipPill from '$lib/person/RelationshipPill.svelte';
import RelationshipPill from '$lib/person/relationship/RelationshipPill.svelte';
type Person = { id: string; firstName?: string | null; lastName: string; displayName: string };
type Tag = { id: string; name: string };

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { getContext } from 'svelte';
import type { Annotation } from '$lib/types';
import type { Annotation } from '$lib/shared/types';
import { m } from '$lib/paraglide/messages.js';
type UpdateAnnotationFn = (

View File

@@ -1,7 +1,7 @@
import { describe, it, expect } from 'vitest';
import { render } from 'vitest-browser-svelte';
import AnnotationEditOverlay from './AnnotationEditOverlay.svelte';
import type { Annotation } from '$lib/types';
import type { Annotation } from '$lib/shared/types';
const annotation: Annotation = {
id: 'ann-1',

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import type { Annotation } from '$lib/types';
import type { Annotation } from '$lib/shared/types';
import AnnotationShape from './AnnotationShape.svelte';
type DrawRect = {

View File

@@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
import { render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import AnnotationLayer from './AnnotationLayer.svelte';
import type { Annotation } from '$lib/types';
import type { Annotation } from '$lib/shared/types';
const annotation: Annotation = {
id: 'ann-1',

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import type { Annotation } from '$lib/types';
import type { Annotation } from '$lib/shared/types';
import AnnotationEditOverlay from './AnnotationEditOverlay.svelte';
let {

View File

@@ -1,7 +1,7 @@
import { describe, it, expect } from 'vitest';
import { render } from 'vitest-browser-svelte';
import AnnotationShape from './AnnotationShape.svelte';
import type { Annotation } from '$lib/types';
import type { Annotation } from '$lib/shared/types';
const annotation: Annotation = {
id: 'ann-1',

View File

@@ -3,7 +3,7 @@ import { m } from '$lib/paraglide/messages.js';
import { getConfirmService } from '$lib/shared/services/confirm.svelte.js';
import CommentThread from '$lib/shared/discussion/CommentThread.svelte';
import PersonMentionEditor from '$lib/shared/discussion/PersonMentionEditor.svelte';
import type { PersonMention } from '$lib/types';
import type { PersonMention } from '$lib/shared/types';
const { confirm } = getConfirmService();

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { provideConfirmService, type ConfirmService } from '$lib/shared/services/confirm.svelte.js';
import TranscriptionBlock from './TranscriptionBlock.svelte';
import type { PersonMention } from '$lib/types';
import type { PersonMention } from '$lib/shared/types';
type BlockProps = {
blockId: string;

View File

@@ -3,7 +3,7 @@ import { m } from '$lib/paraglide/messages.js';
import TranscriptionBlock from './TranscriptionBlock.svelte';
import OcrTrigger from '$lib/ocr/OcrTrigger.svelte';
import TranscribeCoachEmptyState from '$lib/shared/help/TranscribeCoachEmptyState.svelte';
import type { PersonMention, TranscriptionBlockData } from '$lib/types';
import type { PersonMention, TranscriptionBlockData } from '$lib/shared/types';
import { createBlockAutoSave } from '$lib/document/transcription/useBlockAutoSave.svelte';
import { createBlockDragDrop } from '$lib/document/transcription/useBlockDragDrop.svelte';

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
import { getLocale } from '$lib/paraglide/runtime.js';
import HelpPopover from '$lib/shared/help/HelpPopover.svelte';
import HelpPopover from '$lib/shared/primitives/HelpPopover.svelte';
type Props = {
mode: 'read' | 'edit';

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import type { TranscriptionBlockData } from '$lib/types';
import type { TranscriptionBlockData } from '$lib/shared/types';
import type { components } from '$lib/generated/api';
import { splitByMarkers } from '$lib/document/transcription/transcriptionMarkers';
import {

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import TranscriptionReadView from './TranscriptionReadView.svelte';
import type { TranscriptionBlockData } from '$lib/types';
import type { TranscriptionBlockData } from '$lib/shared/types';
const PERSON_ID = '11111111-0000-0000-0000-000000000001';

View File

@@ -2,7 +2,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import TranscriptionReadView from './TranscriptionReadView.svelte';
import type { TranscriptionBlockData } from '$lib/types';
import type { TranscriptionBlockData } from '$lib/shared/types';
const blocks: TranscriptionBlockData[] = [
{

View File

@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import { BlockConflictResolvedError, mergeBlockOnConflict } from './blockConflictMerge';
import type { PersonMention, TranscriptionBlockData } from '$lib/types';
import type { PersonMention, TranscriptionBlockData } from '$lib/shared/types';
const baseBlock: TranscriptionBlockData = {
id: 'b1',

View File

@@ -1,4 +1,4 @@
import type { PersonMention, TranscriptionBlockData } from '$lib/types';
import type { PersonMention, TranscriptionBlockData } from '$lib/shared/types';
/**
* Sentinel thrown by saveBlockWithConflictRetry after a 409 rename-mid-edit

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, vi } from 'vitest';
import { saveBlockWithConflictRetry } from './saveBlockWithConflictRetry';
import { BlockConflictResolvedError } from './blockConflictMerge';
import type { PersonMention } from '$lib/types';
import type { PersonMention } from '$lib/shared/types';
const DOC = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa';
const BLK = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb';

View File

@@ -1,4 +1,4 @@
import type { PersonMention, TranscriptionBlockData } from '$lib/types';
import type { PersonMention, TranscriptionBlockData } from '$lib/shared/types';
import {
BlockConflictResolvedError,
mergeBlockOnConflict

View File

@@ -1,5 +1,5 @@
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from 'vitest';
import type { PersonMention } from '$lib/types';
import type { PersonMention } from '$lib/shared/types';
const mockSaveFn =
vi.fn<(blockId: string, text: string, mentionedPersons: PersonMention[]) => Promise<void>>();

View File

@@ -1,5 +1,5 @@
import { SvelteMap } from 'svelte/reactivity';
import type { PersonMention } from '$lib/types';
import type { PersonMention } from '$lib/shared/types';
export type SaveState = 'idle' | 'saving' | 'saved' | 'fading' | 'error';

View File

@@ -1,6 +1,6 @@
import { describe, it, expect, vi } from 'vitest';
import { createBlockDragDrop } from './useBlockDragDrop.svelte';
import type { TranscriptionBlockData } from '$lib/types';
import type { TranscriptionBlockData } from '$lib/shared/types';
function makeBlock(id: string, sortOrder: number): TranscriptionBlockData {
return {

View File

@@ -1,4 +1,4 @@
import type { TranscriptionBlockData } from '$lib/types';
import type { TranscriptionBlockData } from '$lib/shared/types';
type Options = {
getSortedBlocks: () => TranscriptionBlockData[];

View File

@@ -3,9 +3,9 @@ import { onMount, setContext } from 'svelte';
import { createPdfRenderer } from '$lib/document/viewer/usePdfRenderer.svelte';
import PdfControls from './PdfControls.svelte';
import AnnotationLayer from '$lib/document/annotation/AnnotationLayer.svelte';
import type { Annotation } from '$lib/types';
import type { Annotation } from '$lib/shared/types';
import { m } from '$lib/paraglide/messages.js';
import { parseBackendError, getErrorMessage } from '$lib/errors';
import { parseBackendError, getErrorMessage } from '$lib/shared/errors';
type DrawRect = { x: number; y: number; width: number; height: number; pageNumber: number };

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import { enhance } from '$app/forms';
import { m } from '$lib/paraglide/messages.js';
import RelationshipChip from '$lib/person/RelationshipChip.svelte';
import AddRelationshipForm from '$lib/person/AddRelationshipForm.svelte';
import RelationshipChip from '$lib/person/relationship/RelationshipChip.svelte';
import AddRelationshipForm from '$lib/person/relationship/AddRelationshipForm.svelte';
import { chipLabel, otherName, inferredRelationshipLabel } from '$lib/person/relationshipLabels';
import type { components } from '$lib/generated/api';

View File

@@ -4,8 +4,8 @@ import { page } from 'vitest/browser';
import StammbaumCard from './StammbaumCard.svelte';
vi.mock('$app/forms', () => ({ enhance: () => () => {} }));
vi.mock('$lib/person/RelationshipChip.svelte', () => ({ default: () => null }));
vi.mock('$lib/person/AddRelationshipForm.svelte', () => ({ default: () => null }));
vi.mock('$lib/person/relationship/RelationshipChip.svelte', () => ({ default: () => null }));
vi.mock('$lib/person/relationship/AddRelationshipForm.svelte', () => ({ default: () => null }));
afterEach(cleanup);

View File

@@ -3,8 +3,8 @@ import { onMount } from 'svelte';
import { invalidateAll } from '$app/navigation';
import { m } from '$lib/paraglide/messages.js';
import { chipLabel, otherName, inferredRelationshipLabel } from '$lib/person/relationshipLabels';
import AddRelationshipForm from '$lib/person/AddRelationshipForm.svelte';
import type { RelFormData } from '$lib/person/AddRelationshipForm.svelte';
import AddRelationshipForm from '$lib/person/relationship/AddRelationshipForm.svelte';
import type { RelFormData } from '$lib/person/relationship/AddRelationshipForm.svelte';
import type { components } from '$lib/generated/api';
type PersonNodeDTO = components['schemas']['PersonNodeDTO'];

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
import type { FlatMessage } from '$lib/types';
import type { FlatMessage } from '$lib/shared/types';
import { extractQuote } from '$lib/shared/discussion/comment';
import { getInitials } from '$lib/person/personFormat';
import { relativeTime } from '$lib/shared/utils/time';

View File

@@ -2,7 +2,7 @@ import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page, userEvent } from 'vitest/browser';
import CommentMessage from './CommentMessage.svelte';
import type { FlatMessage } from '$lib/types';
import type { FlatMessage } from '$lib/shared/types';
afterEach(cleanup);

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { onMount, untrack } from 'svelte';
import { m } from '$lib/paraglide/messages.js';
import type { Comment, FlatMessage, MentionDTO } from '$lib/types';
import type { Comment, FlatMessage, MentionDTO } from '$lib/shared/types';
import MentionEditor from '$lib/shared/discussion/MentionEditor.svelte';
import CommentMessage from '$lib/shared/discussion/CommentMessage.svelte';
import { extractContent } from '$lib/shared/discussion/mention';

View File

@@ -2,7 +2,7 @@ import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import CommentThread from './CommentThread.svelte';
import type { Comment } from '$lib/types';
import type { Comment } from '$lib/shared/types';
afterEach(() => {
cleanup();

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { onDestroy, tick } from 'svelte';
import { detectMention } from '$lib/shared/discussion/mention';
import type { MentionDTO } from '$lib/types';
import type { MentionDTO } from '$lib/shared/types';
import { m } from '$lib/paraglide/messages.js';
type Props = {

View File

@@ -5,7 +5,7 @@ import StarterKit from '@tiptap/starter-kit';
import { Mention } from '@tiptap/extension-mention';
import { m } from '$lib/paraglide/messages.js';
import type { components } from '$lib/generated/api';
import type { PersonMention } from '$lib/types';
import type { PersonMention } from '$lib/shared/types';
import { deserialize, serialize } from '$lib/shared/discussion/mentionSerializer';
import MentionDropdown from './MentionDropdown.svelte';

View File

@@ -6,7 +6,7 @@ import {
renderBody,
renderTranscriptionBody
} from './mention';
import type { MentionDTO, PersonMention } from '$lib/types';
import type { MentionDTO, PersonMention } from '$lib/shared/types';
// ─── escapeHtml ───────────────────────────────────────────────────────────────

View File

@@ -1,4 +1,4 @@
import type { MentionDTO, PersonMention } from '$lib/types';
import type { MentionDTO, PersonMention } from '$lib/shared/types';
/**
* Single-source CSS selector for rendered person-mention anchors. Used by:

View File

@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import { deserialize, serialize } from './mentionSerializer';
import type { PersonMention } from '$lib/types';
import type { PersonMention } from '$lib/shared/types';
// ─── deserialize ─────────────────────────────────────────────────────────────

View File

@@ -1,5 +1,5 @@
import type { JSONContent } from '@tiptap/core';
import type { PersonMention } from '$lib/types';
import type { PersonMention } from '$lib/shared/types';
/**
* Converts stored block text + sidecar into a Tiptap ProseMirror document.