Commit graph

6 commits

Author SHA1 Message Date
3d0b7fe799 Allow users to edit or cancel unpaid orders before payment.
Adds backend endpoints and frontend edit page so pending orders can be updated or soft-cancelled without admin intervention.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 11:21:47 +02:00
86fb946e33 Add password reset, logged-in change password, and Mailpit email dev/E2E.
All checks were successful
CI / Lint, type check, unit tests, coverage (push) Successful in 2m2s
CI / E2E browser tests (push) Successful in 1m55s
Operators can fix prod admin passwords without email via Byt lösenord;
end users can use forgot-password when SMTP is configured. Local and CI
use Mailpit to capture outbound mail and verify reset links end-to-end.

- Backend: V8 password_reset_tokens, PasswordResetService, EmailService,
  POST /api/auth/forgot-password, reset-password, change-password
- Optional testToken in forgot-password response (docker profile only, for E2E)
- Frontend: ForgotPasswordPage, ResetPasswordPage, ChangePasswordPage,
  routes, login link, header Byt lösenord
- Mailpit (ghcr.io/axllent/mailpit:v1.28) in docker-compose + e2e stack
- E2E: password-reset.spec.ts + Mailpit API helper tests SMTP delivery
- Separate dev/e2e Docker image names to avoid overwriting bilhej-frontend
- Docs: README email section, production-email-checklist, .env.example
- Unit/integration tests for reset, change password, and Vitest page specs

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 18:05:15 +02:00
18f462c5c1 feat: add real vehicle lookup via biluppgifter.se scraping
- Add VehicleInfoResponse DTO record with make, model, year, color, fuel fields
- Add VehicleNotFoundException for unknown plates (returns 404)
- Add VehicleLookupException for scrape failures (returns 500)
- Add handlers in GlobalExceptionHandler: 404 'Inget fordon hittades', 500 'Ett internt fel uppstod'
- Add VehicleLookupService that fetches biluppgifter.se/fordon/{plate}/ HTML
- Parse summary cards (.info > em + span) for Farg, Bransle, Modellar
- Parse Fordonsdata section (ul.list > li with span.label / span.value) for Fabrikat, Modell, Variant, Fordonsar
- Build model from Modell + Variant, parse year from Fordonsar / Modellar with Modellar fallback
- Filter out 'Logga in' placeholder values from gated fields
- Add VehicleController with GET /api/vehicles/{plate}, public endpoint (already permitAll)
2026-05-19 15:15:20 +02:00
a74bb89824 feat: add Order entity, repository, and service with TDD tests
- Create V5__create_orders_table.sql migration with orders table
  - UUID primary key, user_id FK to users, status CHECK constraint
  - Indexes on user_id and status columns
- Add OrderStatus enum (PENDING_PAYMENT, PAID, LOOKUP_STARTED, SENT, DELIVERED, FAILED)
- Add OrderStatusConverter for JPA VARCHAR persistence
- Create Order entity with fields: id, userId, plate, template, letterText, status, amountPaid, trackingId, timestamps
- Create OrderRepository with findByUserIdOrderByCreatedAtDesc and findByStatus queries
- Create OrderService with createOrder (normalizes plate, sets PENDING_PAYMENT), getOrdersByUserId, getOrderById
- Add OrderNotFoundException with 404 handler in GlobalExceptionHandler
- Write OrderServiceTest with 8 unit tests covering status, UUID generation, plate normalization, and error handling
2026-05-14 14:34:14 +02:00
3d4a6daee9 feat: add login endpoint with JWT authentication
Add POST /api/auth/login endpoint that authenticates users by email and
password, returning a JWT token on success. Also fixes a critical bug
where expired or malformed JWT tokens in the Authorization header caused
unhandled exceptions, crashing requests to all endpoints including public
ones like registration.

Changes:
- Add AuthController.login() endpoint with LoginRequest DTO
- Add UserService.authenticate() that validates credentials and throws
  InvalidCredentialsException on failure
- Add InvalidCredentialsException and GlobalExceptionHandler handler
  that maps it to 401 with Swedish error message
- Fix JwtAuthenticationFilter to catch JwtException (expired, malformed)
  and pass through without crashing — the filter now acts as a graceful
  enricher rather than a gatekeeper
- Add 5 controller tests for login endpoint (success, 401, validation)
- Add 4 service tests for authenticate() (success, email not found,
  password mismatch, email normalization)
- Add 2 filter tests for expired and malformed token pass-through
2026-05-13 19:16:19 +02:00
8e495672d3 feat: add user registration flow (backend + frontend)
Implement end-to-end registration: POST /api/auth/register creates a
user, returns a JWT, and the frontend RegisterPage stores the token
and redirects to home.

Backend:
- Add AuthController with POST /api/auth/register endpoint
- Add RegisterRequest record (@Email, @NotBlank, @Size(min=8))
- Add AuthResponse and ErrorResponse DTOs
- Add GlobalExceptionHandler (@RestControllerAdvice with logging)
  - EmailAlreadyExistsException -> 409 (Swedish message)
  - MethodArgumentNotValidException -> 400 (field errors)
  - Generic Exception -> 500 (Swedish message + server-side log)

Frontend:
- Add api/client.ts: centralized fetch wrapper with Bearer token
  interceptor, ApiError class, JSON error parsing
- Add api/auth.ts: register() function
- Add stores/authStore.ts: Pinia store with token persistence via
  localStorage, registerUser/logout/isAuthenticated
- Add pages/RegisterPage.vue: email + password + confirm password
  form with client-side validation, submit handler, error display,
  redirect to home on success
- Add route /registrera pointing to RegisterPage
- Add 'Registrera' link to AppHeader navigation

Infrastructure:
- Add __tests__/setup.ts: localStorage polyfill for jsdom 29
  (jsdom 29 lacks standard Storage method implementations)
- Register polyfill via vitest config setupFiles

Tests (17 new, 2 extended):
- AuthControllerTest (@SpringBootTest + @AutoConfigureMockMvc):
  5 backend tests (success 201, duplicate 409, invalid email 400,
  short password 400, missing email 400)
- authStore.spec.ts: 5 tests (unauthenticated start, localStorage
  restore, register success, register failure, logout)
- RegisterPage.spec.ts: 12 tests (render, validation, submit,
  redirect, error display, login link)
- AppHeader.spec.ts: added 'Registrera' link test
- Router.spec.ts: added /registrera route resolution test

Build: 95 tests pass (57 frontend + 38 backend), lint clean.
2026-05-01 19:37:39 +02:00