Repository navigation
Backend Structure
backend-applications/
|- nr-waste-plus-backend/ # Spring Boot 4 BFF (PostgreSQL + external providers)
| |- src/main/java/ca/bc/gov/nrs/hrs/
| | |- BackendApplication.java # @SpringBootApplication entry point
| | |- configuration/ # app config, security chain, metrics, CORS
| | |- controller/ # /api/codes, /api/forest-clients, /api/search, /api/users
| | |- dto/
| | | |- base/ # shared enums and base records
| | | |- client/ # forest client API contracts
| | | \- search/ # reporting unit and search contracts
| | |- entity/
| | | \- users/ # user preference persistence entities (preferences, bookmarks)
| | |- exception/ # ResponseStatusException hierarchy
| | |- provider/
| | | |- forestclient/ # forest client facade + clients
| | | |- legacy/ # legacy facade + clients
| | | \- forwarders/ # JWT and B3 propagation
| | |- repository/ # Spring Data repositories
| | |- security/ # customizers, role checks, auditor
| | |- service/ # business orchestration services
| | \- util/ # JWT, URI, and environment utilities
| \- src/test/java/ca/bc/gov/nrs/hrs/
| |- controller/ # integration tests by endpoint group
| |- provider/ # integration/unit tests by upstream group
| |- security/ # authorization and role tests
| |- util/ # utility unit tests
| \- extensions/ # Testcontainers + @WithMockJwt support
|
\- nr-waste-plus-legacy/ # Spring Boot 3 Oracle-backed service
|- src/main/java/ca/bc/gov/nrs/hrs/
| |- LegacyApplication.java # @SpringBootApplication entry point
| |- configuration/ # app config, security chain, metrics, graceful shutdown
| |- controller/ # /api/codes and /api/search
| |- dto/
| | |- base/ # identity, roles, code description
| | \- search/ # reporting unit and client search contracts
| |- entity/
| | |- codes/ # Oracle code-table entities
| | |- reportingunit/ # reporting unit entity
| | \- search/ # projection interfaces
| |- exception/ # domain-specific HTTP exceptions
| |- mappers/ # MapStruct mapper interfaces/implementations
| |- repository/
| | |- codes/ # code-table repositories
| | \- *.java # native-query repositories + SQL constants
| |- security/ # customizers, role checker, auditor
| |- service/
| | |- codes/ # district/sampling/status services
| | \- search/ # reporting and advanced search services
| \- util/ # JWT and pagination helpers
\- src/test/java/ca/bc/gov/nrs/hrs/
|- controller/ # MockMvc integration tests
|- mappers/ # mapping-specific unit tests
|- security/ # role and authorization tests
|- util/ # JWT and pagination unit tests
\- extensions/ # Oracle container + custom JWT test context
Both backends use the same core package layering:
-
controller/for HTTP concerns and endpoint composition -
service/for business rules and orchestration -
repository/orprovider/for data access and integrations -
dto/for API contracts -
security/for filter-chain customizers and role logic -
configuration/for bean and framework wiring -
exception/for HTTP-aware domain failures -
util/for cross-cutting helper utilities
| Layer | Spring Boot 4 backend | Spring Boot 3 legacy |
|---|---|---|
| Integration edge |
provider/ facade to Forest Client API and Legacy API |
mostly native SQL in repository/
|
| Persistence | compact PostgreSQL model for user preferences | Oracle schema access with projections and native queries |
| Mapping | mostly inline/manual mapping in services/providers | explicit mappers/ package (MapStruct-centric) |
| Search domain | external-orchestrated + enrichment | core domain capability with query-heavy repository layer |
- Keep root package as
ca.bc.gov.nrs.hrs. - Use singular role folders unless domain grouping is explicit.
- Group by technical layer first, then by domain where needed (
service/codes,service/search). - Keep test package paths aligned with production packages.
| Type | Naming pattern | Examples |
|---|---|---|
| Application entrypoint | *Application |
BackendApplication, LegacyApplication
|
| Configuration | *Configuration |
SecurityConfiguration, HrsMetricConfiguration
|
| Controller | *Controller |
SearchController, CodesController
|
| Service | *Service |
ReportingUnitSearchService, UserService
|
| Repository | *Repository |
UserPreferenceRepository, OrgUnitRepository
|
| Provider/Client |
*Provider, *Client
|
LegacyApiProvider, ForestClientFetchClient
|
| Mapper | *Mapper |
DistrictMapper, ReportingUnitSearchMapper
|
| Exception |
*Exception (or existing domain-aligned names) |
UserNotFoundException |
| Utility | *Util |
JwtPrincipalUtil, PaginationUtil
|
- Keep DTOs in
dto/<domain>/packages (base,search,client). - Prefer immutable record DTOs for response payloads.
- Keep enums under
dto/baseor feature-specific DTO subpackages. - Use clear suffixes for discoverability:
*Dto,*ResultDto,*ParametersDto.
When introducing new backend features, follow this baseline shape:
ca/bc/gov/nrs/hrs/
|- controller/
| \- <Feature>Controller.java
|- service/
| \- <feature>/
| \- <Feature>Service.java
|- dto/
| \- <feature>/
| |- <Feature>RequestDto.java
| \- <Feature>ResponseDto.java
|- repository/ or provider/
| \- <feature>/
| \- <Feature>Repository.java or <Feature>Provider.java
|- exception/
| \- <Feature>ErrorException.java
\- src/test/java/ca/bc/gov/nrs/hrs/
|- controller/
|- service/ or provider/
\- <feature>/
Required expectations:
- Expose only controller-facing DTOs at API boundaries.
- Keep business logic in services, not controllers.
- Keep data-access and upstream-calling details out of services when a provider/repository boundary exists.
- Mirror package changes in tests.
- Preserve existing security and observability annotations/patterns.
-
provider/exists in backend and is a first-class anti-corruption layer. -
mappers/exists in legacy and is central to projection-to-DTO translation. -
repository/in legacy contains heavier SQL query responsibilities than backend. -
entity/in backend is currently minimal; legacy has broader Oracle model coverage.
These differences are expected given runtime and data-source responsibilities.
- Standardize
mapper/versusmappers/naming when both services can align without disruptive refactor. - Split oversized utility classes into focused units (claims, roles, principal identity, pagination).
- Keep SQL constants close to repositories but consider per-feature query modules as native SQL grows.
- Introduce
@ControllerAdviceif exception mapping complexity increases across endpoints. - Revisit entity package depth (
entity/usersvsentity/) as backend domain model expands.
These rules apply to both backend applications and represent the architectural contract that all code contributions must respect.
- No business logic in controllers.
- No entity exposure outside the persistence layer.
- No
@Transactionalon controllers. - Controllers must delegate to services; services delegate to repository or provider boundaries.
- No direct upstream HTTP calls from controllers.
- No field injection with
@Autowired. - Use constructor injection via
@RequiredArgsConstructoror@AllArgsConstructor. - Use
@Service,@Repository, or@Configurationover@Componentwhen the role is clear. - Do not use multiple
@Valueproperties for a group of related configuration values — use@ConfigurationPropertiesinstead. - No circular dependencies.
Allowed exception:
- Abstract MapStruct mapper classes where the framework requires field injection for abstract mapper wiring.
- No
@CrossOriginon controllers. - All new endpoints must be explicitly covered by route authorization rules.
- JWT role and claim extraction must remain within
security/orutil/package boundaries. - Do not bypass configured security customizers with ad-hoc filters.
- Avoid
FetchType.EAGERunless explicitly justified in comments. - Avoid
CascadeType.ALLunless explicitly justified in comments. - Prefer explicit
mappedByand ownership declarations on relationships. - Keep native SQL within repository modules and documented inline.
- Multi-write service operations must define transaction boundaries.
- No
System.out.printlnin any application code. - No wildcard imports.
- No static mutable state in utility classes.
- Classes exceeding 300 lines require a documented decomposition plan.
- No
@Scheduledused outside a dedicatedscheduler/package. - No
@Asyncwithout explicit executor bean configuration.
- No H2 for integration tests where Oracle or PostgreSQL behavior is required.
- No
@SpringBootTestfor pure unit tests. - No mocked repositories inside integration tests that are meant to validate persistence or query behavior.
- Testcontainers should use a reusable static container per test suite.
- Use
@DynamicPropertySourceto wire container-provided datasource properties. - Use descriptive test names;
@DisplayNameis recommended for integration tests.
Use this checklist when reviewing changes to code in any layer.
- No complex business logic blocks.
- Response types are DTOs or view models, not entities.
- No
@Transactionalannotation. - Dependencies point only toward services, injected via constructor.
- Orchestration and business rules remain in services.
- No HTTP or controller concerns in service classes.
- Multi-write paths define transaction boundaries.
- Observability annotations are consistent with existing service pattern.
- Provider facade pattern is used for all external API calls in the backend.
- Native SQL stays within repository and query-constant modules in the legacy service.
- No N+1 call or query patterns; flag for batching or caching where found.
- JPA annotations are explicit and safe.
- Optimistic locking applied where concurrent writes are possible.
- Projection interfaces are placed and named consistently with existing patterns.
- Route-level authorization rules cover any new endpoint.
- Role checks and claim mapping are centralized, not duplicated in controllers or services.
- No local bypasses of the configured security filter chain.
- Test type matches the layer under test (unit or integration).
- Testcontainers used for all DB-coupled integration tests.
- Security changes include corresponding JWT-based integration test coverage.
When reviewing a change for architectural compliance:
- Identify the layer or package each changed file belongs to.
- Check each file against the rules and checklist for its layer.
- Categorize any violations using the taxonomy below.
- Assign severity and document file, line, issue, and recommendation.
| Category | Description |
|---|---|
| Layering and Boundaries | Business logic, entity exposure, or HTTP concerns in the wrong layer |
| Spring Configuration and Dependency Injection | Field injection, wrong stereotype, or @Value misuse |
| API Contract and DTO Boundaries | Entity returned from controller, missing DTO packaging |
| Persistence and JPA/Hibernate | Fetch strategy, cascade, native SQL placement |
| Security and Authorization | Missing route coverage, bypassed filter, JWT logic in wrong layer |
| Observability and Reliability | Missing tracing annotations, unhandled exceptions, silent failures |
| Testing Strategy and Testcontainers | H2 use, missing Testcontainers, wrong test type |
| Naming and Packaging Conventions | Incorrect suffix, wrong package, inconsistent naming |
| Build and Deployment Architecture | Profile, plugin, or deployment manifest inconsistencies |
| Severity | Meaning |
|---|---|
| CRITICAL | Must be resolved before merge; breaks architectural contract, security, or correctness |
| WARNING | Should be resolved soon; degrades maintainability or consistency |
| SUGGESTION | Improvement opportunity with no immediate risk |
When proposing a refactor, provide:
- File path and line number
- Current behavior (what)
- Architectural problem (why)
- Proposed fix (how)
- Risk and migration impact
This wiki documents NR Waste Plus for users and developers. Verify security and deployment guidance against the current application configuration before applying it elsewhere.
- Report an issue or ask a question in the GitHub repository.
- Follow the Contributing Guidelines to propose an update.
- Read the Code of Conduct.
Collection indexes support human browsing and machine retrieval. Keep both current when adding or moving wiki pages.
NR Waste Plus Wiki | GitHub Repository