This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Vaadin Flow 25.1 web application template using Java 26, packaged as a WAR, deployed on Jetty 12.1. Uses vaadin-core (free components only, Hilla disabled). Parent POM is com.svenruppert:dependencies:06.02.02 which provides plugin and dependency version management. pom.xml is the authoritative version reference — see "Source of truth" at the end of this file.
# Run dev server (default goal is jetty:run)
./mvnw
# Compile only
./mvnw compile
# Run unit tests
./mvnw test
# Run a single test
./mvnw test -Dtest=ClassName#methodName
# Production build (optimized frontend bundle)
./mvnw package -Pproduction
# Mutation testing with PiTest + per-package coverage gate
./mvnw -P_mutation-gate \
org.pitest:pitest-maven:mutationCoverage \
verify
# Standalone fat-jar (java -jar target/application.jar)
./mvnw -P_shadejar -DskipTests package
# Check for dependency updates
./mvnw versions:display-dependency-updates- AppShell (
com.svenruppert.flow.AppShell) - App shell configurator. Sets viewport, PWA metadata, themy-themeLumo theme, and enables@Push(server push via WebSocket). - AppServlet (
com.svenruppert.flow.AppServlet) - CustomVaadinServlet. Mapped + configured viasrc/main/webapp/WEB-INF/web.xml, where the criticali18n.providerinit-param points atcom.svenruppert.flow.i18n.AppI18NProvider(Vaadin V25 ignoresMETA-INF/servicesforI18NProvider). - MainLayout (
com.svenruppert.flow.views.MainLayout) -AppLayoutwith brand mark + role-gated drawer + locale/theme switchers + auth-action button. All routed views use this as their parent layout. - Views are in
com.svenruppert.flow.views(and.views.main). Each view declares apublic static final String PATH(orNAV) constant used for routing and nav links. - i18n - Translation bundles in
src/main/resources/vaadin-i18n/translations*.properties. Views implementI18nSupportand calltr(K_KEY, "English fallback"). CustomAppI18NProviderdefeats the JVM-default-localeResourceBundlefallback bug. - Storage paths - Single point of truth:
com.svenruppert.flow.security.storage.AppStoragePaths. Production defaults to./data/; tests fork with-Dapp.storage.dir=target/test-datavia Surefire<systemPropertyVariables>. - Frontend - Custom theme at
src/main/frontend/themes/my-theme/, view-specific CSS insrc/main/frontend/styles/. Thegenerated/directory is auto-generated by Vaadin and should not be edited.
.mvn/maven.configforces-U(update snapshots), strict test failures, verbose plugin validation..mvn/jvm.configsets heap limits and--enable-native-access=ALL-UNNAMED.- Maven enforcer requires Maven >= 3.9.9.
- PiTest targets
com.svenruppert.*prod classes andjunit.com.svenruppert.*test classes. - Test convention: test classes go under
junit.com.svenruppert.*package (not the standardcom.svenruppert.*). - Surefire passes
-Dapp.storage.dir=${project.build.directory}/test-dataso tests never touch the repo-rooted./data/tree. - Surefire also passes
-Dapp.hibp.enabled=falsesoPasswordPreflightskips the Have-I-Been-Pwned k-anonymity range call. Production runs leave this unset (default =true); the HIBP layer is fail-open on network errors (CWE-359), so a network outage never blocks legitimate password changes.
production- Vaadin production frontend build with optimized bundle._java- Additional compiler setup with newer ASM (9.8) for Java 26 support._shadejar- Builds a standalone Jetty fat-jar namedapplication.jar(uses nano-vaadin-jetty 04.00.00)._mutation-gate- Runs PIT mutation coverage +tools/pit-gate.shto enforce per-package floors (build fails on regression).
pom.xml is the authoritative version reference for: parent POM version, JDK version, Vaadin version, Jetty version, jSentinel version, nano-vaadin-jetty version. Update it first, then mirror values into CLAUDE.md and AGENTS.md. Cross-check with:
./mvnw versions:display-dependency-updatesThe current versions snapshot is:
| Property | Value |
|---|---|
Parent (com.svenruppert:dependencies) |
06.02.02 |
JDK / maven.compiler.release |
26 |
vaadin.version |
25.1.1 |
jetty.version |
12.1.8 |
jsentinel.version |
00.74.00 |
nano-vaadin-jetty.version |
04.00.00 |
Follow the global implementation-cycle skill. Project-pluggable slots:
- Tracker = ClickUp (workspace
2443039, foldersvenruppert90150380304).- Plan + per-issue: list
publikationsverwaltung(901524338583) - Concepts:
publikationsverwaltung-concepts(901524338584),Open → deployed - Features:
publikationsverwaltung-features(901524338585)
- Plan + per-issue: list
- Status mapping:
Open(not started) →in progress→Closed(completed). Concept task:Open → deployed. (review/on-hold/testing/bugfixing/release prepared/skippedalso exist.) - Sync mechanic: ClickUp status field + a
## Completion logappended to the task'smarkdown_description(date, commit hash, what shipped, acceptance result). Parent gets status only. - Build/test:
./mvnw test; acceptance per issue = module test green + full./mvnw clean verifywhen a shared/parent file changed. - Mutation gate:
./mvnw -P_mutation-gate org.pitest:pitest-maven:mutationCoverage verify(floors intools/pit-baselines.txt; add a line per new package). - Publish/deploy: WAR via
./mvnw clean package -Pproduction→target/ROOT.war; optional fat-jar via_shadejar. Tag schemev<X.Y.Z>. - Version/modules: single-module WAR,
-SNAPSHOTworking line, finalize-strip before release. Domain code lives incom.svenruppert.publications; views stay undercom.svenruppert.flow.views. - Standards pass:
/java-standards-pass(haslogger, httpstatus, mediatype, result, vaadin-i18n). - Commit/branch: work on the integration branch directly; push is the human's decision; never an AI-attribution / "generated with" footer.
Non-negotiable status discipline: every issue moves to in progress when work begins and to
Closed only when done — no issue stays Open while worked on, and none jumps Open → Closed
directly. The board reflects the real state of work at all times.