audit(frontend): score frontend/ against legibility rubric C1–C10 #388
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Part of Epic #387 — Codebase Legibility Audit. This is AUDIT-1: read-only assessment of
frontend/against the full Legibility Rubric. The output is a Markdown report underdocs/audits/audit-frontend-report.mdfollowing the per-subsystem orient template. No code changes in this issue.Inputs (read first)
See the first comment of #387 for the complete reference bundle:
Scope (in)
frontend/src/— routes, components, lib, hooks, utils, stores, server, paraglidefrontend/messages/(i18n source)frontend/package.json, build scripts, vitest/playwright configfrontend/CLAUDE.md(evaluate as documentation surface)frontend/Dockerfile(only the developer-experience aspects)Scope (out)
frontend/node_modules/frontend/.svelte-kit/,frontend/.svelte-kit.old/frontend/test-results.locked/,frontend/e2e/.auth/frontend/src/lib/paraglide/Rubric checks particularly relevant to this subsystem
All of C1, C2 (frontend portion), C3.5, C3.6, C4, C5, C6.3, C6.4, C7, C8.2, C8.3, C8.4, C9.2, C10. C1–C2 may overlap with AUDIT-5 — note overlap and let AUDIT-6 deduplicate at rollup.
Acceptance criteria
docs/audits/audit-frontend-report.mdexists on a feature branchlib/components/(root level) that doesn't map cleanly to the canonical domain set, with a recommended target locationlib/shared/with admission-criteria justificationfrontend/.svelte-kit.old/andfrontend/test-results.locked/directoriesdocs/audits/and is merged before this issue is closedDefinition of Done
Report committed under
docs/audits/audit-frontend-report.mdonmain. Top-5 recommendations summarized as a closing comment on this issue. Issue closed viaCloses #Nin the merge commit.Dispatch
Recommended: hand to a parallel Explore agent with the prompt:
AUDIT-1 — Frontend Legibility Audit
Read-only assessment of
frontend/againstRUBRIC-LEGIBILITY-001. Report followsTEMPLATE-ORIENT-001. Reference bundle: issue #387, first comment.1. Subsystem profile
The frontend is a SvelteKit 2 + Svelte 5 (runes) SSR app served by
@sveltejs/adapter-node. It owns the entire web UI for the Familienarchiv: file-based routing undersrc/routes/, a typed API client (openapi-fetch) generated from the backend's OpenAPI spec intosrc/lib/generated/api.ts, Tailwind 4 styling with brand utilities defined insrc/routes/layout.css, Paraglide i18n (de/en/es) compiled intosrc/lib/paraglide/, Vitest for unit + browser-mode component tests, and Playwright for E2E. Auth is cookie-based; SSR hooks insrc/hooks.server.tsinjectAuthorizationfromauth_tokenand gate non-public routes.2. Inventory
Routes (top-level)
//documents/documents/[id]/documents/[id]/edit/documents/new/documents/bulk-edit/persons/persons/[id]/persons/[id]/edit/persons/new/stammbaum/briefwechsel/aktivitaeten/geschichten/geschichten/[id]/geschichten/[id]/edit/geschichten/new/enrich/enrich/[id]/enrich/done/admin/admin/groups/admin/users/admin/tags/admin/ocr/admin/invites/admin/system/users/[id]/admin/users/[id]/profile/login/logout/register/forgot-password/reset-password/hilfe/hilfe/transkription/api/*/api/[...path]/api/documents/api/persons/api/tags/demo/demo/paraglidesv createlib/root filesapi.server.tserrors.tsErrorCodemirror + paraglide lookuptypes.tsutils.tsisoToGermanfromutils/date(60-byte stub)relativeTime.tssearch.tsperson-validation.tsrelationshipLabels.tsindex.ts// place files you want to import …Components currently in
lib/components/(root level — 79 files)The flat dir mixes ≥9 domains and 3 cross-cutting categories. Domain assignment per the canonical set:
BackButton,ConfirmDialog,DateInput,LanguageSwitcher,Pagination,SortDropdown,ThemeToggle,OverflowPillButton,OverflowPillDisplay,ProgressRing,ExpandableText,GroupDivider,HelpPopover,UnsavedWarningBanner,UploadSuccessBanner,DistributionBarMentionEditor,MentionDropdown,PersonMentionEditor,PersonMentionEditor.test-host,CommentMessage,CommentThreadPersonChip,PersonChipRow,PersonHoverCard,PersonMultiSelect,PersonTypeahead,PersonTypeBadge,PersonTypeSelector,RelationshipChip,RelationshipPill,AddRelationshipForm,StammbaumCard,StammbaumSidePanel,StammbaumTree,ContributorStackTagChipList,TagInput,TagParentPickerDocumentRow,DocumentThumbnail,DocumentTopBar,DocumentViewer,DocumentMetadataDrawer,DocumentMultiSelect,DocumentStatusChip,ConversationThumbnail,ThumbnailRow,ReadyColumn,SegmentationColumn,TranscriptionColumn,EnrichmentBlock,PdfViewer,PdfControls,FileSwitcherStrip(in document/)AnnotationLayer,AnnotationShape,AnnotationEditOverlayTranscriptionBlock,TranscriptionBlock.test-host,TranscriptionEditView,TranscriptionReadView,TranscriptionPanelHeader,TranscribeCoachEmptyState,TranscribeDragDemo,RichtlinienRuleCard,ScriptTypeSelectOcrTrigger,OcrProgress,OcrTrainingCard,SegmentationTrainingCard,TrainingHistoryNotificationBell,NotificationDropdownGeschichteEditor,GeschichtenCardMissionControlStrip,DashboardActivityFeed,DashboardFamilyPulse,DashboardNeedsMetadata,DashboardRecentDocuments,DashboardResumeStripSub-directories:
lib/components/document/lib/components/chronik/lib/components/user/Stores, hooks, utils, services, actions
lib/stores/bulkSelection.svelte.ts(document),notifications.svelte.ts(notification)lib/hooks/useBlockAutoSave,useBlockDragDrop,useFileLoader,usePdfRenderer,useTypeahead,useUnsavedWarninglib/services/confirm.svelte.ts+ test-hostlib/actions/clickOutside.ts,radioGroupNav.tslib/utils/date,debounce,sort,sanitize,notifications,requiredFields,validateFile,filename,time,documentStatusLabel,personFormat,personLifeDates,groupDocuments,comment,commentDeepLink,mention,mentionSerializer,transcriptionMarkers,extractText,blockConflictMerge,saveBlockWithConflictRetry,deepLinkScroll,hoverCardPosition,date-bucketslib/types/personHoverCard.ts,training.tslib/ocr/translateOcrProgress.tslib/server/locale.tsPage-local components co-located in
src/routes/(≥39 files)routes/AppNav.svelte,AuthHeader.svelte,UserMenu.svelte,DocumentList.svelte,DropZone.svelte,SearchFilterBar.svelte— shell components living next to the layoutroutes/admin/{EntityNav,EntityNavSection}.svelte,routes/admin/{groups,tags,users,ocr}/…— many*ListPanel.svelte,Tag*.svelte,OcrHealthBar.svelte, etc.routes/briefwechsel/{ConversationFilterBar,ConversationTimeline,Correspondent…,Correspondenz…,SinglePersonHintBar}.svelte(7 files)routes/persons/[id]/{PersonCard,PersonDocumentList,PersonRelationshipsCard,PersonMergePanel,CoCorrespondentsList,NameHistoryCard}.svelte+ edit subfolderroutes/profile/{PersonalInfoForm,PasswordChangeForm}.svelteThis co-location is a second, parallel organizational paradigm to
lib/components/— the codebase has not chosen one. (See §5.)3. Rubric scorecard
README.mdat repo root;frontend/README.md:1-39is the unmodifiedsv createtemplate (# sv… "If you're seeing this, you've probably already done this step. Congrats!")README.mdat repo root with one-paragraph product description; replacefrontend/README.mdstub (or rely onfrontend/CLAUDE.mdcontent moved to README). Overlap with AUDIT-5; flagging here per scope.frontend/README.md:1-39has nonedocs/ARCHITECTURE.mdwith diagramdocs/ARCHITECTURE.md;docs/architecture/c4-diagrams.mdexists but is not linked from any READMEARCHITECTURE.md.frontend/README.mdhas none of these;COLLABORATING.mdanddocs/exist but are not linkedfrontend/README.md.frontend/.svelte-kit.old/,.svelte-kit-backup/,test-results.locked/,proofshot-artifacts/(committed-or-tracked); 6 ×src/lib/paraglide_bak*/(~4 MB).gitignoreproperly.frontend/README.md:18-26saysnpm run devonly; no instructions to run backend/MinIO/DB;frontend/CLAUDE.md:142-150does point to rootdocker-compose up -dfrontend/README.mdhas none;frontend/CLAUDE.md:7-19lists Svelte 5, TS 5.9, Vite 7 (no Node version)@types/node) to README.frontend/README.mdnorfrontend/CLAUDE.mdmentionsadmin@familyarchive.local / admin123; defer to AUDIT-5frontend/e2e/CLAUDE.md:130-138has a small troubleshooting table; no frontend-wide sectionfrontend/README.mdexists but is the emptysvstub;frontend/e2e/CLAUDE.mdis good but is CLAUDE-marked, not human-markedfrontend/CLAUDE.mdcontent intofrontend/README.md.frontend/CLAUDE.md:38-56lists routes but does not name domains as bounded contextslib/<domain>/README.md(see §8).frontend/; tension is real (/users/[id]is a Person profile and/admin/users/[id]is an AppUser)docs/GLOSSARY.mdand link from frontend README. Critical for Anja & Tobias.lib/domain-based, names stack-symmetriclib/components/is a flat 79-file bucket spanning ≥9 domains; onlydocument/,chronik/,user/sub-dirs exist;lib/utils/mixes mention, transcription, document, person, file, sort, dates, etc. (24 files in one folder)shared/justifiedshared/does not exist yetlib/shared/exists; cross-cutting code is currently inlib/root or scatteredlib/shared/{ui,discussion,dashboard,error-handling,i18n}per D-FE-3/4.Person-touching code is in:lib/components/Person*.svelte(7 files),lib/components/Stammbaum*.svelte(3 files),lib/components/AddRelationshipForm.svelte,lib/utils/personFormat.ts,lib/utils/personLifeDates.ts,lib/person-validation.ts,lib/relationshipLabels.ts,lib/types/personHoverCard.ts,routes/persons/,routes/persons/[id]/Person*.svelte(page-local) — minimum 6 different parents to scanlib/person/per REFACTOR-2.TranscriptionBlock.svelte,TranscriptionEditView.svelte,TranscriptionReadView.svelte,TranscriptionPanelHeader.svelte,TranscriptionColumn.svelte,TranscribeCoachEmptyState.svelte,TranscribeDragDemo.svelte,RichtlinienRuleCard.svelte,ScriptTypeSelect.svelte,lib/utils/transcriptionMarkers.ts,lib/utils/blockConflictMerge.ts,lib/utils/saveBlockWithConflictRetry.ts,lib/hooks/useBlock*.svelte.ts— 13+ files, 5 different parentsdocument.transcription/*together.Helper/Utils/Managerwithout modifierlib/utils.ts(60-byte re-export) andlib/utils/exist; component names look meaningfullib/utils.ts; consider per-domain util grouping./users/[id](Person profile) vs/admin/users(AppUser admin) — names collide/users/[id]→/persons/[id](already exists) or merge; eliminate semantic overlap.frontend/CLAUDE.mdcovers patterns (API client, form actions, date handling, save bars) but not "how to add a new domain"; mostly tells the AI how, not a humanfrontend/CLAUDE.md:60-80); error handling usesparseBackendErrorANDgetErrorMessageAND rawresult.error as unknown as { code? }cast at every call site (e.g.routes/admin/+layout.server.ts:38-48repeats the cast 3×) — boilerplate begs a helperokOrThrow(result)helper.frontend/CLAUDE.mdis 198 lines of essential conventions; the human-facingfrontend/README.mdis the 39-linesvstublib/components/document/*cousin imports are local and correct (DocumentEditLayout.svelte:11-13);lib/components/document/WhoWhenSection.svelteimportsPersonTypeaheadfromlib/components/(cross-domain into person) — this is expected per D-FE-1, but with nolib/person/folder yet, the rule is unenforceable.lib/components/TranscriptionEditView.svelte:4importsOcrTrigger(document.transcription→ocr — needs justification once domains exist)lib/<domain>/exists.shared/shared/exists; cross-cutting code is sprinkled acrosslib/components/(e.g.BackButton,Pagination,LanguageSwitcher,ThemeToggle,ConfirmDialog,DateInput,HelpPopover) andlib/utils/,lib/services/,lib/actions/,lib/hooks/lib/shared/.lib/;lib/components/document/,chronik/,user/sub-dirs lack READMEsroutes/+layout.svelte:21-27justifiesuntrackfor bulk-selection effect,lib/components/StammbaumTree.svelte:2-3explains the eslint-disable). Many large components lack any why-comment —lib/components/StammbaumTree.sveltehas 30+ lines of layout magic numbers (NODE_W=160,MIN_VIEWBOX_W=1200) without rationale;lib/utils/blockConflictMerge.tsis non-trivial and lightly commentedask Marcel/Claude generated/TODO: figure out/non-obviousroutes/admin/+layout.server.ts:29(legitimate, names the future endpoint) andlib/components/chronik/ChronikRow.svelte:163(backend gap). Zero "ask Marcel"/"Claude generated"/"non-obvious" matches. Also:routes/api/tags/+server.ts:27has a strayconsole.log('Tags Data', data)(dev artifact)lib/api.server.ts:1-15documents the regen workflow;frontend/README.md:177-183coversnpm run generate:api; OpenAPI spec served by backendlib/generated/api.tsis generated and must not be edited (it is gitignored per.gitignore:30-32then re-added — confusing).lib/components/Pagination.svelte.spec.ts,lib/components/PersonTypeahead.svelte.spec.ts,routes/+page.server.spec.ts(8995 bytes) all assert on observable behaviour, not implementation;lib/utils/mention.spec.ts(14k) covers many edge cases. Defer to manual mutation pass before REFACTOR-2.Person*,TranscriptionBlock*,Annotation*,Document*,bulkSelection).frontend/e2e/:auth.spec.ts,documents.spec.ts,persons.spec.ts,transcription.spec.ts,annotations.spec.ts,geschichten.spec.ts,briefwechsel-*.spec.ts,bulk-edit.spec.ts,permissions.spec.ts,accessibility.spec.ts, etc. — all critical journeys coveredback-button.spec.ts,notification-deep-link.spec.ts,person-mention-read.spec.ts— names predict scopeplaywright.config.ts:22-24explicitly setsfullyParallel: false, workers: 1ande2e/CLAUDE.md:43-48confirms tests share auth state and must run sequentially. Vitest tests appear independentAPI_INTERNAL_URL,API_PROXY_TARGET,E2E_BASE_URL) are scattered acrosshooks.server.ts:47,vite.config.ts:18,playwright.config.ts:18,27; never listed in one placeOcrProgress.svelte(onlytranslateOcrProgressis imported, the .svelte file is orphaned),DocumentStatusChip.svelte(zero imports),ExpandableText.svelte(zero imports),DashboardRecentDocuments.svelte(only its own spec imports it).src/lib/index.tsis the empty// place files …placeholder.lib/utils.tsis a 60-byte re-export. 6 paraglide_bak* dirs (~4 MB) that the build does not use. 3 straytest-results/screenshots/dirs insidesrc/(src/routes/test-results/,src/routes/login/test-results/,src/lib/components/test-results/).frontend/.svelte-kit.old/,.svelte-kit-backup/,test-results.locked/.routes/demo/androutes/demo/paraglide/are leftovers fromsv createlib/components/StammbaumTree.svelte:19-27defines layout constants but inline; widely OK elsewhereconsole.loginroutes/api/tags/+server.ts:27. Noif (false)blocks.routes/users/[id]androutes/admin/users/[id]co-exist with overlapping semantics — feels in-flightresult.data!afterresponse.okcheck. Defensive?? null/?? []inroutes/+page.svelte:36-60is reasonable for SSR data4. Subsystem health summary
Applicable checks: 37 of 50 (excluding 8 N/A and 5 deferred-to-other-audits in C2.3 / C9.1). PASS rate: 6 / 37 ≈ 16 %. Five Critical findings.
Overall: 🔴 (fails the threshold of "0 Critical" required for either 🟡 or 🟢).
The verdict is dominated by C1 / C3 / C4 — the lack of a real README, a real domain doc, and a domain-organised
lib/. The code itself is largely clean (C6 / C8 / C10 sample fine); the legibility wrapper around the code is the gap.5. Domain mapping gaps — every flat
lib/components/fileEvery component currently in
lib/components/(root level) and its plausible target home. "Blocker question" only listed when non-trivial.shared/ui (admission-criteria-clean — no entity, no CRUD)
BackButton.sveltelib/shared/ui/ConfirmDialog.sveltelib/shared/ui/(paired withlib/services/confirm.svelte.ts)DateInput.sveltelib/shared/ui/LanguageSwitcher.sveltelib/shared/i18n/Pagination.sveltelib/shared/ui/SortDropdown.sveltelib/shared/ui/ThemeToggle.sveltelib/shared/ui/OverflowPillButton.svelteOverflowPillDisplay.sveltelib/shared/ui/ProgressRing.sveltelib/shared/ui/ExpandableText.sveltelib/shared/ui/GroupDivider.sveltelib/shared/ui/orlib/document/EnrichmentBlockHelpPopover.sveltelib/shared/ui/UnsavedWarningBanner.sveltelib/shared/ui/UploadSuccessBanner.sveltelib/document/(only used post-upload)DistributionBar.sveltelib/shared/dashboard/shared/discussion (D-FE-3)
MentionEditor.svelte,MentionDropdown.sveltelib/shared/discussion/PersonMentionEditor.svelte+.test-host.sveltelib/shared/discussion/(orlib/person/?) — blocker: is "person mention" a person concept or a discussion concept?CommentMessage.svelte,CommentThread.sveltelib/shared/discussion/person (D-FE-1)
PersonChip.svelte,PersonChipRow.sveltelib/person/PersonHoverCard.sveltelib/person/PersonMultiSelect.svelte,PersonTypeahead.sveltelib/person/PersonTypeBadge.svelte,PersonTypeSelector.sveltelib/person/RelationshipChip.svelte,RelationshipPill.sveltelib/person/relationship/AddRelationshipForm.sveltelib/person/relationship/StammbaumCard.svelte,StammbaumSidePanel.svelte,StammbaumTree.sveltelib/person/relationship/ContributorStack.sveltelib/person/(avatar stack of contributors)tag (D-FE-2)
TagChipList.svelte,TagInput.svelte,TagParentPicker.sveltelib/tag/document
DocumentRow.svelte,DocumentThumbnail.svelte,DocumentTopBar.svelte,DocumentViewer.sveltelib/document/DocumentMetadataDrawer.svelte,DocumentMultiSelect.sveltelib/document/DocumentMetadataDrawerzero-import — verify before moveDocumentStatusChip.sveltelib/document/ConversationThumbnail.svelte,ThumbnailRow.sveltelib/document/(or conversation derived view?)ReadyColumn.svelte,SegmentationColumn.svelte,TranscriptionColumn.sveltelib/document/(mission-control board columns)EnrichmentBlock.sveltelib/document/PdfViewer.svelte,PdfControls.sveltelib/document/(or shared/ui if reused for non-document PDFs — none currently)document.annotation
AnnotationLayer.svelte,AnnotationShape.svelte,AnnotationEditOverlay.sveltelib/document/annotation/document.transcription
TranscriptionBlock.svelte(+.test-host.svelte),TranscriptionEditView.svelte,TranscriptionReadView.svelte,TranscriptionPanelHeader.sveltelib/document/transcription/TranscribeCoachEmptyState.svelte,TranscribeDragDemo.sveltelib/document/transcription/RichtlinienRuleCard.svelte,ScriptTypeSelect.sveltelib/document/transcription/ocr
OcrTrigger.svelte,OcrTrainingCard.svelte,SegmentationTrainingCard.svelte,TrainingHistory.sveltelib/ocr/OcrProgress.sveltelib/ocr/translateOcrProgressutil is used; the component is not.notification
NotificationBell.svelte,NotificationDropdown.sveltelib/notification/geschichte
GeschichteEditor.svelte,GeschichtenCard.sveltelib/geschichte/shared/dashboard (D-FE-4)
MissionControlStrip.svelte,DashboardActivityFeed.svelte,DashboardFamilyPulse.svelte,DashboardResumeStrip.svelte,DashboardNeedsMetadata.sveltelib/shared/dashboard/DashboardRecentDocuments.sveltePage-local components co-located in
routes/(parallel paradigm)The 39+
*.sveltefiles undersrc/routes/**/(not+page.svelte/+layout.svelte) form a second organizational paradigm that competes withlib/components/. Examples:routes/AppNav.svelte,routes/briefwechsel/Conversation*.svelte,routes/persons/[id]/Person*.svelte,routes/admin/users/UsersListPanel.svelte,routes/profile/PasswordChangeForm.svelte. Blocker question: are these page-locals (legitimate co-location, leave alone) or should everything live underlib/<domain>/? REFACTOR-2 must answer this before moving anything.6. Cross-cutting candidates for
lib/shared/Each item below satisfies the admission criteria: (a) no entity, (b) no user-facing CRUD, (c) ≥2 consumers OR framework infrastructure.
BackButton.svelteConfirmDialog.svelte+lib/services/confirm.svelte.tsPagination.svelte,SortDropdown.svelte,DateInput.svelte,OverflowPill*.svelte,ProgressRing.svelte,HelpPopover.svelte,UnsavedWarningBanner.svelteLanguageSwitcher.svelte,ThemeToggle.sveltelib/api.server.ts+page.server.tslib/errors.tslib/server/locale.ts,lib/relativeTime.ts,lib/utils/date.tslib/utils/debounce.ts,lib/utils/sort.ts,lib/utils/sanitize.ts,lib/utils/extractText.tslib/actions/clickOutside.ts,lib/actions/radioGroupNav.tslib/services/confirm.svelte.tsMentionEditor.svelte,MentionDropdown.svelte,lib/utils/mention.ts,lib/utils/mentionSerializer.ts,lib/utils/comment.ts,lib/utils/commentDeepLink.tsMissionControlStrip.svelte,Dashboard*.svelte,DistributionBar.svelteItems that should NOT go to
shared/:PersonTypeahead,PersonMultiSelect,PersonChip*,PersonHoverCard— bound toPersonentity (D-FE-1: "cross-domain consumption is normal"), belong tolib/person/.TagInput,TagChipList,TagParentPicker— bound toTagentity (D-FE-2), belong tolib/tag/.EnrichmentBlock, allDocument*— bound toDocumententity.7. Dead/suspicious code register
frontend/src/lib/components/OcrProgress.sveltelib/ocr/translateOcrProgress.tsutil isfrontend/src/lib/components/DocumentStatusChip.sveltefrontend/src/lib/components/ExpandableText.sveltefrontend/src/lib/components/DashboardRecentDocuments.svelte.spec.tsreferences itfrontend/src/lib/index.ts(line 1)// place files you want to import …frontend/src/lib/utils.ts(line 1)isoToGerman, germanToIsofromutils/date— useless redirection$lib/utils/datefrontend/src/lib/components/__mocks__/navigatingStore.ts(105 bytes)src/lib/__mocks__/or co-locate with the consuming specfrontend/src/routes/demo/,frontend/src/routes/demo/paraglide/sv createscaffold leftover, surfaces as/demoroutesfrontend/src/routes/api/tags/+server.ts:22, 27, 32console.errorand oneconsole.log('Tags Data', data)(dev artifact)console.log; replaceconsole.errorwith proper error handling or acceptfrontend/src/routes/admin/+layout.server.ts:29-30/api/admin/statsfrontend/src/lib/components/chronik/ChronikRow.svelte:163frontend/src/routes/users/[id]/+page.svelte/admin/users/[id](one is Person profile, one is AppUser admin) — confuses Person ≠ AppUserfrontend/.svelte-kit.old/(24 KB)eslint.config.js:15) but it's still on diskfrontend/.svelte-kit-backup/(32 KB)frontend/test-results.locked/(20 KB)frontend/proofshot-artifacts/(68 KB).gitignoreproofshot-artifacts/) but present on diskfrontend/src/lib/paraglide_bak/,paraglide_bak2/,paraglide_bak3/,paraglide_bak4/,paraglide_bak_b1_chown_pending/,paraglide_bak_now/(≈4 MB total)paraglide_bak*but pollute the source tree and confuse readersfrontend/src/routes/test-results/screenshots//test-resultsroute to a readerfrontend/test-results/and gitignorefrontend/src/routes/login/test-results/screenshots/frontend/src/lib/components/test-results/screenshots/lib/components/frontend/README.md:1-39# svtemplate fromnpx sv create("If you're seeing this, you've probably already done this step. Congrats!")frontend/src/lib/types.ts:38DocumentPanelTab = 'metadata' | 'transcription' | 'discussion' | 'history'and other types are mixed-domainfrontend/src/lib/components/PersonMentionEditor.test-host.svelte,TranscriptionBlock.test-host.svelte,lib/services/confirm.test-host.svelte*.test-host.svelteand exclude — or move to__tests__/Suspicious-but-not-dead (keep, but note):
frontend/src/lib/components/StammbaumTree.svelte:2-3has a file-leveleslint-disable svelte/prefer-svelte-reactivity— justified inline, OK.frontend/src/routes/AppNav.svelte:143-147has 3svelte-ignorecomments for a11y — overlay backdrop click; acceptable but worth a Skip-link audit.8. Documentation gaps
frontend/. The 39-line# svstub atfrontend/README.mdmust be replaced. The substance currently lives infrontend/CLAUDE.md(198 lines: stack, project structure, API client pattern, form actions, date handling, styling, key components, run instructions, vite proxy, i18n) — every section there belongs in a human-facing README per C5.3.lib/. Once REFACTOR-2 createslib/<domain>/directories, each needs a 1-paragraph "what it owns / does NOT own" file. Especially urgent for:person/(vs AppUser),document/transcription/(vs OCR),shared/discussion/(the comment+mention split).Person(historical) vsAppUser(login account),Geschichte(story),Briefwechsel(correspondence),Chronik(activity feed),Stammbaum(family tree),Richtlinien(transcription guidelines),Aktivitäten— bilingual terms confuse non-German speakers, even those who can read code.lib/generated/api.ts(137 KB) is generated from the backend OpenAPI spec; thefrontend/CLAUDE.md:177-183documentsnpm run generate:api, but the file header inlib/generated/api.tsshould warn "DO NOT EDIT — regenerate vianpm run generate:api" and the regen requires backend running with--spring.profiles.active=dev(mentioned only in CLAUDE.md). The.gitignore:30-32situation (# src/lib/generated/api.tscommented out) is confusing.API_INTERNAL_URL,API_PROXY_TARGET,E2E_BASE_URL,CIare referenced inhooks.server.ts:47,vite.config.ts:18,playwright.config.ts:18,playwright.config.ts:23— never listed together.errors.tscode, how to wire a new API endpoint into the typed client. Anja and Tobias will have to grep./home/marcel/Desktop/familienarchiv/CLAUDE.md:218documentsconversations/route; the actual path isbriefwechsel/. This is exactly the "click live nav, not URLs from docs" risk previously logged.DocumentStatuslifecycle on the frontend side, thebulkSelectionclear-on-route-change behaviour (good comment in+layout.svelte:21-27, but the store itself is uncommented), or thehandleFetchclone-and-rewrite dance inhooks.server.ts:91-101.9. Prerequisites for big-bang refactor (REFACTOR-2 / #408)
Before any
lib/reorganisation:Person*.svelte.spec.ts,Tag*.svelte.spec.ts,Document*.svelte.spec.ts,Transcription*.svelte.{spec,test}.ts,Annotation*.svelte.{spec,test}.ts,bulkSelection.svelte.spec.ts,notifications.svelte.spec.ts,lib/utils/mention.spec.ts,lib/utils/blockConflictMerge.spec.ts,lib/utils/saveBlockWithConflictRetry.spec.ts. Use Stryker or hand-mutate one assertion per file as a smoke check.lib/paradigm. Decide whether components used by exactly one page (the 39+ files currently insideroutes/) stay co-located or move tolib/<domain>/. Without this rule, the refactor will be inconsistent.PersonMentionEditor(person vs shared/discussion),EnrichmentBlock(document vs shared/dashboard),DistributionBar(shared/ui vs shared/dashboard),ConversationThumbnail(document vs conversation derived view),lib/types.ts(split or keep).$lib/<domain>/<File>.svelte. SvelteKit's$libalias points tosrc/lib/— no extra config needed, but verifytsconfig.jsonandeslint.config.jscope with new sub-folders.lib/components/bucket during the refactor window. Add a doc-only rule and a CI check (grep -E '\$lib/components/[^/]+\.svelte'should return zero in new diffs after REFACTOR-2 lands)./users/[id]vs/admin/users/[id]semantic overlap. Don't move user-domain components while two user routes still bleed into each other (Person ≠ AppUser).lib/shared/with at least one resident as a baseline before moving everything.10. Top 5 prioritized recommendations
frontend/README.mdwith a real human-facing README built from the contents offrontend/CLAUDE.md(and add Anja-readable sections: domains, env vars, glossary entries, "how to add an X"). This single change resolves three Critical findings (C1.1, C2.5, C3.1) and unblocks everything else. Also write a top-level repoREADME.mdper AUDIT-5 scope.lib/components/intolib/<domain>/{component,store,util,hook,type}per the canonical set (REFACTOR-2). Until this happens, any "find me the Person code" question fails. Use the §5 mapping verbatim; createlib/shared/{ui,discussion,dashboard,i18n}as the cross-cutting bucket.paraglide_bak*, the 4 dead components,frontend/src/lib/index.ts,frontend/src/lib/utils.ts, the 3 straytest-results/screenshots/dirs insidesrc/, thefrontend/.svelte-kit.old/,routes/demo/, the strayconsole.log, the two stale TODOs (filed as Gitea issues). Reviewing a refactor diff is much harder when half the moved files are dead.docs/GLOSSARY.mdwith the bilingual + Person ≠ AppUser distinctions and link it from both rootREADME.mdandfrontend/README.md. Tobias will not get pastBriefwechsel,Chronik,Stammbaum,Richtlinien,Aktivitäten,Geschichtewithout it; Anja will not get pastPerson≠AppUserwithout it. Cheap, high-leverage, unblocks C3.3 (Critical).Report generated under AUDIT-1, scope per #388, references #387 first comment. Read-only audit; no code modified.