Add AppHeader and AppFooter to give the site a consistent chrome
around the core page content. Add ComposePage stub reachable via
"Skicka ett brev till ägaren" CTA on HomePage after vehicle lookup
succeeds. Add stub pages for about, contact, and privacy.
- Create AppHeader.vue with logo link (BilHälsning) and Hem nav link
- Create AppFooter.vue with 4 links: Om oss, Kontakt, Integritetspolicy, Villkor
- Create ComposePage.vue stub that reads plate from route query params
- Create AboutPage.vue and ContactPage.vue stub pages
- Add 4 new routes: /compose, /om, /kontakt, /integritetspolicy
- Update App.vue to render AppHeader + <main> + AppFooter around RouterView
- Add home__cta RouterLink button to HomePage, visible only when vehicle
lookup succeeds, linking to /compose?plate=<plate>
- Remove BilHälsning h1 from HomePage (moved to header)
- Add 17 new tests: AppHeader (2), AppFooter (1), ComposePage (3),
AboutPage (1), ContactPage (1), HomePage rewrite (6), App update (2)
- Update App.spec.ts to verify header/footer components render
Move vehicle-info display logic out of HomePage into a reusable
VehicleInfo component. The component accepts vehicle, loading,
notFound, and plate props and renders the correct state with
priority: vehicle card > loading > not found. Follows the
small-page-component pattern from CODING_GUIDELINES.md.
- Create VehicleInfo.vue with 3-state v-if chain and scoped styles
- Define and export VehicleInfo interface (make/model/year/color)
- Add VehicleInfo.spec.ts with 7 tests covering all states and
priority edge cases
- Update HomePage.vue to use VehicleInfo, replacing 3 inline
v-if/else-if blocks with a single component tag
- Remove 5 unused CSS classes from HomePage (home__status,
home__vehicle, home__vehicle-text, home__not-found,
home__not-found p)
- Update AGENTS.md to require thorough commit messages with bullet
points
- V1__create_users_table.sql replaces placeholder: creates users table with
id UUID PK, email UNIQUE NOT NULL, password_hash NOT NULL, subscription
VARCHAR(20) DEFAULT 'none' with CHECK constraint (none/basic/pro),
created_at/updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP.
Compatible with both H2 and PostgreSQL.
- SecurityConfig: minimal @Configuration providing BCryptPasswordEncoder
bean. Required because Spring Boot 4 no longer auto-configures a
PasswordEncoder.
- Subscription enum: NONE, BASIC, PRO with string values matching the DB
CHECK constraint.
- User entity: @PrePersist generates UUID and timestamps in application
code, @PreUpdate refreshes updated_at. Email setter normalizes to
lowercase for case-insensitive uniqueness. Explicit getters/setters
(no Lombok per guidelines).
- UserRepository: Spring Data JPA extending JpaRepository<User, UUID>.
findByEmail(Optional) and existsByEmail for duplicate checks.
- UserService: @RequiredArgsConstructor with constructor-injected
UserRepository and PasswordEncoder. createUser normalizes email,
checks duplicates via existsByEmail, throws EmailAlreadyExistsException,
hashes password with BCrypt, saves. findByEmail returns Optional<User>.
- EmailAlreadyExistsException: custom RuntimeException for duplicate
registration attempts. ControllerAdvice handler deferred to auth ticket.
Verification: ./gradlew test passes (Flyway + H2 context loads).
docker compose up -d succeeds, Flyway applies V1 against PostgreSQL 16.
\d users confirms all columns, constraints, defaults, and indexes.
- Generate from Spring Initializr with Gradle Groovy DSL, Java 21, Spring Boot 4.0.6
- Dependencies: Web, Security, Data JPA, PostgreSQL Driver, Flyway, Validation, Lombok
- Add H2 runtime dependency for zero-setup local development
- Configure application.yml: H2 in-memory database, port 8080, Flyway with ddl-auto=validate
- Create placeholder Flyway migration V1__init_schema.sql
- Verify ./gradlew test passes and ./gradlew bootRun starts on port 8080
- Update AGENTS.md and README.md: Maven → Gradle commands, Spring Boot 3 → 4