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>
This commit is contained in:
Marcel
2026-03-22 23:57:01 +01:00
parent 5f49a5787c
commit 908221f04d
15 changed files with 618 additions and 64 deletions

View File

@@ -5,7 +5,7 @@ import { env } from 'process';
import { cookieName, cookieMaxAge } from '$lib/paraglide/runtime';
import { detectLocale } from '$lib/server/locale';
const PUBLIC_PATHS = ['/login', '/logout'];
const PUBLIC_PATHS = ['/login', '/logout', '/forgot-password', '/reset-password'];
const handleLocaleDetection: Handle = ({ event, resolve }) => {
if (!event.cookies.get(cookieName)) {
@@ -71,6 +71,12 @@ export const handleFetch: HandleFetch = async ({ event, request, fetch }) => {
return fetch(request);
}
// Password reset endpoints are public — no auth header needed.
const PUBLIC_API_PATHS = ['/api/auth/forgot-password', '/api/auth/reset-password'];
if (PUBLIC_API_PATHS.some((p) => request.url.includes(p))) {
return fetch(request);
}
const token = event.cookies.get('auth_token');
if (!token) {