From c3d4762ca08c1d4ff018e020748de2e4bb2e55ae Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 6 May 2026 21:33:30 +0200 Subject: [PATCH] docs(c4): add L3 frontend 3a middleware/auth and 3b document workflows --- .../c4/l3-frontend-3a-middleware-auth.puml | 29 ++++++++++++++ .../c4/l3-frontend-3b-document-workflows.puml | 38 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 docs/architecture/c4/l3-frontend-3a-middleware-auth.puml create mode 100644 docs/architecture/c4/l3-frontend-3b-document-workflows.puml diff --git a/docs/architecture/c4/l3-frontend-3a-middleware-auth.puml b/docs/architecture/c4/l3-frontend-3a-middleware-auth.puml new file mode 100644 index 00000000..e02df734 --- /dev/null +++ b/docs/architecture/c4/l3-frontend-3a-middleware-auth.puml @@ -0,0 +1,29 @@ +@startuml +!include + +title Component Diagram: Web Frontend — Middleware, Auth & Layout + +Person(user, "User") +Container(backend, "API Backend", "Spring Boot") + +System_Boundary(frontend, "Web Frontend (SvelteKit / SSR)") { + Component(hooks, "hooks.server.ts", "SvelteKit Server Hook", "Four handle layers: (1) handleAuth — redirects unauthenticated users to /login; (2) userGroup — reads auth_token cookie, fetches /api/users/me, stores user in event.locals; (3) handleFetch — injects Authorization header on all outgoing /api/ calls; (4) handleLocaleDetection — sets language cookie from Accept-Language header.") + Component(i18n, "hooks.ts (Paraglide)", "SvelteKit Client Hook", "Client-side i18n middleware. Detects language from URL and sets the active locale for Paraglide.js translation functions.") + Component(layout, "+layout.server.ts", "SvelteKit Layout Loader", "Passes event.locals.user down to all child pages so every route has access to the authenticated user.") + Component(loginPage, "/login", "SvelteKit Route", "Form action: encodes email:password as Base64 Basic Auth token, POSTs to /api/users/me to validate, sets auth_token httpOnly cookie (SameSite=strict, maxAge=86400), redirects to /.") + Component(logoutPage, "/logout", "SvelteKit Route (server-only)", "Clears the auth_token cookie and redirects to /login.") + Component(registerPage, "/register", "SvelteKit Route", "Loader validates invite code via GET /api/auth/invite/{code}. Form action: POST /api/auth/register to create the user account.") + Component(forgotPw, "/forgot-password", "SvelteKit Route", "Form action: POST /api/auth/forgot-password. Always responds with success to prevent email enumeration.") + Component(resetPw, "/reset-password", "SvelteKit Route", "Form action: POST /api/auth/reset-password with the token from the query string.") +} + +Rel(user, hooks, "Every browser request", "HTTPS") +Rel(hooks, backend, "GET /api/users/me (session check)", "HTTP / Basic Auth") +Rel(hooks, loginPage, "Redirect if no token") +Rel(hooks, layout, "Stores authenticated user in event.locals") +Rel(loginPage, backend, "POST /api/users/me (auth check)", "HTTP / Basic Auth") +Rel(registerPage, backend, "GET /api/auth/invite/{code}, POST /api/auth/register", "HTTP / JSON") +Rel(forgotPw, backend, "POST /api/auth/forgot-password", "HTTP / JSON") +Rel(resetPw, backend, "POST /api/auth/reset-password", "HTTP / JSON") + +@enduml diff --git a/docs/architecture/c4/l3-frontend-3b-document-workflows.puml b/docs/architecture/c4/l3-frontend-3b-document-workflows.puml new file mode 100644 index 00000000..7ba2bb1e --- /dev/null +++ b/docs/architecture/c4/l3-frontend-3b-document-workflows.puml @@ -0,0 +1,38 @@ +@startuml +!include + +title Component Diagram: Web Frontend — Document Workflows + +Person(user, "User") +Container(backend, "API Backend", "Spring Boot") + +System_Boundary(frontend, "Web Frontend (SvelteKit / SSR)") { + Component(homePage, "/ (Home / Search)", "SvelteKit Route", "Loader: parses URL params (q, from, to, senderId, receiverId, tags), fetches /api/documents/search and /api/persons. Renders search form with full-text, date range, sender/receiver typeahead, and tag filters.") + Component(docDetail, "/documents/[id]", "SvelteKit Route", "Loader: GET /api/documents/{id}. Page: metadata panel, inline file viewer, transcription editor, annotation layer, and comment thread.") + Component(docEdit, "/documents/[id]/edit", "SvelteKit Route", "Edit form with PersonTypeahead, TagInput, date/location fields. Form action: PUT /api/documents/{id}.") + Component(docNew, "/documents/new", "SvelteKit Route", "Upload form for a new document. Loader: GET /api/persons. Form action: POST /api/documents with multipart file.") + Component(docBulkEdit, "/documents/bulk-edit", "SvelteKit Route", "Multi-document metadata editor. Loader: GET /api/documents/incomplete. Requires WRITE_ALL (redirects otherwise). Action: PATCH /api/documents/bulk.") + Component(enrichPage, "/enrich/[id]", "SvelteKit Route", "Guided enrichment workflow. Loader: GET /api/documents/{id}. Progressively saves annotations and transcription blocks.") + Component(apiPersons, "/api/persons (SvelteKit API)", "SvelteKit Server Route", "Proxies GET /api/persons?q=... to backend for PersonTypeahead suggestions.") + Component(apiTags, "/api/tags (SvelteKit API)", "SvelteKit Server Route", "Proxies GET /api/tags to backend for TagInput autocomplete.") + Component(typeahead, "PersonTypeahead.svelte", "Svelte Component", "Async autocomplete for selecting a person. Debounces input, calls /api/persons?q=.") + Component(tagInput, "TagInput.svelte", "Svelte Component", "Multi-tag input. Supports free-text entry and selecting existing tags from /api/tags.") +} + +Rel(user, homePage, "Searches and browses", "HTTPS / Browser") +Rel(homePage, backend, "GET /api/documents/search, GET /api/persons", "HTTP / JSON") +Rel(docDetail, backend, "GET /api/documents/{id}, GET /api/documents/{id}/file", "HTTP / JSON + Binary") +Rel(docEdit, backend, "PUT /api/documents/{id}", "HTTP / Multipart") +Rel(docNew, backend, "GET /api/persons, POST /api/documents", "HTTP / JSON + Multipart") +Rel(docBulkEdit, backend, "GET /api/documents/incomplete, PATCH /api/documents/bulk", "HTTP / JSON") +Rel(enrichPage, backend, "GET/POST /api/transcription, POST /api/documents/{id}/annotations", "HTTP / JSON") +Rel(homePage, typeahead, "Uses for sender/receiver filter") +Rel(docEdit, typeahead, "Uses for sender/receiver selection") +Rel(docNew, typeahead, "Uses for sender selection") +Rel(docEdit, tagInput, "Uses for tag management") +Rel(typeahead, apiPersons, "Fetches suggestions", "HTTP") +Rel(tagInput, apiTags, "Fetches existing tags", "HTTP") +Rel(apiPersons, backend, "GET /api/persons", "HTTP / JSON") +Rel(apiTags, backend, "GET /api/tags", "HTTP / JSON") + +@enduml