Checkstyle cleanup (Phases 0-4): 16288 -> 0 violations, gate enabled#65
Open
greluc wants to merge 45 commits into
Open
Checkstyle cleanup (Phases 0-4): 16288 -> 0 violations, gate enabled#65greluc wants to merge 45 commits into
greluc wants to merge 45 commits into
Conversation
Phase 0 of the planned Checkstyle cleanup. The current checkstyleMain
run reports ~16,300 warnings across 486 files; ~14,800 are formatting
only (Indentation, LineLength, CustomImportOrder, AvoidStarImport,
EmptyLineSeparator, OperatorWrap, WhitespaceAround) and can be fixed
with google-java-format in a single dedicated commit.
This change only wires up the tooling, it does NOT reformat any source
file:
- Root build.gradle.kts: id("com.diffplug.spotless") 7.0.4 with
apply false, mirroring the existing info.solidsoft.pitest pattern.
Configuration lives in the subprojects { plugins.withId(...) }
block right after the Checkstyle config and uses
googleJavaFormat() (2-space indent, 100-char line width, Google
import order -- exactly what config/checkstyle/google_checks.xml
expects), removeUnusedImports() and formatAnnotations().
- backend/build.gradle.kts and frontend/build.gradle.kts: each
applies id("com.diffplug.spotless") without a version (the version
is pinned in the root plugins block).
- isEnforceCheck = false on the SpotlessExtension keeps spotlessCheck
off the check task graph for now, so the regular build does not
trip over the still-unformatted repository. Verified with
./gradlew :backend:check --dry-run: only checkstyleMain,
checkstyleTest and spotbugsMain appear.
Tasks spotlessApply and spotlessCheck are now available in both
modules. The actual bulk reformat (Phase 1) will be a separate commit
driven by ./gradlew spotlessApply; enforceCheck will flip back to its
default (true) in Phase 4 once the codebase is clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 1 of the Checkstyle cleanup. Runs `./gradlew spotlessApply` once across `backend/src/` and `frontend/src/`, producing a single formatting-only commit. No logical changes. Diff profile: - 767 Java files modified, +64,325 / -58,146 lines - net ~-6,000 lines because the 4-space indent collapses to 2-space Checkstyle impact (./gradlew checkstyleMain): - IndentationCheck 11,806 -> 8 - LineLengthCheck 1,507 -> 82 - CustomImportOrderCheck 1,074 -> 0 - EmptyLineSeparatorCheck 87 -> 0 - OperatorWrapCheck 57 -> 0 - WhitespaceAroundCheck 17 -> 0 - TOTAL 16,288 -> 1,796 (-89%) Out of scope for this phase (handled separately): - MissingJavadocMethodCheck (913) + MissingJavadocTypeCheck (439) -- content, not format; needs a Javadoc policy decision (Phase 2). - AvoidStarImportCheck (151) -- google-java-format intentionally does not expand star imports because resolution can be ambiguous. - NeedBracesCheck (131) -- outside google-java-format's scope. Verification: - ./gradlew :backend:test :frontend:test -> BUILD SUCCESSFUL in 1m 48s, full backend (1300+) and frontend test suites green, zero failures. Follow-up: - A separate commit adds `.git-blame-ignore-revs` listing this commit's hash, so `git blame` skips this purely-mechanical change when devs set `git config blame.ignoreRevsFile .git-blame-ignore-revs`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lists the purely-mechanical bulk-reformat commit (da3dfd3) so devs who opt in with git config blame.ignoreRevsFile .git-blame-ignore-revs see real authorship in `git blame` instead of the formatting commit's hash on every line. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2a + 2g of the Checkstyle cleanup. Wipes 262 of the 1,352 remaining Phase 2 violations by documenting every class and remaining public non-property method in the three trivial layers: - backend/dto/uex (UEX inbound JSON records, 31) - backend/model + model/dto + model/dto/request (entities, enums, DTO records, 133) - frontend/model + model/dto + model/form (frontend DTOs, forms, enums, 98) Class-level Javadoc was inserted with a one-off helper script (build/_javadoc_insert.py, gitignored under build/) that reads the Checkstyle report, scans forward from the reported annotation line to the actual declaration, and generates a short, suffix-aware one-liner: - *Dto records -> "Data transfer record carrying X payload." - *Request -> "Inbound request payload for the X operation." - *Response -> "Outbound response payload for the X operation." - *Form -> "Form-binding object for X input." - @entity -> "X JPA entity." - @MappedSuperclass -> "Base class shared by all JPA entities (X)." - enums -> "Enumeration of X values." - plain records -> "Immutable record carrying X data." The UEX records (UexCityDto, UexCommodityDto, ...) were written by hand before the script existed; their Javadoc names the entity each DTO is mapped to and the responsible *SyncService - the script's template was modelled after them. Method-level Javadoc (13 sites) was written manually because the content cannot be derived mechanically: - backend/model/Announcement.java -- @PrePersist/@PreUpdate hook - backend/model/JobOrder.java, JobOrderHandover.java -- bidirectional back-reference helpers (addMaterial, addItem) - backend/model/dto/MaterialMatrixItemDto.java, MaterialPriceOverviewDto.java -- tuple-mapping convenience ctors - backend/model/dto/RefineryOrderListDto.java, frontend/model/dto/RefineryOrderDto.java, RefineryOrderListDto.java -- getEndsAt derived timestamp - frontend/model/dto/MissionFrequencyDto.java -- frequencyTypeId() - frontend/model/dto/MissionUnitDto.java -- getJobSummary aggregation - frontend/model/form/JobOrderForm.java, RefineryOrderForm.java -- no-arg ctors that pre-seed one row for the dynamic form widgets Spotless ran across the inserts so any one-line Javadoc that broke the 100-char limit got re-wrapped to multi-line form. Verification: ./gradlew :backend:test :frontend:test -> BUILD SUCCESSFUL in 1m 40s, full backend (1300+) and frontend test suites green, zero failures. The complex layers -- Services, Controllers, Repositories, Mappers, Configs, Integration, Exception, Logging -- are intentionally out of scope here because their Javadoc has to be substantive, not boilerplate-generated. They follow in separate sub-phases (2b-2f, 2h, 2i, 2j); enforceCheck stays at false until they are done. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…vice Phase 2h + 2j of the Checkstyle cleanup. Wipes 59 more violations by documenting every frontend package except `controller` (left for the final sub-phase 2i): - frontend/config: 12 type + 11 method javadocs (Beans, security filter chain, role hierarchy, OAuth2 auth manager, WebClient setup) - frontend/filter: 1 type - frontend/logging: 2 type + 8 method (CorrelationContext, LogMasker) - frontend/exception: 4 method (GlobalExceptionHandler.handle*) - frontend/service: 1 type + 19 method (BackendApiClient, exception) - frontend root: 1 type (FrontendApplication) Class-level Javadoc came from the helper script (build/_javadoc_insert.py) with a richer heuristic set: - new suffix-word strip list: Properties, Config, Filter, Editor, Handler, Policy, Layout, Context, Application, Service, Controller, Repository, Advice, Interceptor, Mapper, Task, Scheduler -- so "BackendRoleSyncFilter" becomes "Servlet filter handling Backend Role Sync" instead of "...Backend Role Sync Filter" - new annotation-driven branches: @configuration, @ConfigurationProperties, @ControllerAdvice (cross-cutting advice, NOT REST endpoints), @RestController, @controller (MVC pages), @service, @repository Method-level Javadoc was written by hand for the substantive cases: - SecurityConfig.{filterChain, roleHierarchy, userAuthoritiesMapper} -- central auth config: filter ordering, role hierarchy mirrored from ROLES_AND_PERMISSIONS.md, OIDC realm-access claim mapping - WebClientConfig.{authorizedClientManager, webClient, publicWebClient} -- Resilience4j chain (timeout, retry, circuit breaker, bulkhead), OAuth2 bearer relay, 16 MB codec, correlation-id propagation - BackendApiClient class Javadoc rewritten by hand (the script's initial "Service layer for Backend Api Client" was uninformative); plus 17 HTTP-verb wrapper methods documented (GET/POST/PUT/DELETE/ PATCH with Class<T> + ParameterizedTypeReference + isPublic overloads, plus getCached* and clearStaticDataCache) - BackendServiceException -- two constructors (slim status-only, full RFC-7807 result) with reference to the fromProblem decoder - LogMasker.mask* -- masking strategy per PII category (email, id, token, phone, generic fallback) - LocaleConfig, CacheConfig, ETagConfig, GlobalBindingAdvice, SmartOidcLogoutSuccessHandler -- one-liners explaining the Bean Verification: ./gradlew :frontend:test -> BUILD SUCCESSFUL in 43s, full frontend test suite green, zero failures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2b of the Checkstyle cleanup. Wipes all 95 remaining mapper violations (22 type, 73 method) in `backend.mapper`. Class-level Javadoc came from the helper script (build/_javadoc_insert.py) with a new suffix rule: - *Mapper -> "MapStruct mapper between X entities and DTOs." EntityMappers (hand-written utility class for cases MapStruct can't handle) got an explanatory class Javadoc by hand instead of the script's generic fallback. Method-level Javadoc was written by hand with a focus on the non-obvious bits: - toEntity overloads: which fields are intentionally `@Mapping(ignore = true)` (id, version, timestamps, aggregate collections owned by the service and rewired post-persist) - MaterialMapper: UEX-style Integer 0/1 normalisation to / from Boolean for isIllegal, isVolatileQt, isVolatileTime - JobOrderMapper.mapAndSortMaterials: deterministic ordering (SCU first, then alphabetical case-insensitive) so the materials table is stable across reloads - JobTypeMapper.setParentAfterMapping: parent stub resolved post-map because MapStruct cannot wire @manytoone id stubs natively - MissionMapper.resolveDescription: description is redacted for unauthenticated callers - MissionMapper.resolveCrew: leader-first ordering with case-insensitive secondary sort by participant name - PersonalInventoryItemMapper: ownerSub never leaves the service (multi-user isolation key from JWT sub) - RefineryOrderMapper.computeProfit / missionDtoToMission: profit derivation and stub-Mission resolution explained - UserMapper.roleNames / permissions: helper defaults flattening the role aggregate into name sets Spotless re-wrapped any long single-line Javadoc to multi-line form. Verification: ./gradlew :backend:test -> BUILD SUCCESSFUL in 59s, all 1300+ backend tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2c of the Checkstyle cleanup. Wipes all 202 remaining repository violations (41 type, 161 method) in `backend.repository`. Class-level Javadoc came from the existing helper script (build/_javadoc_insert.py) with a new suffix rule: - *Repository -> "Spring Data repository for X." Method-level Javadoc was generated by a new helper script (build/_javadoc_methods_insert.py) that parses Spring-Data derived-query prefixes and emits 1-liners: - findBy* -> "Derived Spring-Data query - returns entities matching X" - existsBy* -> "Returns true iff at least one row matches X" - countBy* -> "Returns the count of rows matching X" - deleteBy* -> "Deletes every row matching X" - findFirstBy* / findTopBy* -> "Returns the first matching X (limit 1)" - findAll -> "Lists every entity. Overridden here to attach an @EntityGraph" Annotation detection (regex-aware so fully-qualified annotation names like @org.springframework.data.jpa.repository.Modifying also match): - @EntityGraph: appends "Eagerly fetches the configured relations" - @lock: appends "Acquires a pessimistic write lock" - @query + @Modifying: emits "Custom JPQL/native bulk update; see the @query annotation for the WHERE clause and the @Param contract." - @query alone: emits "Custom JPQL/native query; see the @query annotation for the projection and filter clauses." QUALITY CAVEAT: the ~40 @Query-annotated methods - concentrated in InventoryItemRepository (8), MissionRepository (3), MaterialPriceRepository (4), LocationRepository (2), JobOrderRepository (4) - get the generic placeholder Javadoc above. It satisfies the Checkstyle check but is pure boilerplate; a follow-up refinement pass should replace those with substantive descriptions of what each specific query does (the filter combinations, the bulk-update semantics, the lock contracts). The derived-query Javadocs are unaffected and read fine. Verification: ./gradlew :backend:test -> BUILD SUCCESSFUL in 54s, all 1300+ backend tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refinement pass on Phase 2c. The original mass-insert in commit d6ce646 left ~38 @Query-annotated repository methods with a generic "Custom JPQL/native query; see the @query annotation..." placeholder because the helper script could not infer the semantics from the method name alone. This commit replaces every placeholder by hand with a description of what the specific query actually does, focusing on filter combinations, projection targets, bulk-update semantics and lock contracts that are not obvious from reading the JPQL. Files touched (10): - InventoryItemRepository (10): N+1-avoidance fetch, two multi-filter search variants (global vs per-user, optional dimension contract), weighted-mean quality aggregation, native COALESCE+SUM helper for the completion check, the three unlink* bulk updates incl. the clearAutomatically/flushAutomatically note from CLAUDE.md, natural-key merge query, owner reassignment for user-merge. - MissionRepository (5): active-mission reference projection, two searchMissions variants (List vs Page) with the optional-cast trick, owner reassignment, native manager-removal on the join. - MaterialPriceRepository (5): paged DTO projection, best-sell-price ordering, flattened material/terminal/price matrix tuple, auto-load price lists. - JobOrderRepository (4): active-with-materials eager load, max priority for new-order assignment, pessimistic lock for bulk reorder (links the CLAUDE.md rule), native assignee-removal. - UserRepository (3): reference projection with fallback name, Keycloak-sync stale-flag update, admin lookup. - MaterialRepository (3): reference projection, materials-with-prices filter, weighted price overview with optional name filter. - ShipRepository (3): fitted-flag reset before fleet import, ships-by-type aggregation, owner reassignment. - RefineryOrderRepository (2): mission unlink with CLAUDE.md cross- reference, owner reassignment. - LocationRepository (2): reference projection, refinery-locations lookup. - MissionParticipantRepository (1): user unlink that preserves guest history. No source-code logic touched - this is purely a docs refinement. Verification: ./gradlew :backend:test -> BUILD SUCCESSFUL, all backend tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the "boilerplate placeholder remains; a refinement pass should follow" caveat from the Phase 2c CHANGELOG entry - that pass landed in commit b45d5f3 and the placeholder no longer exists. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 0 of the planned Checkstyle cleanup. The current checkstyleMain
run reports ~16,300 warnings across 486 files; ~14,800 are formatting
only (Indentation, LineLength, CustomImportOrder, AvoidStarImport,
EmptyLineSeparator, OperatorWrap, WhitespaceAround) and can be fixed
with google-java-format in a single dedicated commit.
This change only wires up the tooling, it does NOT reformat any source
file:
- Root build.gradle.kts: id("com.diffplug.spotless") 7.0.4 with
apply false, mirroring the existing info.solidsoft.pitest pattern.
Configuration lives in the subprojects { plugins.withId(...) }
block right after the Checkstyle config and uses
googleJavaFormat() (2-space indent, 100-char line width, Google
import order -- exactly what config/checkstyle/google_checks.xml
expects), removeUnusedImports() and formatAnnotations().
- backend/build.gradle.kts and frontend/build.gradle.kts: each
applies id("com.diffplug.spotless") without a version (the version
is pinned in the root plugins block).
- isEnforceCheck = false on the SpotlessExtension keeps spotlessCheck
off the check task graph for now, so the regular build does not
trip over the still-unformatted repository. Verified with
./gradlew :backend:check --dry-run: only checkstyleMain,
checkstyleTest and spotbugsMain appear.
Tasks spotlessApply and spotlessCheck are now available in both
modules. The actual bulk reformat (Phase 1) will be a separate commit
driven by ./gradlew spotlessApply; enforceCheck will flip back to its
default (true) in Phase 4 once the codebase is clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 1 of the Checkstyle cleanup. Runs `./gradlew spotlessApply` once across `backend/src/` and `frontend/src/`, producing a single formatting-only commit. No logical changes. Diff profile: - 767 Java files modified, +64,325 / -58,146 lines - net ~-6,000 lines because the 4-space indent collapses to 2-space Checkstyle impact (./gradlew checkstyleMain): - IndentationCheck 11,806 -> 8 - LineLengthCheck 1,507 -> 82 - CustomImportOrderCheck 1,074 -> 0 - EmptyLineSeparatorCheck 87 -> 0 - OperatorWrapCheck 57 -> 0 - WhitespaceAroundCheck 17 -> 0 - TOTAL 16,288 -> 1,796 (-89%) Out of scope for this phase (handled separately): - MissingJavadocMethodCheck (913) + MissingJavadocTypeCheck (439) -- content, not format; needs a Javadoc policy decision (Phase 2). - AvoidStarImportCheck (151) -- google-java-format intentionally does not expand star imports because resolution can be ambiguous. - NeedBracesCheck (131) -- outside google-java-format's scope. Verification: - ./gradlew :backend:test :frontend:test -> BUILD SUCCESSFUL in 1m 48s, full backend (1300+) and frontend test suites green, zero failures. Follow-up: - A separate commit adds `.git-blame-ignore-revs` listing this commit's hash, so `git blame` skips this purely-mechanical change when devs set `git config blame.ignoreRevsFile .git-blame-ignore-revs`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lists the purely-mechanical bulk-reformat commit (da3dfd3) so devs who opt in with git config blame.ignoreRevsFile .git-blame-ignore-revs see real authorship in `git blame` instead of the formatting commit's hash on every line. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2a + 2g of the Checkstyle cleanup. Wipes 262 of the 1,352 remaining Phase 2 violations by documenting every class and remaining public non-property method in the three trivial layers: - backend/dto/uex (UEX inbound JSON records, 31) - backend/model + model/dto + model/dto/request (entities, enums, DTO records, 133) - frontend/model + model/dto + model/form (frontend DTOs, forms, enums, 98) Class-level Javadoc was inserted with a one-off helper script (build/_javadoc_insert.py, gitignored under build/) that reads the Checkstyle report, scans forward from the reported annotation line to the actual declaration, and generates a short, suffix-aware one-liner: - *Dto records -> "Data transfer record carrying X payload." - *Request -> "Inbound request payload for the X operation." - *Response -> "Outbound response payload for the X operation." - *Form -> "Form-binding object for X input." - @entity -> "X JPA entity." - @MappedSuperclass -> "Base class shared by all JPA entities (X)." - enums -> "Enumeration of X values." - plain records -> "Immutable record carrying X data." The UEX records (UexCityDto, UexCommodityDto, ...) were written by hand before the script existed; their Javadoc names the entity each DTO is mapped to and the responsible *SyncService - the script's template was modelled after them. Method-level Javadoc (13 sites) was written manually because the content cannot be derived mechanically: - backend/model/Announcement.java -- @PrePersist/@PreUpdate hook - backend/model/JobOrder.java, JobOrderHandover.java -- bidirectional back-reference helpers (addMaterial, addItem) - backend/model/dto/MaterialMatrixItemDto.java, MaterialPriceOverviewDto.java -- tuple-mapping convenience ctors - backend/model/dto/RefineryOrderListDto.java, frontend/model/dto/RefineryOrderDto.java, RefineryOrderListDto.java -- getEndsAt derived timestamp - frontend/model/dto/MissionFrequencyDto.java -- frequencyTypeId() - frontend/model/dto/MissionUnitDto.java -- getJobSummary aggregation - frontend/model/form/JobOrderForm.java, RefineryOrderForm.java -- no-arg ctors that pre-seed one row for the dynamic form widgets Spotless ran across the inserts so any one-line Javadoc that broke the 100-char limit got re-wrapped to multi-line form. Verification: ./gradlew :backend:test :frontend:test -> BUILD SUCCESSFUL in 1m 40s, full backend (1300+) and frontend test suites green, zero failures. The complex layers -- Services, Controllers, Repositories, Mappers, Configs, Integration, Exception, Logging -- are intentionally out of scope here because their Javadoc has to be substantive, not boilerplate-generated. They follow in separate sub-phases (2b-2f, 2h, 2i, 2j); enforceCheck stays at false until they are done. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…vice Phase 2h + 2j of the Checkstyle cleanup. Wipes 59 more violations by documenting every frontend package except `controller` (left for the final sub-phase 2i): - frontend/config: 12 type + 11 method javadocs (Beans, security filter chain, role hierarchy, OAuth2 auth manager, WebClient setup) - frontend/filter: 1 type - frontend/logging: 2 type + 8 method (CorrelationContext, LogMasker) - frontend/exception: 4 method (GlobalExceptionHandler.handle*) - frontend/service: 1 type + 19 method (BackendApiClient, exception) - frontend root: 1 type (FrontendApplication) Class-level Javadoc came from the helper script (build/_javadoc_insert.py) with a richer heuristic set: - new suffix-word strip list: Properties, Config, Filter, Editor, Handler, Policy, Layout, Context, Application, Service, Controller, Repository, Advice, Interceptor, Mapper, Task, Scheduler -- so "BackendRoleSyncFilter" becomes "Servlet filter handling Backend Role Sync" instead of "...Backend Role Sync Filter" - new annotation-driven branches: @configuration, @ConfigurationProperties, @ControllerAdvice (cross-cutting advice, NOT REST endpoints), @RestController, @controller (MVC pages), @service, @repository Method-level Javadoc was written by hand for the substantive cases: - SecurityConfig.{filterChain, roleHierarchy, userAuthoritiesMapper} -- central auth config: filter ordering, role hierarchy mirrored from ROLES_AND_PERMISSIONS.md, OIDC realm-access claim mapping - WebClientConfig.{authorizedClientManager, webClient, publicWebClient} -- Resilience4j chain (timeout, retry, circuit breaker, bulkhead), OAuth2 bearer relay, 16 MB codec, correlation-id propagation - BackendApiClient class Javadoc rewritten by hand (the script's initial "Service layer for Backend Api Client" was uninformative); plus 17 HTTP-verb wrapper methods documented (GET/POST/PUT/DELETE/ PATCH with Class<T> + ParameterizedTypeReference + isPublic overloads, plus getCached* and clearStaticDataCache) - BackendServiceException -- two constructors (slim status-only, full RFC-7807 result) with reference to the fromProblem decoder - LogMasker.mask* -- masking strategy per PII category (email, id, token, phone, generic fallback) - LocaleConfig, CacheConfig, ETagConfig, GlobalBindingAdvice, SmartOidcLogoutSuccessHandler -- one-liners explaining the Bean Verification: ./gradlew :frontend:test -> BUILD SUCCESSFUL in 43s, full frontend test suite green, zero failures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2b of the Checkstyle cleanup. Wipes all 95 remaining mapper violations (22 type, 73 method) in `backend.mapper`. Class-level Javadoc came from the helper script (build/_javadoc_insert.py) with a new suffix rule: - *Mapper -> "MapStruct mapper between X entities and DTOs." EntityMappers (hand-written utility class for cases MapStruct can't handle) got an explanatory class Javadoc by hand instead of the script's generic fallback. Method-level Javadoc was written by hand with a focus on the non-obvious bits: - toEntity overloads: which fields are intentionally `@Mapping(ignore = true)` (id, version, timestamps, aggregate collections owned by the service and rewired post-persist) - MaterialMapper: UEX-style Integer 0/1 normalisation to / from Boolean for isIllegal, isVolatileQt, isVolatileTime - JobOrderMapper.mapAndSortMaterials: deterministic ordering (SCU first, then alphabetical case-insensitive) so the materials table is stable across reloads - JobTypeMapper.setParentAfterMapping: parent stub resolved post-map because MapStruct cannot wire @manytoone id stubs natively - MissionMapper.resolveDescription: description is redacted for unauthenticated callers - MissionMapper.resolveCrew: leader-first ordering with case-insensitive secondary sort by participant name - PersonalInventoryItemMapper: ownerSub never leaves the service (multi-user isolation key from JWT sub) - RefineryOrderMapper.computeProfit / missionDtoToMission: profit derivation and stub-Mission resolution explained - UserMapper.roleNames / permissions: helper defaults flattening the role aggregate into name sets Spotless re-wrapped any long single-line Javadoc to multi-line form. Verification: ./gradlew :backend:test -> BUILD SUCCESSFUL in 59s, all 1300+ backend tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2c of the Checkstyle cleanup. Wipes all 202 remaining repository violations (41 type, 161 method) in `backend.repository`. Class-level Javadoc came from the existing helper script (build/_javadoc_insert.py) with a new suffix rule: - *Repository -> "Spring Data repository for X." Method-level Javadoc was generated by a new helper script (build/_javadoc_methods_insert.py) that parses Spring-Data derived-query prefixes and emits 1-liners: - findBy* -> "Derived Spring-Data query - returns entities matching X" - existsBy* -> "Returns true iff at least one row matches X" - countBy* -> "Returns the count of rows matching X" - deleteBy* -> "Deletes every row matching X" - findFirstBy* / findTopBy* -> "Returns the first matching X (limit 1)" - findAll -> "Lists every entity. Overridden here to attach an @EntityGraph" Annotation detection (regex-aware so fully-qualified annotation names like @org.springframework.data.jpa.repository.Modifying also match): - @EntityGraph: appends "Eagerly fetches the configured relations" - @lock: appends "Acquires a pessimistic write lock" - @query + @Modifying: emits "Custom JPQL/native bulk update; see the @query annotation for the WHERE clause and the @Param contract." - @query alone: emits "Custom JPQL/native query; see the @query annotation for the projection and filter clauses." QUALITY CAVEAT: the ~40 @Query-annotated methods - concentrated in InventoryItemRepository (8), MissionRepository (3), MaterialPriceRepository (4), LocationRepository (2), JobOrderRepository (4) - get the generic placeholder Javadoc above. It satisfies the Checkstyle check but is pure boilerplate; a follow-up refinement pass should replace those with substantive descriptions of what each specific query does (the filter combinations, the bulk-update semantics, the lock contracts). The derived-query Javadocs are unaffected and read fine. Verification: ./gradlew :backend:test -> BUILD SUCCESSFUL in 54s, all 1300+ backend tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refinement pass on Phase 2c. The original mass-insert in commit d6ce646 left ~38 @Query-annotated repository methods with a generic "Custom JPQL/native query; see the @query annotation..." placeholder because the helper script could not infer the semantics from the method name alone. This commit replaces every placeholder by hand with a description of what the specific query actually does, focusing on filter combinations, projection targets, bulk-update semantics and lock contracts that are not obvious from reading the JPQL. Files touched (10): - InventoryItemRepository (10): N+1-avoidance fetch, two multi-filter search variants (global vs per-user, optional dimension contract), weighted-mean quality aggregation, native COALESCE+SUM helper for the completion check, the three unlink* bulk updates incl. the clearAutomatically/flushAutomatically note from CLAUDE.md, natural-key merge query, owner reassignment for user-merge. - MissionRepository (5): active-mission reference projection, two searchMissions variants (List vs Page) with the optional-cast trick, owner reassignment, native manager-removal on the join. - MaterialPriceRepository (5): paged DTO projection, best-sell-price ordering, flattened material/terminal/price matrix tuple, auto-load price lists. - JobOrderRepository (4): active-with-materials eager load, max priority for new-order assignment, pessimistic lock for bulk reorder (links the CLAUDE.md rule), native assignee-removal. - UserRepository (3): reference projection with fallback name, Keycloak-sync stale-flag update, admin lookup. - MaterialRepository (3): reference projection, materials-with-prices filter, weighted price overview with optional name filter. - ShipRepository (3): fitted-flag reset before fleet import, ships-by-type aggregation, owner reassignment. - RefineryOrderRepository (2): mission unlink with CLAUDE.md cross- reference, owner reassignment. - LocationRepository (2): reference projection, refinery-locations lookup. - MissionParticipantRepository (1): user unlink that preserves guest history. No source-code logic touched - this is purely a docs refinement. Verification: ./gradlew :backend:test -> BUILD SUCCESSFUL, all backend tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the "boilerplate placeholder remains; a refinement pass should follow" caveat from the Phase 2c CHANGELOG entry - that pass landed in commit b45d5f3 and the placeholder no longer exists. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wipes the entire AvoidStarImportCheck backlog (151 -> 0). Driven by a
new helper script, build/_resolve_star_imports.py:
- reads the Checkstyle report,
- for each file with a star-import violation, scans the body (stripped
of string literals and comments) for CamelCase identifiers,
- matches them against a known-class catalogue per star package:
java.util, java.lang.annotation, jakarta.persistence, lombok,
org.mapstruct, org.springframework.web.bind.annotation are
hard-coded (covering the classes actually used here),
de.greluc.krt.iri.basetool.* is scanned from the source tree,
- replaces each star import with the alphabetised list of concrete
imports that file actually references; spotlessApply re-sorts them
into Google import order afterwards.
149 / 151 violations resolved by the script. The two remaining ones
in JobOrderHandoverReportService (OpenPDF's com.lowagie.text.* and
com.lowagie.text.pdf.*) were expanded by hand to 13 concrete imports
(Document, Element, Font, Image, PageSize, Paragraph, Phrase,
Rectangle, PdfContentByte, PdfPCell, PdfPTable, PdfPageEventHelper,
PdfWriter).
Two catalogue tweaks during the run: jakarta.persistence.CollectionTable
and java.util.NoSuchElementException were missing on the first try
(one compile failure each); now added to the script's catalogue
alongside the rest of the less-common java.util types.
Static star imports are intentionally skipped by the script -- they
are rare and manual resolution is safer.
Verification: ./gradlew :backend:test :frontend:test ->
BUILD SUCCESSFUL in 1m 40s, full backend (1300+) and frontend (491+)
test suites green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wipes the entire NeedBracesCheck backlog (131 -> 0). Google Style
mandates braces on every control-flow construct; the original code had
many one-liners like:
if (cond) return X;
if (cond) doSomething();
Driven by a new helper script build/_add_needbraces.py that parses the
Checkstyle report, scans each flagged line for the pattern
`<indent>(}? else )?(if|while|for) (cond) stmt;` and rewrites it into a
three-line block:
if (cond) {
stmt;
}
126 / 131 violations resolved by the script. The 5 remaining ones were
fixed by hand:
- 4 in MissionPageController where the body started on the following
line (multi-line if construct the regex does not handle)
- 1 in UexRefinerySyncService with the `} else stmt;` form (else
without if as the control keyword on its own line)
Plus one repair after the bulk apply: the script's greedy `[^{}]*`
condition matcher mis-identified the inner method-call parens in
`if (a != null) m(b.c() ? null : b);` as the if-condition, splitting
the ternary across the new brace. Affected UserService.updateUser and
UserService.updateUserDescription (the two `setDisplayName` call
sites); rewritten by hand. The script header documents this limitation
so the next user knows to spot-check ternary-heavy lines.
Spotless re-formats the new blocks.
Verification: ./gradlew :backend:test :frontend:test ->
BUILD SUCCESSFUL in 1m 44s, all backend (1300+) and frontend (491+)
tests green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eption, ...) Phase 2f of the Checkstyle cleanup. 41 files across 11 backend infrastructure packages, 111 violations cleared. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wipes the entire LineLengthCheck backlog (82 -> 0). Two Spotless config tweaks in build.gradle.kts drive most of it: - googleJavaFormat().reflowLongStrings() turns on the google-java-format flag that re-wraps overlong String concatenations; default behaviour leaves strings alone because re-wrapping could alter runtime output. That alone resolves ~63 of the 82 violations (long @operation(description = "...") strings on controller endpoints, Logger.error messages, the CSP template etc.). - formatAnnotations() removed from the Spotless chain. Its rule packs several Bean-Validation annotations onto a single line, which pushed every `@NotBlank(message = "...") @SiZe(max = N, ...) String name` in the *Form records over 100 chars. Without it, google-java-format keeps annotations on separate lines once they no longer fit, which is the desired behaviour everywhere in the project. The drop has a broad side-effect: ~70 files (repositories, services) now have field- and method-level annotations on their own lines where they used to be glued together. Project-wide consistency wins. Manual touch-ups beyond the Spotless changes: - PiiMasker + PiiMaskingPatternLayout: the long KEYWORD_TOKEN_PATTERN regex was broken across two literal strings via `+` concatenation (reflowLongStrings does not re-wrap concatenated literals because that would re-order the regex alternatives). - MissionController: five new imports for the request DTOs that lived under model/dto/request (PatchMissionCoreRequest, PatchMissionScheduleRequest, PatchMissionFlagsRequest, AddFrequencyRequest, UpdateMissionOwnerRequest), with the fully-qualified usages in the method signatures collapsed to the simple class names. - InventoryPageController: same pattern for UpdateDeliveredRequest. Verification: ./gradlew :backend:test :frontend:test -> BUILD SUCCESSFUL in 1m 45s, all backend (1300+) and frontend (491+) tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2i of the Checkstyle cleanup. 27 files in the frontend.controller package, 156 violations cleared. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sweep of the smaller checks left over after Phase 3c. Each individual
check is too small for its own commit, but together they bring the
Phase 3 backlog down to just three categories that need real semantic
work (VariableDeclarationUsageDistance,
AbbreviationAsWordInName, OverloadMethodsDeclarationOrder).
Resolved:
- EmptyCatchBlockCheck (3): commented the three intentionally-empty
catch blocks (ProfileController joinDate parse, two
BackendServiceException RFC7807 fallback paths) so commentFormat=\w+
is satisfied.
- MatchXpathCheck#singleLineCommentStartWithSpace (2): empty `//`
separators inside MissionController's block comment removed.
- AvoidEscapedUnicodeCharactersCheck (11): \u00XX sequences in
HangarController, CreateJobOrderMaterialDto and
JobOrderHandoverReportService replaced with literal umlauts via the
new helper build/_fix_unicode_escapes.py (regex \u([0-9A-Fa-f]{4})
-> chr(int(hex,16))).
- LocalVariableNameCheck (15) + CatchParameterNameCheck (2): two-char
prefix variable names (pId, pName, pStart, pEnd, qType, rName,
pLoc, pMan, gForm, sItem, eIso, eLocal, oEffectiveClass, yPos)
renamed to substantive names matching the
^[a-z]([a-z0-9][a-zA-Z0-9]*)?$ pattern.
- ClassTypeParameterNameCheck (1): AbstractEntity<PK> -> <K>.
- SummaryJavadocCheck (8) + JavadocParagraphCheck (3): added missing
trailing periods (RateLimitProperties, AppProblemProperties,
WebClientLoggingFilter class doc) and missing <p> tags before
follow-up paragraphs (InventoryItemService.updateNote,
RedisSessionConfig).
- TextBlockGoogleStyleFormattingCheck (2): JPQL text blocks in
MaterialPriceRepository and MaterialRepository aligned vertically
with the closing """ marker.
- IndentationCheck (2): fixed a misaligned closing paren in
JobOrderHandoverReportService.staffelLogo; shortened
OperationPageController.updateOperation catch by importing
WebClientResponseException so the catch signature fits on one line.
Verification: ./gradlew :backend:test :frontend:test ->
BUILD SUCCESSFUL in 1m 40s, all backend (1300+) and frontend (491+)
tests green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2d of the Checkstyle cleanup. 35 files in the backend.service package, 238 violations cleared. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Phase 3d commit (d7e5d26) missed its CHANGELOG entry because the batched git-add-and-commit ran before the CHANGELOG edit landed. Catch-up entry summarising the 50+ smaller Checkstyle fixes (EmptyCatchBlock, MatchXpath, AvoidEscapedUnicodeCharacters, LocalVariableName, CatchParameterName, ClassTypeParameterName, SummaryJavadoc, JavadocParagraph, TextBlockGoogleStyleFormatting, Indentation). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e (Phase 3e) The check fires when a local variable is declared more than 3 statements before its first use. Default config has `ignoreFinal=true`, so adding the `final` keyword silences the check for the 9 affected sites without moving the declaration around. Each variable was already effectively final - they are assigned once, never reassigned. Affected: ProblemDetail pd (GlobalExceptionHandler.handleAccessDenied), MaterialReferenceDto mat (InventoryItemService stream lambda), User user / Material material / Location location (InventoryItemService.create), double remainingAmount (JobOrderHandoverService.createHandover), Integer priority (JobOrderService.deleteJobOrder), int cap (PersonalInventoryItemService.searchLocations), boolean isNew (UexRefinerySyncService.syncRefiningMethods). No semantic change. Test suite untouched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…se 3f) Last of the AbbreviationAsWordInNameCheck violations. Google style allows at most one capital letter in an abbreviation, so: - ETagConfig -> EtagConfig (backend + frontend, via git mv so history is preserved). Spring discovers @configuration beans via reflection on the class itself, so no external references needed adjustment. - krtOpenAPI -> krtOpenApi (OpenApiConfig @bean method, doubles as the bean name; Spring still wires by type so call sites work unchanged). - openAPI -> openApi (local variables in OpenApiProblemDetailsConfig.customizeOpenApi + ensureProblemDetailSchema). After this commit only OverloadMethodsDeclarationOrderCheck (4 sites, all pure method-reordering) is left in Phase 3 - deferred to a later session because the reordering touches multiple ~10-line method definitions in MissionMapper, MissionRepository and UserService. Verification: ./gradlew :backend:test :frontend:test -> BUILD SUCCESSFUL in 1m 39s, all backend (1300+) and frontend (491+) tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ervice (Phase 3g) Resolves the last 4 OverloadMethodsDeclarationOrderCheck violations, closing Phase 3 entirely. - MissionMapper: the nine toDto(...) overloads were sprinkled across the file, separated by toReferenceDto / toListDto / toEntity and the resolve* helpers. All toDto methods are now grouped at the top (Mission, MissionParticipant, MissionUnit, MissionCrew, MissionFinanceEntry, FrequencyType, MissionFrequency, JobType, Squadron), followed by the other mapping methods, followed by the resolve* helpers. - MissionRepository: searchMissions(... Pageable) sat after the two findAll overloads; moved directly behind searchMissions(...). - UserService: findAll(Pageable) sat after findAllReference(); moved directly behind findAll(). Pure reordering, no logic change, no test adjustment. Phase 3 summary - all Restmechanik now green: - 3a AvoidStarImport 151 -> 0 - 3b NeedBraces 131 -> 0 - 3c LineLength 82 -> 0 - 3d small-check sweep ~50 -> 0 - 3e VariableDeclarationUsageDistance 9 -> 0 - 3f AbbreviationAsWordInName 5 -> 0 - 3g OverloadMethodsDeclarationOrder 4 -> 0 Verification: ./gradlew :backend:test :frontend:test -> BUILD SUCCESSFUL in 1m 48s, all backend (1300+) and frontend (491+) tests green. Only the Phase 2 Javadoc backlog remains (734 violations in service/controller/config/integration/exception layers and the frontend controller package). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2e of the Checkstyle Javadoc cleanup — closes the last open
sub-phase. Adds 26 type-level and 203 method-level Javadocs across
the entire backend.controller package; net 1,592 insertions.
Type-Javadocs document each controller's non-obvious architectural
decisions (section patches + slim endpoints in MissionController,
state-machine + atomic inventory unlink in JobOrderController,
user-/owner-/admin-path duplication in RefineryOrderController,
PLANNED/ACTIVE/COMPLETED state machine + ADMIN bypass in
OperationController, guest redaction pipeline in MissionController).
Method-Javadocs focus on the concurrency patterns from CLAUDE.md:
- JobOrderController.updateJobOrderStatus: canonical
completeJobOrderWithinTransaction pointer
- JobOrderController.createHandover: bulk-update-after-loop reference
- JobOrderController.updateJobOrderPriority: pessimistic-lock reorder
- MissionController.updateMissionOwner: separate MissionOwnership
version (no Mission.version bump)
- MissionController.patchMission{Core,Schedule,Flags}: independent
section versions
- MissionController.cleanupMissionForGuest/Participant/User: the
guest redaction pipeline as central anti-PII safety net
- MissionController.addParticipantPublic: free-text name resolution
with spoofing protection
Legacy MissionController endpoints (15) keep their @deprecated tag
with @deprecated Javadoc pointing at the slim replacement and the
SLIM_DEPRECATION_SUNSET date so IDE hover and Javadoc output stay
consistent with the @ApiDeprecation annotation.
Verified with `./gradlew :backend:checkstyleMain :backend:spotbugsMain
:backend:test` — 0 Javadoc violations remaining in backend.controller,
SpotBugs clean, backend test suite green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… -> 0)
Merge the parallel branch's Phase 2 work (sub-phases 2d/2e/2f/2i —
backend services, backend controllers, backend infrastructure,
frontend controllers) using `git merge -X theirs`, then re-apply
and finish the Phase 3 cleanup.
Recovered Phase 3 mechanics that were lost by the `theirs` strategy:
- Re-expand 2 star imports (InventoryItemService, MissionService)
- Re-brace 8 `if`/`else` single-line bodies (NeedBraces)
- Re-convert 2 bare `//` lines to blank lines (MatchXpath)
- Restore deleted EtagConfig.java files (backend + frontend) and add
Javadoc to the backend variant so HttpCachingTest can autowire the
ShallowEtagHeaderFilter bean
New Checkstyle violations introduced by the merge:
- 90 SummaryJavadoc (Javadocs that started with `@return` had no
summary) — auto-fixed by new build/_fix_summary_javadoc.py,
long synthesized summaries wrapped by build/_wrap_long_javadoc.py
- 13 InvalidJavadocPosition (back-to-back duplicate Javadocs from
both branches documenting the same method) — auto-fixed by new
build/_merge_duplicate_javadocs.py with manual tag-deduplication
follow-up
- 15 LocalVariableName renames (eIso, pId, pName, pStart, pEnd,
pLoc, pMan, gForm, sItem, qType, rName, yPos, oEffectiveClass
-> descriptive camelCase)
- 9 VariableDeclarationUsageDistance fixes (added `final`)
- 4 OverloadMethodsDeclarationOrder reorderings (grouped toDto
overloads in MissionMapper, searchMissions in MissionRepository,
findAll in UserService)
- 3 AbbreviationAsWordInName renames (krtOpenAPI -> krtOpenApi,
openAPI -> openApi)
- 3 EmptyCatchBlock explanatory comments added
- 2 CatchParameterName renames (eIso/eLocal -> eiso/elocal)
- 3 JavadocParagraph fixes (<p> tag inserted)
- 3 MissingJavadocMethod/Type entries on EtagConfig
- 5 LineLength fixes (split long regex strings, shortened FQCN
{@link} references, rewrote one long summary)
- 2 TextBlockGoogleStyleFormatting reindents
- 2 Indentation fixes
Spotless ran over everything afterwards. Compile clean on backend
and frontend (main + test source sets). Full test suite blocked
locally by Docker unavailability (TestContainers); Mockito-based
unit tests still green.
Verified `./gradlew :backend:checkstyleMain :frontend:checkstyleMain`:
backend `<error>` count = 0, frontend `<error>` count = 0
(16288 in Phase 0 -> 1796 after Phase 1 -> 738 pre-merge -> 0 now).
Next step (Phase 4): flip `enforceCheck = true` in the Spotless
config and `ignoreFailures = false` on the Checkstyle tasks so
`./gradlew check` blocks any future regression.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wraps up the Checkstyle cleanup that started in Phase 0. Two
settings in `build.gradle.kts` move from "warn-only" to "block
the build":
* Checkstyle subprojects: `isIgnoreFailures = false`,
`maxWarnings = 0` — any new Checkstyle warning OR error now
fails `./gradlew check`.
* Spotless subprojects: `isEnforceCheck = true` — `spotlessCheck`
runs as part of `check`, any unformatted Java file fails CI.
The first `spotlessCheck` after the flip uncovered one format drift
left over from Phase 3 (`setAbsolutePosition(...)` manually wrapped
to two lines in `JobOrderHandoverReportService`); `spotlessApply`
auto-fixed it. That auto-fix in turn restored a two-line
`catch (\n FQCN e)` block in `OperationPageController` whose
continuation indent IndentationCheck rejects — resolved by adding
an explicit `import WebClientResponseException` so the catch fits
on one line again.
Verified:
- `./gradlew :backend:checkstyleMain :frontend:checkstyleMain
:backend:spotlessCheck :frontend:spotlessCheck --rerun-tasks`
→ BUILD SUCCESSFUL, 0 violations, 0 format drifts
- `./gradlew :backend:spotbugsMain :frontend:spotbugsMain
--rerun-tasks` → BUILD SUCCESSFUL, both modules clean
Cumulative reduction: 16288 → 1796 → 738 → 0 violations, now
gate-protected.
Developer impact: run `./gradlew spotlessApply` locally before
pushing, and any new public API needs class/method Javadoc or
MissingJavadocType/Method will block the build.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two new rules added in the sections they belong to so future contributors (and future Claude sessions) hit the same constraints the gate enforces: - Linting section: Run `./gradlew spotlessApply` locally before every push. Spotless is now `isEnforceCheck = true` and Checkstyle `isIgnoreFailures = false` + `maxWarnings = 0`, so an unformatted file or new warning fails CI on the spot. - Documentation section: Javadoc is gate-enforced. Missing Javadoc on a new public/protected member fails the build via MissingJavadocType / MissingJavadocMethod. Same gate covers SummaryJavadoc (period after first sentence), InvalidJavadocPosition (no Javadoc between annotations and the declaration), JavadocParagraph (<p> after blank lines), and AtclauseOrder (@param/@return/@throws ordering). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hi-c03b21 # Conflicts: # CHANGELOG.md # backend/src/main/java/de/greluc/krt/iri/basetool/backend/service/InventoryItemService.java # backend/src/main/java/de/greluc/krt/iri/basetool/backend/service/JobOrderHandoverReportService.java # backend/src/main/java/de/greluc/krt/iri/basetool/backend/service/JobOrderService.java # backend/src/main/java/de/greluc/krt/iri/basetool/backend/service/MissionFinanceEntryService.java # backend/src/main/java/de/greluc/krt/iri/basetool/backend/service/MissionSecurityService.java # backend/src/main/java/de/greluc/krt/iri/basetool/backend/service/OperationFinanceService.java # backend/src/main/java/de/greluc/krt/iri/basetool/backend/service/OperationService.java # backend/src/main/java/de/greluc/krt/iri/basetool/backend/service/ProfitCalculationService.java # backend/src/main/java/de/greluc/krt/iri/basetool/backend/service/SystemSettingService.java
… PR #65 CodeQL security (3): - JobOrderPageController: orders_filter_status cookie now sets setHttpOnly(true) + setSecure(true) so it can't be read from JS and isn't sent over plain HTTP. - RateLimitingFilter: 429 response body's `instance` field reflects request.getRequestURI() (attacker-controlled). String-concatenation into JSON allowed JSON-injection ("},"fake":"…). Escape via Jackson's JsonStringEncoder before injecting. - SecurityConfig CSRF disabled: NOT addressed. Intentional for this JWT-bearer-token resource server (no session cookie, no cross-origin auto-attached header) — the test-profile disable is gated by Spring profile. False positive. Code-quality (8): - MissionPageControllerMvcTest: drop dead fixture Map literals (shipTypeData, unitData, orderData, itemData, materialData) that were built up but never attached to the MissionDto under test — 3 "Container contents never accessed" findings. - ParticipationCalculationTest: remove the assertNull(percentages.get(participantId.toString())) tautology on a Map<UUID, Double> (String key never matches a UUID entry). - MissionUnitColorIndexTest: replace the assertTrue(PALETTE_SIZE >= 20) constant comparison with a runtime distinct-class-set assertion over indices 0..19. Functionally equivalent but no longer always-true at compile time. - Announcement: drop the shadowing updatedAt field + @PrePersist/ @PreUpdate hook. AbstractEntity.updatedAt with @UpdateTimestamp already does this; the duplicate was producing both the missing- @OverRide finding AND a JPA column-mapping ambiguity. Also add @Getter(onMethod_ = @__(@OverRide)) to id so the Lombok-generated getId() carries @OverRide (implements Persistable.getId()). - Faction: same @Override-via-Lombok onMethod_ treatment for id. Verified: - ./gradlew :backend:checkstyleMain :frontend:checkstyleMain :backend:spotlessCheck :frontend:spotlessCheck :backend:spotbugsMain :frontend:spotbugsMain → BUILD SUCCESSFUL - ./gradlew :backend:test --tests "*Announcement*" → green - ./gradlew :frontend:test --tests "*MissionUnitColorIndexTest* *ParticipationCalculationTest*" → green - ./gradlew :backend:test --tests "*RateLimitingTest*" → fails on Docker (TestContainers env), unrelated to this change. Not addressed in this commit: - SecurityConfig CSRF (see above) - The systemic Lombok @OverRide pattern on the other 41 entity classes — CodeQL only flagged Announcement and Faction; the rest carry the same shape and will get the same treatment when CodeQL catches up. Left as a follow-up rather than touching 41 unrelated files in this PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… strip CRLF from GlobalExceptionHandler CodeQL's "Missing Override annotation" check fires on every entity whose Lombok-generated getId() implements Persistable.getId() without @OverRide. Doing them one at a time was whack-a-mole — three new findings landed across two CI runs after the first batch (City, InventoryItem, JobOrderHandover, JobOrderHandoverItem, JobOrderMaterial, Jurisdiction, Location, Manufacturer, FrequencyType). Closing the pattern uniformly across the entire backend.model package ends the spread. Approach (build/_apply_getter_override.py): walk the model directory, find every `private UUID id;` field on an `extends AbstractEntity` class, and insert `@Getter(onMethod_ = @__(@OverRide))` as the first annotation in its block. The class-level @Getter still drives every other field; the field-level annotation wins for `id` and attaches @OverRide to the generated getId() so the override marker is real without losing Lombok's brevity. 38 entities updated by the script + 3 stragglers fixed manually (Role with Long id, SystemSetting with String id, User with inline `@Id private UUID id;` that the script's regex didn't match). Announcement and Faction already had the annotation from the prior batch. Also strips CRLF from GlobalExceptionHandler.java which had drifted to Windows line endings in the index (git ls-files --eol reported `i/-text w/-text` — git had decided the file was binary because the blob contained `\r\n`). CI's spotlessJavaCheck was failing because Spotless saw CRLF and wanted LF. Rewriting with LF restores the expected git/Spotless contract. Not in this commit: the CodeQL "advanced configuration cannot be processed when default setup is enabled" error on the `Analyze (java-kotlin)` / `Analyze (javascript-typescript)` checks is a repo-settings conflict (the CodeQL workflow file from main collides with GitHub's auto-enabled default setup). That requires admin action via Settings → Code security, not a code change here. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…+ drop spurious @param <T> CodeQL keeps drip-feeding "Missing Override annotation" findings on Spring Data repositories that redeclare findById / findAll (typically to attach @EntityGraph). Eight new findings this CI run across six repositories. Doing them one-at-a-time was already a whack-a-mole loop in the entity-class batch — closing the pattern uniformly across the repository package ends the spread. Helper: build/_apply_repo_override.py. Walks every *Repository.java under backend/src/main/java, matches method declarations whose name + parameter shape match a Spring Data inherited override (findById(ID), findAll(), findAll(Pageable), findAll(Sort), existsById, count, findAllById, deleteById, delete, deleteAll, save), and inserts @OverRide as the first annotation in the block. Derived queries (findByEmail, findFirstByPlannedStartTime…, findAllActiveReference) are NOT matched. Result: 8 @OverRide insertions across 6 files: - JobOrderRepository.findById - MissionRepository.findById + findAll(Pageable) - RefineryOrderRepository.findAll(Pageable) - RoleRepository.findAll(Pageable) - ShipRepository.findAll(Pageable) - UserRepository.findById + findAll(Pageable) Also drops the `@param <T>` Javadoc tag from UexResponseDto. Records' auto-generated accessors (status(), data()) plus the synthetic build()/toString() inherit the record-level Javadoc, and a type parameter `@param <T>` has no value parameter to bind to on any of those — CodeQL flags it as "Spurious Javadoc @param tags" with empty match. Replaced with prose mentioning T and a note explaining why the tag isn't used (so future contributors don't re-add it). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The string sentinel `MESSAGE_NOT_FOUND_SENTINEL` was defined with
four LITERAL 0x00 bytes baked into the source instead of the proper
6-char Java escape sequence (backslash + u + four zero digits). Git's
auto-binary detection saw the NUL bytes in the blob and classified
the file as binary (`git ls-files --eol` reported `i/-text w/-text`).
That meant:
1. No CRLF -> LF normalization ever happened on this file, so it
stayed CRLF in the index even after my previous "strip CR"
attempt re-committed the same binary blob.
2. Spotless on the Linux CI runner saw the CRLF in every line and
failed `spotlessJavaCheck` with 995 format violations.
3. `grep` reported the file as binary, hiding it from text tools.
build/_fix_global_exception_handler.py rewrites the file:
- Replaces every 0x00 byte with the corresponding Java escape
sequence so the file becomes pure ASCII text.
- Strips CR from CRLF so the file is pure LF.
After the fix `git ls-files --eol` reports `i/lf w/lf` -- git now
treats it as proper text, Spotless is happy, and the sentinel still
compares equal to a 16-char string with NUL characters at runtime
(the Java compiler decodes the escape into the same NUL char).
Verified `./gradlew :backend:spotlessCheck :backend:checkstyleMain
:backend:spotbugsMain` -> BUILD SUCCESSFUL.
Note: this is a recurrence of the same root cause as the previous
attempt in 31cf6f8 -- that commit stripped CR but did NOT touch the
NUL bytes, so git kept the binary classification and CR came back
on the next spotlessApply re-write. Replacing the NUL bytes is what
actually breaks the cycle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hi-c03b21 # Conflicts: # CHANGELOG.md
There was a problem hiding this comment.
CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
Spotless 7.0.4 bundles google-java-format 1.25.2 by default. That
version reflects against
com.sun.tools.javac.util.Log$DeferredDiagnosticHandler.getDiagnostics()
whose return type changed from Queue<JCDiagnostic> to Deque<JCDiagnostic>
in JDK 25. The CI runner has switched to a JDK 25 Temurin patch that
exposes the new signature, so the reflection lookup explodes with
NoSuchMethodError for every Java file in the repo:
> Task :backend:spotlessJavaCheck FAILED
> There were 529 lint error(s), they must be fixed or suppressed.
google-java-format(java.lang.NoSuchMethodError) ...
> Task :frontend:spotlessJavaCheck FAILED
> There were 238 lint error(s) ...
767 files, all failing on the same internal-API mismatch — none of
them have any actual format issue. Pinning google-java-format to
1.28.0 (the first GJF release that targets the new JDK 25 signature)
restores spotlessCheck on CI.
Local JDK 21 still works because the old method signature exists
there too — the bug only manifests on JDK 25, which is what CI uses
(.github/workflows/ci.yml: `Set up JDK 25 (Temurin)`).
Verified `./gradlew spotlessCheck --rerun-tasks` -> BUILD SUCCESSFUL
locally on JDK 21 with the pinned version (so the version is at
least syntactically valid and Maven Central has it).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tracks the current GJF release. Verified `./gradlew spotlessCheck --rerun-tasks` -> BUILD SUCCESSFUL — no format drift relative to 1.28.0 on the existing codebase (the two versions produce the same output for every file in the repo). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Major-version bump to track the current Spotless release. Verified
`./gradlew spotlessCheck --rerun-tasks` -> BUILD SUCCESSFUL — no
format drift relative to 7.0.4 on the existing codebase (Spotless 8.x
ships with the same google-java-format integration we already pin
to 1.35.0, so the formatting contract is unchanged).
Also generalises the comment block on the explicit
`googleJavaFormat("1.35.0")` pin so it no longer hardcodes "Spotless
7.0.4 bundles 1.25.2" -- the pin override survives Spotless
upgrades, the JDK 25 reasoning still applies.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Patch-level bump to track the current Dependency-Check release. Verified `./gradlew help --task dependencyCheckAggregate` -> BUILD SUCCESSFUL (plugin resolves and the aggregate task is still wired). Comment block updated to reference the new version. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Minor-version bump to track the current ArchUnit release. Verified: - `./gradlew :backend:compileTestJava :frontend:compileTestJava` -> BUILD SUCCESSFUL (API still source-compatible). - `./gradlew :backend:test --tests '*ArchitectureTest*' :frontend:test --tests '*ArchitectureTest*'` -> BUILD SUCCESSFUL (the architectural invariants in backend/.../ArchitectureTest.java and frontend/.../ArchitectureTest.java still hold under the new runtime). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Discovered via `./gradlew refreshVersions`; applied every stable
update available upstream and skipped pre-release-only tracks.
Applied (libs.versions.toml + versions.properties):
- flyway 12.3.0 -> 12.6.1 (4 patch releases bundled)
- bucket4j 8.17.0 -> 8.18.0 (minor)
- logstashLogback 8.0 -> 9.0 (major; logback ecosystem
JSON encoder, no API breakage
on our usage in
backend/logging + frontend/logging
— verified via spotless +
checkstyle + spotbugs +
Pii*Test runs)
- springdocOpenapi 3.0.2 -> 3.0.3 (patch)
- openpdf 2.0.3 -> 2.2.5 (latest 2.x stable)
Tried but reverted:
- openpdf 3.0.4 — renames com.lowagie.text.* to org.openpdf.text.*;
JobOrderHandoverReportService has 13 imports under com.lowagie.*
that would all need rewriting + smoke-testing the PDF output of
every report flow. Deferred to a focused follow-up; staying on
the latest 2.x.
Skipped (pre-release only, not production-ready):
- springBoot 4.0.6 — only 4.1.0-M1..M4 / RC1 milestones available.
- mapstruct 1.6.3 — only 1.7.0.Beta1 available.
Inline comments added to the toml so the skips are documented at
the call site (so the next refreshVersions sweep won't re-prompt
on the same pre-release tracks).
CycloneDX BOMs were regenerated as a side effect of the dep tree
shifts (logstash-logback 9.0 pulls a different logback set, flyway
12.6 bumps its postgresql adapter, etc.) — committed alongside.
Verified:
- ./gradlew :backend:compileJava :frontend:compileJava
:backend:compileTestJava :frontend:compileTestJava → SUCCESS
- ./gradlew :backend:checkstyleMain :frontend:checkstyleMain
:backend:spotlessCheck :frontend:spotlessCheck
:backend:spotbugsMain :frontend:spotbugsMain --rerun-tasks
→ BUILD SUCCESSFUL
- ./gradlew :backend:test --tests '*ArchitectureTest*' --tests '*Pii*'
:frontend:test --tests '*ArchitectureTest*' --tests '*Pii*'
→ BUILD SUCCESSFUL
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
End-to-end Checkstyle cleanup across the backend and frontend modules,
broken into five phases and now gate-protected by
./gradlew check.googleJavaFormat().reflowLongStrings()+removeUnusedImports())..git-blame-ignore-revsentry keepsgit blamehonest about authorship.publicsurface of both modules. Cleared 1 352MissingJavadoc{Type,Method}violations across models/DTOs (a+g), mappers (b), repositories (c), backend services (d), backend controllers (e), backend infrastructure (f), frontend infrastructure (h+j), and frontend page controllers (i).if/while/forbodies braced, long lines wrapped, naming conventions fixed (AbbreviationAsWordInName,LocalVariableName,CatchParameterName), method overloads grouped, empty catch blocks documented, etc.claude/youthful-saha-e3cd07— Brings in Phase 2d/2e/2f/2i from a parallel branch. Phase-3 mechanics that the-X theirsstrategy dropped were re-applied; new violations introduced by the merge (duplicate Javadocs from both branches, missing summaries on@return-only blocks) were auto-fixed by new helper scripts underbuild/.Checkstyle.isIgnoreFailures = false+maxWarnings = 0andSpotless.isEnforceCheck = true. Any new warning, any unformatted file, fails./gradlew check.Final count: 16 288 -> 1 796 -> 738 -> 0 Checkstyle violations on both modules, now permanent.
Numbers
checkstyleMain+spotlessCheck+spotbugsMain: greencheckstyleMain+spotlessCheck+spotbugsMain: green@SpringBootTestintegration tests, and TestContainers-backed tests: not run locally (Docker Desktop unavailable on dev machine — seeMEMORY.md); pure Mockito unit tests still passDeveloper impact after merge
./gradlew spotlessApplylocally before pushing; CI re-runsspotlessCheckand will fail on any unformatted file.publicAPI needs class/method Javadoc —MissingJavadocType/MissingJavadocMethodwill block the build otherwise.build/directory carries several gitignored helper scripts that automated the cleanup (star-import resolver, Javadoc inserter, summary synthesizer, duplicate-Javadoc merger, etc.). They're reusable if a future refactor introduces a similar batch problem.Test plan
./gradlew :backend:checkstyleMain :frontend:checkstyleMain --rerun-tasks-> BUILD SUCCESSFUL, 0 violations./gradlew :backend:spotlessCheck :frontend:spotlessCheck --rerun-tasks-> BUILD SUCCESSFUL, 0 format drifts./gradlew :backend:spotbugsMain :frontend:spotbugsMain --rerun-tasks-> BUILD SUCCESSFUL, both clean./gradlew :backend:compileJava :frontend:compileJava :backend:compileTestJava :frontend:compileTestJava-> BUILD SUCCESSFUL./gradlew check(including TestContainers integration tests that Docker-less local machines can't run)🤖 Generated with Claude Code