From f7747ba352ca820964845f4ae7dc946c60cd88bb Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 18 Apr 2026 19:24:06 +0200 Subject: [PATCH] docs(spec): add register page design spec Captures the centered-card registration design 1:1 from the claude.ai/design export. Covers all 10 sections: desktop overview, header, above-card copy, form fields, password states, notification card, submit button, success panel, mobile layout, and i18n/a11y/backend implementation notes. Relates to #269 Co-Authored-By: Claude Sonnet 4.6 --- docs/specs/register-page-spec.html | 1371 ++++++++++++++++++++++++++++ 1 file changed, 1371 insertions(+) create mode 100644 docs/specs/register-page-spec.html diff --git a/docs/specs/register-page-spec.html b/docs/specs/register-page-spec.html new file mode 100644 index 00000000..a8a883b9 --- /dev/null +++ b/docs/specs/register-page-spec.html @@ -0,0 +1,1371 @@ + + + + + +Register Page · Final Design Spec · Familienarchiv + + + +
+ + +
+
+
+

Register Page · Final Design Spec

+

Centered-card variant (Variant A). Friendly, inviting registration form for Familienarchiv — a collaborative archive of family letters from the 19th and 20th centuries. Designed for a dual audience (60+ and 25–42), with large 17px serif inputs, du-Anrede (informal you), German-first with DE/EN/ES toggle, live password-match feedback, mention-notification opt-in, and a post-submit success panel.

+
+ Final · Ready for implementation +
+
+
+
Variant
+
A — Centered card · 640px white card on sand canvas
+
+
+
Fields
+
Vorname · Nachname · E-Mail · Passwort · Passwort bestätigen · Benachrichtigungen
+
+
+
Languages
+
DE (default) / EN / ES — header toggle; swaps all labels, hints, and validation messages live
+
+
+
Audience
+
60+ primary (48px touch targets, 17px serif, calm layout) · 25–42 secondary
+
+
+
+ + +
+ 📐 Mockup scale notice — all font-size, height, and padding values + in the mockup CSS are scaled to ~55% of actual implementation values. + Do not copy sizes from mockup CSS. Use the ⚙ Implementation + Reference tables after each section. +
+ + + +
+
+ 1 + Full page — desktop (1280px) +
+ +
+ Default — form at rest, German language +
+
+
+
+
localhost:3000/register
+
+
+
+
+
+ Familienarchiv +
+ + + +
+
+
+
+
+
+
Ein Familienprojekt
+
Schön, dass du da bist.
+
Bereits 1.500 Briefe aus vielen Jahrzehnten sind im Archiv. Mit deinem Konto hilfst du mit, sie zu lesen, zu ordnen und für die nächsten Generationen zu bewahren.
+
+
+
+ +
+
Über dich
+
+
+
Vorname
+ +
+
+
Nachname
+ +
+
+
+ +
+
Konto
+
+
+
E-Mail-Adresse
+ +
+
+
Passwort
+
+ + +
+
Mindestens 8 Zeichen.
+
+
+
Passwort bestätigen
+
+ + +
+
+
+
+ +
+
Benachrichtigungen
+
+
+ + + +
+
+
Benachrichtige mich,
+
wenn jemand mich in einem Kommentar erwähnt oder mir auf einen Kommentar antwortet.
+
+
+
+
+ + +
+
+
+
+
+
+
+ +
+
Implementation Reference — Page structureroutes/register/+page.svelte
+ + + + + + +
ElementTailwind classesReal pxNotes
Page wrapperflex min-h-screen flex-col bg-canvasSame pattern as login page
Main centering wrapperflex flex-1 justify-center items-start px-8 pt-1664px top paddingItems start (not center) so tall forms don't overflow
Content columnw-full max-w-[640px]640px maxFixed max-width card column
Form cardbg-surface border border-line rounded-sm shadow-sm p-1040px paddingrounded-sm = 2px; shadow-sm = 0 1px 2px rgb(0 0 0/.05)
+
+
+ + + +
+
+ 2 + Header — anatomy & language toggle states +
+ +
+ + +
+ DE active (default) +
+
+
+
+
localhost:3000/register
+
+
+
+
+ Familienarchiv +
+ + + +
+
+
+
+
+
Active language: mint underline + white text. Inactive: 55% opacity.
+
+ + +
+ EN active +
+
+
+
+
localhost:3000/register?lang=en
+
+
+
+
+ Familienarchiv +
+ + + +
+
+
+
+
+
Toggle switches all copy live (no page reload). All labels, hints, and validation messages switch language.
+
+ + +
+ ES active +
+
+
+
+
localhost:3000/register?lang=es
+
+
+
+
+ Familienarchiv +
+ + + +
+
+
+
+
+
+
+ +
+
Implementation Reference — Headerroutes/AuthHeader.svelte (extend) or new RegisterHeader.svelte
+ + + + + + + + + +
ElementTailwind classesReal pxNotes
Header wrappersticky top-0 z-50 bg-[#012851]Same as authenticated header but no nav links (unauthenticated page)
Mint accent stripeh-1 bg-accent4px--c-accent: #a1dcd8. Always at the very top of the header.
Nav barh-16 flex items-center px-864px tall, 32px side paddingMax-width container inside: max-w-screen-xl mx-auto w-full
Wordmarkfont-sans text-xl font-bold tracking-[.15em] text-white uppercase20pxNot a link on the register page (user is not yet logged in)
Lang toggle containerml-auto flex items-center gap-14px gap
Lang button — inactivefont-sans text-xs font-bold tracking-[.12em] uppercase text-white/55 px-2.5 py-1.5 border-b-2 border-transparent transition-colors hover:text-white12px, padding 6px 10pxTouch target: 12+6+6 = 24px tall, acceptable for a header toggle since it's not a primary action
Lang button — activetext-white border-b-2 border-accentMint underline border
+
+
+ + + +
+
+ 3 + Above-card — eyebrow, headline, subtext +
+ +
+ + +
+ German (DE) +
+
+
+
Ein Familienprojekt
+
Schön, dass du da bist.
+
Bereits 1.500 Briefe aus vielen Jahrzehnten sind im Archiv. Mit deinem Konto hilfst du mit, sie zu lesen, zu ordnen und für die nächsten Generationen zu bewahren.
+
+
+
+
+ + +
+ English (EN) +
+
+
+
A family project
+
Glad to have you here.
+
Already 1,500 letters from many decades are in the archive. Your account helps read them, organise them, and keep them safe for the next generations.
+
+
+
+
+ + +
+ Spanish (ES) +
+
+
+
Un proyecto familiar
+
Qué bien tenerte aquí.
+
Ya hay 1.500 cartas de muchas décadas en el archivo. Con tu cuenta ayudas a leerlas, organizarlas y conservarlas para las próximas generaciones.
+
+
+
+
+ +
+ +
+
Implementation Reference — Above-cardroutes/register/+page.svelte
+ + + + + + +
ElementTailwind classesReal pxNotes
Above-card wrappertext-center mb-936px bottom margin
Eyebrow labelinline-block font-sans text-[11px] font-bold tracking-[.22em] uppercase text-ink-2 border-t border-b border-[#d4d2c5] px-3.5 py-1.5 mb-[18px]11px / padding 6px 14pxi18n key: m.register_eyebrow()
Headlinefont-serif font-normal text-[46px] leading-[1.12] tracking-[-0.005em] text-ink mb-446pxi18n key: m.register_headline(). Tinos (serif), not bold — weight 400.
Subtextfont-serif text-lg leading-relaxed text-ink-2 max-w-[540px] mx-auto18px, max-width 540pxi18n key: m.register_sub(). text-wrap: pretty via inline style for better line breaks.
+
+
+ + + +
+
+ 4 + Form section — Über dich (name fields) +
+ +
+ + +
+ Empty +
+
+
Über dich
+
+
+
Vorname
+ +
+
+
Nachname
+ +
+
+
+
+
+ + +
+ Focused — Vorname +
+
+
Über dich
+
+
+
Vorname
+ +
+
+
Nachname
+ +
+
+
+
+
Focus: navy border + soft navy glow ring.
+
+ + +
+ Filled +
+
+
Über dich
+
+
+
Vorname
+ +
+
+
Nachname
+ +
+
+
+
+
+ + +
+ Error — submitted empty +
+
+
Über dich
+
+
+
Vorname
+ +
+
+
Nachname
+ +
+
+
+
+
Red border only — no text error for empty name fields (border color communicates invalid state on submit).
+
+ +
+ +
+
Implementation Reference — Name fieldsroutes/register/+page.svelte
+ + + + + + + + + + + +
ElementTailwind classesReal pxNotes
Section caption wrapperflex items-center gap-3 mb-1Gap 12px between text and rule line
Section caption textfont-sans text-[11px] font-bold tracking-[.18em] uppercase text-ink whitespace-nowrap11pxi18n key: m.register_section_about()
Section caption ruleflex-1 h-px bg-line1px
2-column name gridgrid grid-cols-2 gap-4 mt-416px gap, 16px top marginOn mobile (<480px): grid-cols-1
Field wrapperflex flex-col
Field labelblock font-sans text-xs font-bold tracking-[.1em] uppercase text-ink-2 mb-212px, 8px bottom margini18n keys: m.register_first_name(), m.register_last_name()
Text input — defaultw-full border border-line bg-surface font-serif text-[17px] text-ink placeholder:text-ink-3 px-4 py-[14px] rounded-none outline-none focus-visible:ring-2 focus-visible:ring-focus-ring/15 focus-visible:border-ink transition-colors17px font / 48px tall (14+14+17+1px borders)No border-radius (Tailwind's rounded-none keeps it at 2px via border-radius:2px from global reset — or use rounded-sm)
Text input — invalid+ border-danger focus-visible:ring-danger/20Applied when submitted && !field.trim()
Placeholdersplaceholder:text-ink-3DE: "z.B. Frieda" / "z.B. Lehmann" · EN: "e.g. Frieda" / "e.g. Lehmann"
+
+
+ + + +
+
+ 5 + Form section — Konto (e-mail & passwords) +
+ +
+ + +
+ Default — empty +
+
+
Konto
+
+
+
E-Mail-Adresse
+ +
+
+
Passwort
+
+ + +
+
Mindestens 8 Zeichen.
+
+
+
Passwort bestätigen
+
+ + +
+
+
+
+
+
+ + +
+ Password valid + passwords match +
+
+
Konto
+
+
+
E-Mail-Adresse
+ +
+
+
Passwort
+
+ + +
+
Mindestens 8 Zeichen. ✓
+
+
+
Passwort bestätigen
+
+ + +
+
Passwörter stimmen überein.
+
+
+
+
+
Green dot + green text when passwords match. Show button label changes to "Verbergen".
+
+ + +
+ Password mismatch +
+
+
Konto
+
+
+
E-Mail-Adresse
+ +
+
+
Passwort
+
+ + +
+
Mindestens 8 Zeichen. ✓
+
+
+
Passwort bestätigen
+
+ + +
+
Die beiden Passwörter stimmen noch nicht überein.
+
+
+
+
+
Red border on confirm field + red error text. No dot icon for errors.
+
+ +
+ +
+
Implementation Reference — Konto fieldsroutes/register/+page.svelte
+ + + + + + + + + + +
ElementTailwind classesReal pxNotes
Email inputw-full border border-line bg-surface font-serif text-[17px] text-ink placeholder:text-ink-3 px-4 py-[14px] rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-focus-ring/15 focus-visible:border-ink transition-colors17px font / 48px talltype="email", autocomplete="email"
Password input wrapperrelativeContains input + show/hide button
Password inputSame as email input + pr-[92px]92px right padding to clear show/hide btntype="password" toggles to type="text" on show
Show/hide buttonabsolute right-0 inset-y-0 px-3.5 font-sans text-[11px] font-bold tracking-[.1em] uppercase text-ink-2 border-l border-line hover:text-ink transition-colors11px fonttype="button" (prevent form submit). Label: m.password_show() / m.password_hide()
Hint text — neutralfont-sans text-[13px] text-ink-3 mt-1.513px, 6px top margini18n key: m.register_pw_hint() ("Mindestens 8 Zeichen.")
Hint text — success (match)font-sans text-[13px] text-[#0a6b56] mt-1.5 flex items-center gap-1.5Shown when pw.length > 0 && pw === pw2. Dot: w-2 h-2 rounded-full bg-turquoise inline-block
Hint text — error (mismatch)font-sans text-[13px] text-danger mt-1.5Shown when pw2.length > 0 && pw !== pw2. i18n key: m.register_pw_match_no()
Validation logicpwValid: length ≥ 8. pwMatch: pw === pw2 && pw.length > 0. pwMismatch: pw2.length > 0 && pw !== pw2. Errors only shown after first submit attempt or onBlur.
+
+
+ + + +
+
+ 6 + Notification preference — CheckOption card +
+ +
+ + +
+ Unchecked +
+
+
Benachrichtigungen
+
+
+
+
+
Benachrichtige mich,
+
wenn jemand mich in einem Kommentar erwähnt oder mir auf einen Kommentar antwortet.
+
+
+
+
+
+
Border: sand (#e4e2d7). Background: white. Checkbox: gray border, white fill.
+
+ + +
+ Checked (default state) +
+
+
Benachrichtigungen
+
+
+
+ + + +
+
+
Benachrichtige mich,
+
wenn jemand mich in einem Kommentar erwähnt oder mir auf einen Kommentar antwortet.
+
+
+
+
+
+
Default state: checked (opt-in by default). Border: navy. Background: mint tint (rgba(161,220,216,.18)).
+
+ +
+ +
+
Implementation Reference — CheckOption cardroutes/register/+page.svelte
+ + + + + + + + + + + + +
ElementTailwind classes / valuesReal pxNotes
Card wrapper (label)<label> with flex gap-3.5 p-3.5 border rounded-sm cursor-pointer transition-colors items-start14px gap, 14px 16px paddingThe entire card is a <label> for large click target. Wrap real <input type="checkbox"> visually hidden inside.
Card — uncheckedborder-line bg-surface
Card — checkedborder-ink bg-[rgba(161,220,216,0.18)]Mint tint bg. No Tailwind utility exists — use inline style or arbitrary value.
Real checkbox inputsr-only (visually hidden, accessible)Bind checked state to this. Default: true.
Custom checkbox boxflex-shrink-0 w-[22px] h-[22px] rounded-sm border-2 flex items-center justify-center mt-px transition-all22×22pxMin touch target met by the card itself.
Checkbox — uncheckedborder-gray-400 bg-surface
Checkbox — checkedborder-ink bg-inkWhite checkmark SVG inside.
Checkmark SVG14×14px, path: M3 8.5l3.2 3.2L13 5, stroke white 2.4, round caps14px iconOnly rendered when checked.
Option titlefont-sans text-sm font-semibold text-ink14pxi18n key: m.register_notify_label()
Option descriptionfont-serif text-[15px] leading-normal text-ink-2 mt-0.515pxi18n key: m.register_notify_desc()
+
+
+ + + +
+
+ 7 + Submit button & footer links +
+ +
+ + +
+ Default +
+
+ + +
+
+
+ + +
+ Submit — hover +
+
+ + +
+
+
Bg darkens: #012851 → #01386f. No scale transform.
+
+ + +
+ Loading (after submit) +
+
+ + +
+
+
Arrow icon replaced by spinner. Button opacity 0.85. cursor: wait. 850ms simulated delay then success.
+
+ +
+ +
+
Implementation Reference — Submit & footerroutes/register/+page.svelte
+ + + + + + + + +
ElementTailwind classesReal pxNotes
Submit buttonw-full bg-primary text-primary-fg font-sans text-[13px] font-bold tracking-[.12em] uppercase py-4 px-6 rounded-sm flex items-center justify-center gap-2.5 transition-colors hover:bg-[#01386f] mt-813px font / 16px top+bottom padding / ~53px tallArrow icon: 16×16px SVG. Loading state: add opacity-85 cursor-wait, swap icon for spinner.
Loading spinnerw-4 h-4 rounded-full border-2 border-white/30 border-t-white animate-spin16pxReplaces arrow icon during loading state
Footer wrappermt-6 flex flex-col gap-3.5 text-center24px top margin, 14px gap
Privacy textfont-serif text-sm text-ink-3 leading-relaxed14pxLinks within: text-ink underline decoration-accent underline-offset-[3px] decoration-2
Sign-in promptfont-sans text-[13px] text-ink-213pxi18n: m.register_have_account() + m.register_sign_in()
Sign-in linkfont-sans text-xs font-bold tracking-[.1em] uppercase text-ink underline decoration-accent underline-offset-[4px] decoration-212pxhref="/login"
+
+
+ + + +
+
+ 8 + Success panel — post-submit state +
+ +
+ + +
+ Success — German +
+
+
+
+
localhost:3000/register
+
+
+
+
+
+ Familienarchiv +
+ + + +
+
+
+
+
+
+
+
+ +
+
Willkommen im Familienarchiv.
+
Wir haben dir eine E-Mail an frieda@beispiel.de geschickt, um deine Adresse zu bestätigen. Anschließend kannst du dich anmelden.
+
+ + +
+
+
+
+
+
+
+
+
+ + +
+ Success — English +
+
+
+
+
localhost:3000/register?lang=en
+
+
+
+
+
+ Familienarchiv +
+ + + +
+
+
+
+
+
+
+
+ +
+
Welcome to Familienarchiv.
+
We sent an email to frieda@example.com to confirm your address. After that, you can sign in.
+
+ + +
+
+
+
+
+
+
+
+
+ +
+ +
+
Implementation Reference — Success panelroutes/register/+page.svelte
+ + + + + + + + +
ElementTailwind classesReal pxNotes
Success wrappertext-center py-28px top/bottom paddingReplaces the entire <form> block. Same card container as the form.
Checkmark circlew-[72px] h-[72px] rounded-full bg-[rgba(161,220,216,0.35)] inline-flex items-center justify-center mb-672pxCheckmark SVG: 34×34px, stroke #012851 2.2px.
Success headlinefont-serif font-normal text-[30px] leading-tight text-ink mb-3.530pxi18n key: m.register_success_h()
Success bodyfont-serif text-[17px] leading-[1.55] text-ink-2 max-w-[420px] mx-auto mb-717px, max 420pxi18n key: m.register_success_b(). Replace {email} token with entered email.
CTA buttonSame as submit button — full-width navyhref="/login". i18n: m.register_success_action()
Resend linkfont-sans text-xs font-bold tracking-[.1em] uppercase text-ink-2 px-2.5 py-2.5 underline decoration-accent underline-offset-[4px] decoration-212pxi18n: m.register_success_resend(). Calls /api/auth/resend-verification. Container: max-w-[320px] mx-auto flex flex-col gap-2.5
+
+
+ + + +
+
+ 9 + Mobile layout — 320px +
+ +
+ + +
+ 320px — form at rest +
+
+ 9:41 +
+
+
+
+
+
+
+
+
+
+ Familienarchiv +
+ + + +
+
+
+
+ +
+
Ein Familienprojekt
+
Schön, dass du
da bist.
+
Bereits 1.500 Briefe sind im Archiv. Mit deinem Konto hilfst du mit, sie zu bewahren.
+
+ +
+
+
Über dich
+ +
+
+
Vorname
+ +
+
+
Nachname
+ +
+
+
+
+
Konto
+
+
+
E-Mail
+ +
+
+
Passwort
+
+ + +
+
+
+
Passwort best.
+
+ + +
+
+
+
+ +
+
+
+
+
Name grid collapses to single column. Subtext shortened. Card padding reduced. All inputs remain 17px on real device (browser zooms accordingly).
+
+ + +
+ 320px — filled, ready to submit +
+
+ 9:41 +
+
+
+
+
+
+
+
+
+
+ Familienarchiv +
+ + + +
+
+
+
+
+
Schön, dass du
da bist.
+
+
+
+
Über dich
+
+
+
Vorname
+ +
+
+
Nachname
+ +
+
+
+
+
Konto
+
+
+
E-Mail
+ +
+
+
Passwort
+
+ + +
+
✓ 8 Zeichen
+
+
+
Best.
+
+ + +
+
Stimmen überein.
+
+
+
+ +
+
+
+
+
+ + +
+ 320px — success panel +
+
+ 9:41 +
+
+
+
+
+
+
+
+
+
+ Familienarchiv +
+ + + +
+
+
+
+
+
+
+ +
+
Willkommen im Familienarchiv.
+
Wir haben dir eine E-Mail an frieda@b.de geschickt, um deine Adresse zu bestätigen.
+
+ + +
+
+
+
+
+
+
+ +
+ +
+
Implementation Reference — Mobile breakpointsroutes/register/+page.svelte
+ + + + + + + + + + +
BreakpointChangeTailwindNotes
Default (mobile-first, <480px)Single-column name gridgrid grid-cols-1 gap-4Start mobile-first; add sm:grid-cols-2 at 480px+
sm: 480px+2-column name gridsm:grid-cols-2Custom breakpoint or use min-[480px]:grid-cols-2
Default (mobile-first)Card padding 24pxp-6Reduced from desktop 40px
sm: 640px+Card padding 40pxsm:p-10Full desktop padding
Default (mobile-first)Main padding 32px toppt-8Reduced from desktop 64px
sm: 640px+Main padding 64px topsm:pt-16
All breakpointsInput font size 17pxtext-[17px]Do NOT reduce on mobile — large text is critical for the 60+ audience. The browser will zoom the viewport to show text clearly.
All breakpointsTouch targets ≥ 44pxButton: py-4 = 16px × 2 + 13px font = 45px ✓CheckOption card: entire card is the touch target (~52px+ tall) ✓
+
+
+ + + +
+
+ 10 + Implementation notes — i18n, accessibility, backend +
+ +
+ + +
+
i18n keys (Paraglide)
+
+
New keys — messages/de.json + en.json + es.json
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDE
register_eyebrowEin Familienprojekt
register_headlineSchön, dass du da bist.
register_subBereits 1.500 Briefe aus vielen Jahrzehnten…
register_section_aboutÜber dich
register_section_accountKonto
register_section_prefsBenachrichtigungen
register_first_nameVorname
register_last_nameNachname
register_emailE-Mail-Adresse
register_passwordPasswort
register_password_confirmPasswort bestätigen
register_pw_hintMindestens 8 Zeichen.
register_pw_match_okPasswörter stimmen überein.
register_pw_match_noDie beiden Passwörter stimmen noch nicht überein.
register_notify_labelBenachrichtige mich,
register_notify_descwenn jemand mich in einem Kommentar erwähnt…
register_submitKonto erstellen
register_submit_loadingWird erstellt…
register_have_accountDu hast bereits ein Konto?
register_sign_inAnmelden
register_success_hWillkommen im Familienarchiv.
register_success_bWir haben dir eine E-Mail an {email} geschickt…
register_success_actionZur Anmeldung
register_success_resendE-Mail erneut senden
register_privacyMit dem Erstellen eines Kontos stimmst du der
register_privacy_linkDatenschutzerklärung
register_terms_linkNutzungsbedingungen
password_showAnzeigen
password_hideVerbergen
page_title_registerRegistrieren — Familienarchiv
+
+
+ + +
+
Accessibility requirements
+
+
WCAG 2.2 checklist
+ + + + + + + + + + + +
CriterionImplementationLevel
1.4.3 Contrast (text)Navy #012851 on white: 14.5:1 ✓. Gray #4b5563 on white: 7.6:1 ✓. Gray #6b7280 on white: 5.9:1 ✓ (AA only — use for large text / hints)AA
2.4.2 Page title<svelte:head><title>{m.page_title_register()}</title>A
1.3.1 Form labelsEvery input has <label for="...">. No placeholder-as-label.A
2.4.3 Focus orderTab order: DE/EN/ES → Vorname → Nachname → Email → Password → Confirm → Checkbox → SubmitA
2.4.7 Focus visiblefocus-visible:ring-2 focus-visible:ring-focus-ring/15 on all inputs. focus-visible:ring-2 focus-visible:ring-white/80 on submit button.AA
2.5.3 Touch target (2.2)All buttons ≥ 44px tall. CheckOption card ≥ 44px. Show/hide button: 44px tall (same as input height).AA
4.1.3 Status messagesPassword match/mismatch feedback announced via aria-live="polite" region.AA
1.4.4 Resize textAll sizes in rem/px that scale with browser zoom. 17px input font = 1.0625rem.AA
Error identificationaria-invalid="true" on invalid inputs. aria-describedby linking to error message element.A
+
+
+ + +
+
Backend wiring
+
+
Route + API integration
+ + + + + + + + + + + + +
ConcernDetails
Routefrontend/src/routes/register/+page.svelte + +page.server.ts
Form actionPOST ?/register+page.server.ts action
API endpointPOST /api/auth/register — create new AppUser (first name, last name, email, password, notifyOnMention)
On successBackend sends verification email. Frontend shows success panel with entered email.
Resend endpointPOST /api/auth/resend-verification — body: { email }
Client-side validationRun before server submit: required fields, email format, password ≥ 8 chars, password match. Show errors inline on first submit attempt.
Server-side errorsMap backend error codes via getErrorMessage(code): EMAIL_ALREADY_EXISTS → Paraglide key. Never display raw backend messages.
notifyOnMention fieldCheckOption checked state maps to notifyOnMention: boolean in request body. Default: true.
Language preferenceThe active language is a client-side Paraglide state only (page.svelte $state). Not persisted until the user creates an account; can be added to the registration payload as preferredLanguage: 'de' | 'en' | 'es' if the backend supports it.
Auth headerRegister page is unauthenticated. Use a minimal header (AuthHeader without nav links) or a dedicated RegisterHeader.
+
+ +
+ Implementation sequence: +
    +
  • 1. Add POST /api/auth/register to Spring Boot backend (new controller + service method)
  • +
  • 2. Add POST /api/auth/resend-verification
  • +
  • 3. Regenerate TypeScript API types (npm run generate:api)
  • +
  • 4. Implement frontend/src/routes/register/+page.svelte
  • +
  • 5. Add i18n keys to all three message files
  • +
  • 6. Add route to navigation (unauthenticated footer or login page link)
  • +
+
+
+ +
+
+ +
+ +