Files
2FATest/AGENTS.md
T

4.7 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this is

A Spring Boot + Vaadin Flow project (Vaadin 25, Spring Boot 4, Java 25). UI is built entirely in server-side Java — no HTML/JS/TypeScript to write for views. Data layer is Spring Data JPA over H2 (file/in-memory, dev only).

Commands

./mvnw spring-boot:run      # run the app (dev), http://localhost:8080
./mvnw test                 # run all tests
./mvnw test -Dtest=TaskServiceTest                       # single test class
./mvnw test -Dtest=TaskServiceTest#tasks_are_validated_before_they_are_stored  # single test method
./mvnw package               # production build -> target/*.jar
java -jar target/*.jar       # run the built jar

No system Maven is required; always use the ./mvnw wrapper. There is no separate lint command configured.

Live hotswap (edit Java, see changes without restart) requires launching via the Vaadin IDE plugin (IntelliJ/VS Code/Eclipse) instead of spring-boot:run — not available from the CLI.

Port defaults to 8080 (override via server.port in src/main/resources/application.properties or the PORT env var).

Architecture

Feature-package structure: code is organized by feature/domain under com.example.<feature>, not by technical layer. Each feature package is self-contained: entity, repository, service, and a ui sub-package for its views. com.example.examplefeature is the template feature to copy/replace — its package-info.java has a TODO Remove this package once you have added real features.

Package visibility convention: types are package-private by default (e.g. TaskRepository, TaskService, TaskListView are not public). Only export a type outside its feature package when another package actually needs it. Follow this pattern for new features.

Null-safety: packages are annotated @NullMarked (JSpecify) in their package-info.java, so all types are non-null by default; use @Nullable explicitly where null is allowed (e.g. Task.dueDate). Apply @NullMarked to any new feature package.

Layout/routing: MainLayout (com.example.base.ui, annotated @Layout) is the shared AppLayout shell (drawer nav + header/footer) applied automatically to routed views. Side-nav entries are auto-discovered via @Menu on @Route view classes (see TaskListView) — no manual registration needed. ViewTitle is a shared composite for the per-view title bar (drawer toggle + heading).

Data access pattern: Slice<T> (via findAllBy(Pageable)) is preferred over Page<T> for grid data providers, since Slice avoids the extra COUNT query — see the comment in TaskRepository. Vaadin Grid is wired to Spring Data via VaadinSpringDataHelpers.toSpringPageRequest(query) in an in-memory/lazy DataProvider callback (see TaskListView).

Entities: JPA entities use @GeneratedValue(strategy = GenerationType.SEQUENCE), expose validation in setters (throwing IllegalArgumentException) rather than via bean-validation annotations, and implement equals/hashCode based on ID only (with a fixed hashCode, per the pattern in Task).

Schema management: spring.jpa.hibernate.ddl-auto=update is used for local dev convenience only. This is explicitly not appropriate for production — the app is meant to move to Flyway (or similar) for real schema migrations before shipping.

Frontend theming: Application sets the app-shell config (@Push, Aura theme via @StyleSheet(Aura.STYLESHEET), plus custom styles.css/view-title.css under src/main/resources/META-INF/resources/). No separate frontend build step is needed for typical UI work since Flow generates the client bundle; the vaadin-maven-plugin build-frontend goal runs as part of the Maven build.

Testing

Two distinct test styles are used:

  • Service/integration tests (TaskServiceTest): @SpringBootTest(webEnvironment = MOCK) + @Transactional (each test rolls back), asserting against the JPA layer directly.
  • UI/browserless tests (TaskListViewTest): extend SpringBrowserlessTest (from com.vaadin:browserless-test-spring), which renders and interacts with actual Vaadin components server-side without a real browser. Use navigate(ViewClass.class), test(component) for interactions/assertions, and $(ComponentClass.class) for component lookup queries. Views expose package-private fields (e.g. taskGrid, description, createBtn) specifically so tests in the same package can drive them directly.

MCP

.mcp.json configures a Vaadin docs MCP server (https://mcp.vaadin.com/docs) and a Playwright MCP server — both available for querying live Vaadin component/API docs and browser automation if needed.