Skip to content

Commit 5fd9c17

Browse files
committed
Merge remote-tracking branch 'origin/main' into fix/bugfix-291-auto-recalculation
2 parents cb5292c + f785ed9 commit 5fd9c17

569 files changed

Lines changed: 27471 additions & 16150 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/analysis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
# provides: AbstractOracleIT starts one gvenzl/oracle-free container per JVM and applies
3636
# the test snapshot with Flyway's Java API.
3737
commands: |
38-
mvn -B -ntp -Dcheckstyle.skip=false -Dskip.integration.tests=false verify checkstyle:checkstyle
38+
mvn -B -ntp -Dskip.integration.tests=false verify
3939
dir: backend
4040
java-cache: maven
4141
java-distribution: temurin

.github/workflows/pr-open.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@ jobs:
3838
- uses: bcgov/action-builder-ghcr@cb2629351c87dd1c2130073e4ebb7233a9653a63 # v4.4.1
3939
with:
4040
package: ${{ matrix.package }}
41-
tags: ${{ github.event.number }}
41+
# The PR tag is mutable (reused every push) and is what merge.yml
42+
# deploys/promotes; the head SHA tag is immutable and is what PR
43+
# deploys use, so each push changes the pod spec and forces a rollout.
44+
tags: |
45+
${{ github.event.number }}
46+
${{ github.event.pull_request.head.sha }}
4247
tag_fallback: latest
4348
triggers: ('${{ matrix.package }}/', 'common/', '.github/workflows/')
4449
build_args: |
@@ -51,6 +56,7 @@ jobs:
5156
secrets: inherit
5257
with:
5358
target: ${{ needs.init.outputs.zone }}
59+
tag: ${{ github.event.pull_request.head.sha }}
5460
triggers: ('backend/', 'frontend/', 'common/', '.github/workflows/')
5561

5662
tests:

backend/.mvn/google_checks.xml

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@
3838
<property name="eachLine" value="true"/>
3939
</module>
4040

41-
<module name="LineLength">
42-
<property name="fileExtensions" value="java"/>
43-
<property name="max" value="100"/>
44-
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
45-
</module>
46-
4741
<module name="TreeWalker">
4842
<module name="OuterTypeFilename"/>
4943
<module name="IllegalTokenText">
@@ -238,14 +232,6 @@
238232
<message key="ws.notPreceded"
239233
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
240234
</module>
241-
<module name="Indentation">
242-
<property name="basicOffset" value="2"/>
243-
<property name="braceAdjustment" value="2"/>
244-
<property name="caseIndent" value="2"/>
245-
<property name="throwsIndent" value="4"/>
246-
<property name="lineWrappingIndentation" value="4"/>
247-
<property name="arrayInitIndent" value="2"/>
248-
</module>
249235
<module name="AbbreviationAsWordInName">
250236
<property name="ignoreFinal" value="false"/>
251237
<property name="allowedAbbreviationLength" value="0"/>
@@ -257,12 +243,6 @@
257243
<module name="NoWhitespaceBeforeCaseDefaultColon"/>
258244
<module name="OverloadMethodsDeclarationOrder"/>
259245
<module name="VariableDeclarationUsageDistance"/>
260-
<module name="CustomImportOrder">
261-
<property name="sortImportsInGroupAlphabetically" value="true"/>
262-
<property name="separateLineBetweenGroups" value="true"/>
263-
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
264-
<property name="tokens" value="IMPORT, STATIC_IMPORT, PACKAGE_DEF"/>
265-
</module>
266246
<module name="MethodParamPad">
267247
<property name="tokens"
268248
value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF,

backend/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ FROM maven:3.9.16-eclipse-temurin-21 AS build
22

33
WORKDIR /workspace
44
COPY pom.xml ./
5+
COPY .mvn ./.mvn
56
RUN mvn -B -ntp -DskipTests dependency:go-offline
67
COPY src ./src
78
RUN mvn -B -ntp package

backend/openshift.deploy.yml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ parameters:
1313
- name: IMAGE_TAG
1414
description: Image tag to use
1515
required: true
16+
# PR deploys pass the immutable head SHA as IMAGE_TAG, so every push changes
17+
# the pod spec and forces a rollout (the mutable PR-number tag would leave
18+
# `oc apply` seeing an unchanged Deployment and keep serving the stale image
19+
# despite imagePullPolicy: Always). Test deploys (merge.yml) use the
20+
# PR-number tag, which is unique per merge, so the spec changes there too.
1621
- name: REGISTRY
1722
description: Container registry to import from
1823
value: ghcr.io
@@ -31,7 +36,7 @@ parameters:
3136
- name: CPU_REQUEST
3237
value: "30m"
3338
- name: MEMORY_REQUEST
34-
value: "384Mi"
39+
value: "256Mi"
3540
- name: MEMORY_LIMIT
3641
description: Container memory limit; the JVM heap sizes itself from this cgroup limit via MaxRAMPercentage (see backend/Dockerfile). Raised for the embedded JasperReports 7 engine (Batik/OpenPDF/fonts add classpath + metaspace + native AWT footprint) per AD-16 "size the reporting path's pod CPU/Mem".
3742
value: "1Gi"
@@ -137,6 +142,11 @@ objects:
137142
value: "true"
138143
- name: ILCR_DATASOURCE_ENABLED
139144
value: ${ILCR_DATASOURCE_ENABLED}
145+
# Story 29.2 — point the Jasper report virtualizer's swap file at the dedicated
146+
# DISK-backed ephemeral volume below, NOT java.io.tmpdir (/tmp here is a Memory-backed
147+
# emptyDir, so spilling there would stay in RAM and defeat the heap relief).
148+
- name: ILCR_REPORTING_SWAP_DIR
149+
value: /var/tmp/report-swap
140150
- name: ORACLEDB_HOST
141151
valueFrom:
142152
secretKeyRef:
@@ -182,9 +192,13 @@ objects:
182192
requests:
183193
cpu: ${CPU_REQUEST}
184194
memory: ${MEMORY_REQUEST}
185-
ephemeral-storage: "200Mi"
195+
ephemeral-storage: "256Mi"
186196
limits:
187197
memory: ${MEMORY_LIMIT}
198+
# Bound total ephemeral (node) storage: base image scratch + the 512Mi report-swap
199+
# volume below (Story 29.2). A print that would exceed this is evicted — a bounded,
200+
# observable failure — rather than filling node disk.
201+
ephemeral-storage: "1Gi"
188202
securityContext:
189203
allowPrivilegeEscalation: false
190204
runAsNonRoot: true
@@ -196,6 +210,8 @@ objects:
196210
volumeMounts:
197211
- name: tmp
198212
mountPath: /tmp
213+
- name: report-swap
214+
mountPath: /var/tmp/report-swap
199215
- name: api-cert
200216
mountPath: /cert
201217
startupProbe:
@@ -221,6 +237,15 @@ objects:
221237
emptyDir:
222238
medium: Memory
223239
sizeLimit: 256Mi
240+
# Story 29.2 — dedicated DISK-backed ephemeral volume for the Jasper report swap file.
241+
# Deliberately NOT medium: Memory (unlike /tmp above): spilling large report page objects
242+
# here relieves the JVM heap onto node ephemeral storage instead of RAM, which is the whole
243+
# point of the virtualizer. Bounded by sizeLimit so a runaway print is evicted (a bounded,
244+
# observable failure) rather than silently consuming node disk. Writable despite the
245+
# read-only root filesystem because it is a mounted volume.
246+
- name: report-swap
247+
emptyDir:
248+
sizeLimit: 512Mi
224249
# Oracle keystore written by the init container, read by the app
225250
- name: api-cert
226251
persistentVolumeClaim:

backend/pom.xml

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,15 @@
6161
<skip.integration.tests>true</skip.integration.tests>
6262
<skip.unit.tests>false</skip.unit.tests>
6363
<jacoco.skip>false</jacoco.skip>
64-
<checkstyle.skip>true</checkstyle.skip>
65-
<checkstyle.failsOnError>false</checkstyle.failsOnError>
64+
<checkstyle.skip>false</checkstyle.skip>
65+
<checkstyle.failsOnError>true</checkstyle.failsOnError>
6666
<checkstyle.includeTestSourceDirectory>false</checkstyle.includeTestSourceDirectory>
6767
<cyclonedx.skip>false</cyclonedx.skip>
6868
<commons-lang3.version>3.20.0</commons-lang3.version>
6969
<jasperreports.version>7.0.8</jasperreports.version>
7070
<sonar.organization>bcgov-sonarcloud</sonar.organization>
7171
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
72+
<sonar.java.checkstyle.reportPaths>target/checkstyle-result.xml</sonar.java.checkstyle.reportPaths>
7273
<!-- Keep Sonar coverage measurement in step with the jacoco instrumentation excludes
7374
below: config/dto/exception/boilerplate are not instrumented, so counting them as
7475
uncovered would understate new-code coverage for lines jacoco never reports on. -->
@@ -510,6 +511,29 @@
510511
</execution>
511512
</executions>
512513
</plugin>
514+
<plugin>
515+
<groupId>com.diffplug.spotless</groupId>
516+
<artifactId>spotless-maven-plugin</artifactId>
517+
<version>2.44.3</version>
518+
<configuration>
519+
<java>
520+
<googleJavaFormat>
521+
<version>1.25.2</version>
522+
<style>GOOGLE</style>
523+
</googleJavaFormat>
524+
<formatAnnotations />
525+
</java>
526+
</configuration>
527+
<executions>
528+
<execution>
529+
<id>spotless-check</id>
530+
<phase>validate</phase>
531+
<goals>
532+
<goal>check</goal>
533+
</goals>
534+
</execution>
535+
</executions>
536+
</plugin>
513537
<plugin>
514538
<groupId>org.apache.maven.plugins</groupId>
515539
<artifactId>maven-checkstyle-plugin</artifactId>
@@ -532,7 +556,7 @@
532556
<executions>
533557
<execution>
534558
<id>validate</id>
535-
<phase>checkstyle</phase>
559+
<phase>validate</phase>
536560
<goals>
537561
<goal>check</goal>
538562
</goals>

backend/src/main/java/ca/bc/gov/nrs/ilcr/BackendConstants.java

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,46 +4,40 @@
44
import lombok.NoArgsConstructor;
55

66
/**
7-
* Application-wide constants: SQL parameter placeholders, sentinel values, and shared
8-
* security path lists.
7+
* Application-wide constants: SQL parameter placeholders, sentinel values, and shared security path
8+
* lists.
99
*
1010
* <p>The token values in this class indicate an absent or unspecified value (for example when
11-
* binding query parameters) and a placeholder client identifier used when no client is
12-
* available. The path arrays centralize the request matchers referenced by the security
13-
* configuration.</p>
11+
* binding query parameters) and a placeholder client identifier used when no client is available.
12+
* The path arrays centralize the request matchers referenced by the security configuration.
1413
*
15-
* <p>This class is not instantiable and only exposes static constant values.</p>
14+
* <p>This class is not instantiable and only exposes static constant values.
1615
*/
1716
@NoArgsConstructor(access = AccessLevel.PRIVATE)
1817
public class BackendConstants {
1918

2019
/**
2120
* Token representing a missing or unspecified value when interacting with legacy queries.
2221
*
23-
* <p>Used in SQL where clauses and parameter binding to indicate the absence of a filter
24-
* value.</p>
22+
* <p>Used in SQL where clauses and parameter binding to indicate the absence of a filter value.
2523
*/
2624
public static final String NOVALUE = "NOVALUE";
2725

2826
/**
2927
* Token representing the absence of a client value.
3028
*
31-
* <p>Used as a fallback client identifier in places where a client list is required but
32-
* none are available.</p>
29+
* <p>Used as a fallback client identifier in places where a client list is required but none are
30+
* available.
3331
*/
3432
public static final String NOCLIENT = "NOCLIENT";
3533

3634
/**
3735
* Paths permitted without authentication regardless of whether security is enabled.
3836
*
39-
* <p>Referenced by the security filter chain to allow the API root, health, info, and
40-
* metrics endpoints.</p>
37+
* <p>Referenced by the security filter chain to allow the API root, health, info, and metrics
38+
* endpoints.
4139
*/
4240
public static final String[] PUBLIC_PATHS = {
43-
"/api",
44-
"/api/health",
45-
"/api/health/**",
46-
"/api/info",
47-
"/api/prometheus"
41+
"/api", "/api/health", "/api/health/**", "/api/info", "/api/prometheus"
4842
};
4943
}

backend/src/main/java/ca/bc/gov/nrs/ilcr/HealthCheck.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@
44
import java.net.URI;
55
import java.time.Duration;
66

7+
/** Simple application health check utility. */
78
public final class HealthCheck {
89
private static final int HEALTHY = 0;
910
private static final int UNHEALTHY = 1;
1011

1112
private HealthCheck() {}
1213

14+
/**
15+
* Main entry point for the health check.
16+
*
17+
* @param args command line arguments
18+
*/
1319
public static void main(String[] args) {
1420
try {
1521
int port = Integer.parseInt(System.getenv().getOrDefault("SERVER_PORT", "8080"));

backend/src/main/java/ca/bc/gov/nrs/ilcr/IlcrBackendApplication.java

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@
44
import org.springframework.boot.SpringApplication;
55
import org.springframework.boot.autoconfigure.SpringBootApplication;
66

7+
/** The main entry point for the ILCR Backend Application. */
78
@SpringBootApplication
89
public class IlcrBackendApplication {
910

10-
public static void main(String[] args) {
11-
// Anchor the JVM to Pacific BEFORE the context refreshes. The app serves the BC Ministry of
12-
// Forests, but its OpenShift containers default to UTC, which shifts date boundaries
13-
// (reporting-year rollover, SYSDATE/audit timestamps read as java.util.Date). Setting it here
14-
// — ahead of SpringApplication.run — is deterministic: logging init, the Hikari pool, and every
15-
// bean's @PostConstruct all observe Pacific, with no startup window left in UTC. Deploy may
16-
// also set TZ=America/Vancouver on the container; this guarantees it even when it doesn't.
17-
TimeZone.setDefault(TimeZone.getTimeZone("America/Vancouver"));
18-
SpringApplication.run(IlcrBackendApplication.class, args);
19-
}
11+
/**
12+
* The main method to start the Spring Boot application.
13+
*
14+
* @param args the command line arguments
15+
*/
16+
public static void main(String[] args) {
17+
// Anchor the JVM to Pacific BEFORE the context refreshes. The app serves the BC Ministry of
18+
// Forests, but its OpenShift containers default to UTC, which shifts date boundaries
19+
// (reporting-year rollover, SYSDATE/audit timestamps read as java.util.Date). Setting it here
20+
// — ahead of SpringApplication.run — is deterministic: logging init, the Hikari pool, and every
21+
// bean's @PostConstruct all observe Pacific, with no startup window left in UTC. Deploy may
22+
// also set TZ=America/Vancouver on the container; this guarantees it even when it doesn't.
23+
TimeZone.setDefault(TimeZone.getTimeZone("America/Vancouver"));
24+
SpringApplication.run(IlcrBackendApplication.class, args);
25+
}
2026
}

backend/src/main/java/ca/bc/gov/nrs/ilcr/assignment/MillUserProfileXrefEntity.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
/**
1010
* Spring Data JDBC row shape for {@code THE.ILCR_MILL_USER_PROFILE_XREF} — one submitter↔mill
1111
* assignment (Story 2.1, AD-3). FAM is the source of truth for identity: {@code USER_GUID} is the
12-
* FAM {@code custom:idp_user_id} (32-char IDIR/BCeID GUID, Story 1.0), with no FK to any user table.
13-
* {@code USER_DISPLAY_NAME}/{@code IDP_USERNAME} are snapshotted from FAM at assign time (Q5) so an
14-
* ended assignment whose user has left FAM still renders. {@code END_DATE} null ⇒ ACTIVE.
12+
* FAM {@code custom:idp_user_id} (32-char IDIR/BCeID GUID, Story 1.0), with no FK to any user
13+
* table. {@code USER_DISPLAY_NAME}/{@code IDP_USERNAME} are snapshotted from FAM at assign time
14+
* (Q5) so an ended assignment whose user has left FAM still renders. {@code END_DATE} null ⇒
15+
* ACTIVE.
1516
*
16-
* <p>{@link MillUserProfileXrefRepository} reads these; the service maps them to the wire
17-
* {@code MillSubmitter} DTO (Story 2.2 — entities never cross the service boundary).
17+
* <p>{@link MillUserProfileXrefRepository} reads these; the service maps them to the wire {@code
18+
* MillSubmitter} DTO (Story 2.2 — entities never cross the service boundary).
1819
*/
1920
@Table(name = "ILCR_MILL_USER_PROFILE_XREF", schema = "THE")
2021
public record MillUserProfileXrefEntity(
@@ -29,5 +30,4 @@ public record MillUserProfileXrefEntity(
2930
@Column("ENTRY_USERID") String entryUserid,
3031
@Column("ENTRY_TIMESTAMP") LocalDateTime entryTimestamp,
3132
@Column("UPDATE_USERID") String updateUserid,
32-
@Column("UPDATE_TIMESTAMP") LocalDateTime updateTimestamp) {
33-
}
33+
@Column("UPDATE_TIMESTAMP") LocalDateTime updateTimestamp) {}

0 commit comments

Comments
 (0)