|
| 1 | +# OpenESPI GreenButton Java - Project Guidelines |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +This is a complete monorepo implementation of the NAESB Energy Services Provider Interface (ESPI) 4.0 specification for Green Button energy data standards. The project provides OAuth2-based energy data exchange capabilities between utilities, third-party applications, and consumers. |
| 6 | + |
| 7 | +**Key Technologies:** |
| 8 | +- Java 21 (LTS) |
| 9 | +- Spring Boot 3.5.0 (Jakarta EE 9+) |
| 10 | +- Maven 3.9+ multi-module build |
| 11 | +- OAuth2 authorization framework |
| 12 | +- Green Button energy data standards |
| 13 | + |
| 14 | +## Project Structure |
| 15 | + |
| 16 | +The project is organized as a Maven multi-module monorepo with 4 main modules: |
| 17 | + |
| 18 | +### Core Modules |
| 19 | +- **`openespi-common/`** - Shared domain models, services, and utilities (Production ready) |
| 20 | +- **`openespi-datacustodian/`** - OAuth2 resource server for energy data (Production ready) |
| 21 | +- **`openespi-authserver/`** - OAuth2 authorization server (Production ready) |
| 22 | +- **`openespi-thirdparty/`** - Client application (Partial Spring Boot migration) |
| 23 | + |
| 24 | +### Module Dependencies |
| 25 | +``` |
| 26 | +openespi-thirdparty ──┐ |
| 27 | +openespi-datacustodian ├──► openespi-common |
| 28 | +openespi-authserver ──┘ |
| 29 | +``` |
| 30 | + |
| 31 | +### Key Directories |
| 32 | +- `src/main/java/` - Java source code |
| 33 | +- `src/main/resources/` - Configuration files, templates |
| 34 | +- `src/test/java/` - Unit and integration tests |
| 35 | +- `etc/` - Database scripts (init, cleanup, seed data) |
| 36 | +- `docker/` - Docker configuration (authserver only) |
| 37 | +- `target` - Directory for build artifacts. DO NOT EDIT FILES IN THIS DIRECTORY |
| 38 | + |
| 39 | +## Testing Requirements |
| 40 | + |
| 41 | +**Always run tests** to verify correctness of proposed solutions: |
| 42 | + |
| 43 | +### Running Tests |
| 44 | +```bash |
| 45 | +# Test all modules |
| 46 | +mvn clean test |
| 47 | + |
| 48 | +# Test specific module with dependencies |
| 49 | +mvn test -pl openespi-datacustodian -am |
| 50 | + |
| 51 | +# Test only Spring Boot 3.5 modules |
| 52 | +mvn test -Pspring-boot-only |
| 53 | + |
| 54 | +# Module-specific testing |
| 55 | +cd openespi-common && mvn test |
| 56 | +cd openespi-datacustodian && mvn test -am |
| 57 | +cd openespi-authserver && mvn test -am |
| 58 | +``` |
| 59 | + |
| 60 | +### Test Categories |
| 61 | +- **Unit tests** - Fast, isolated component testing |
| 62 | +- **Integration tests** - Database and service integration |
| 63 | +- **OAuth2 flow tests** - Authorization and token exchange |
| 64 | +- **Green Button compliance tests** - ESPI specification adherence |
| 65 | + |
| 66 | +## Build Instructions |
| 67 | + |
| 68 | +**Build the project** before submitting results to ensure compilation success: |
| 69 | + |
| 70 | +### Standard Build |
| 71 | +```bash |
| 72 | +# Build all modules (recommended) |
| 73 | +mvn clean install |
| 74 | + |
| 75 | +# Build only production-ready Spring Boot 3.5 modules |
| 76 | +mvn clean install -Pspring-boot-only |
| 77 | +``` |
| 78 | + |
| 79 | +### Development Build |
| 80 | +```bash |
| 81 | +# Quick compile without tests |
| 82 | +mvn clean compile |
| 83 | + |
| 84 | +# Package without running tests (use sparingly) |
| 85 | +mvn clean package -DskipTests |
| 86 | +``` |
| 87 | + |
| 88 | +### Running Applications |
| 89 | +```bash |
| 90 | +# Data Custodian (port 8080) |
| 91 | +cd openespi-datacustodian && mvn spring-boot:run |
| 92 | + |
| 93 | +# Authorization Server (port 8081) |
| 94 | +cd openespi-authserver && mvn spring-boot:run |
| 95 | + |
| 96 | +# Third Party (port 8082) |
| 97 | +cd openespi-thirdparty && mvn spring-boot:run |
| 98 | +``` |
| 99 | + |
| 100 | +## Code Style Guidelines |
| 101 | + |
| 102 | +### Java Standards |
| 103 | +- **Java 21** features encouraged (records, pattern matching, text blocks) |
| 104 | +- **Jakarta EE 9+** APIs (jakarta.* packages, not javax.*) |
| 105 | +- **Spring Boot 3.5** patterns and conventions |
| 106 | +- **Maven** standard directory layout |
| 107 | + |
| 108 | +### Naming Conventions |
| 109 | +- Classes: `PascalCase` (e.g., `UsagePointService`) |
| 110 | +- Methods/Variables: `camelCase` (e.g., `findByRetailCustomerId`) |
| 111 | +- Constants: `UPPER_SNAKE_CASE` (e.g., `DEFAULT_TIMEOUT`) |
| 112 | +- Packages: `lowercase.with.dots` (e.g., `org.greenbuttonalliance.espi.common`) |
| 113 | + |
| 114 | +### Architecture Patterns |
| 115 | +- **Service Layer** - Business logic in `*Service` interfaces with `*ServiceImpl` implementations |
| 116 | +- **Repository Layer** - Data access via Spring Data JPA repositories |
| 117 | +- **Controller Layer** - REST endpoints with proper HTTP status codes |
| 118 | +- **DTO Pattern** - Data transfer objects for API boundaries |
| 119 | + |
| 120 | +### Spring Boot Conventions |
| 121 | +- Use `@Service`, `@Repository`, `@Controller` annotations |
| 122 | +- Configuration via `application.yml` (preferred over `.properties`) |
| 123 | +- Profile-specific configs: `application-{profile}.yml` |
| 124 | +- Auto-configuration over manual bean definitions |
| 125 | + |
| 126 | +### Testing Standards |
| 127 | +- Test classes end with `Test` or `Tests` |
| 128 | +- Use `@SpringBootTest` for integration tests |
| 129 | +- Use `@MockBean` for mocking Spring components |
| 130 | +- Arrange-Act-Assert pattern in test methods |
| 131 | + |
| 132 | +## Migration Status Awareness |
| 133 | + |
| 134 | +When working on the project, be aware of the migration status: |
| 135 | + |
| 136 | +### Production Ready (Spring Boot 3.5) |
| 137 | +- `openespi-common` - Full Spring Boot 3.5 migration ✅ |
| 138 | +- `openespi-datacustodian` - Full Spring Boot 3.5 migration ✅ |
| 139 | +- `openespi-authserver` - Full Spring Boot 3.5 migration ✅ |
| 140 | + |
| 141 | +### Partial Migration |
| 142 | +- `openespi-thirdparty` - Java 21 + Jakarta ready, Spring Boot migration in progress ⚠️ |
| 143 | + |
| 144 | +### Special Considerations |
| 145 | +- When modifying `openespi-thirdparty`, be mindful of ongoing Spring Boot migration |
| 146 | +- Prefer Jakarta EE APIs over legacy javax APIs |
| 147 | +- Use Spring Boot 3.5 patterns in production-ready modules |
| 148 | + |
| 149 | +## Java Coding Hints and Conventions |
| 150 | +* The @MockBean annotation is deprecated. Use @MockitoBean instead. |
| 151 | +* When writing unit tests, verify any required properties have values, unless testing an exception condition. |
| 152 | +* When writing unit tests, be sure to test exception conditions, such as validation constraint errors, and ensure the correct exception is thrown. |
| 153 | +* When writing unit tests for classes which implement an interface NEVER create a test implementation of the interface for the class under test. |
| 154 | +* When adding properties to JPA entities or DTOs, add the new properties after other properties, but above the user, dateCreated, and dateUpdated properties. |
| 155 | + |
| 156 | +## Spring Conventions |
| 157 | +* For dependency injection, favor using private final variables in conjunction with Lombok's @RequiredArgsConstructor. |
| 158 | + |
| 159 | +### DTO Conventions |
| 160 | +- Use DTOs for Spring MVC controllers |
| 161 | +- Name DTOs with `Dto` suffix |
| 162 | +- For HTTP Get and List operations use <classname>Dto |
| 163 | +- For HTTP Create operations use <classname>Dto. Do not add the id, version, createdDate, or dateUpdated properties to the creation DTO. Ignore the id, version, createdDate, and dateUpdated these properties in MapStruct mappings. |
| 164 | +- For HTTP Update operations use <classname>Dto. The update DTO should NOT include the id, createdDate, and dateUpdated properties. The version property should be used to check for optimistic locking. |
| 165 | +- For HTTP Patch operations use <classname>Dto. The patch DTO should NOT include the id, createdDate, and dateUpdated properties. The version property should be used to check for optimistic locking. Patch operations should be used to update a single property. The PatchDTO should NOT have validation annotations preventing null or empty values. |
| 166 | + |
| 167 | +### JPA Conventions |
| 168 | +- Use an `Interger` version property annotated with `@Version` for optimistic locking |
| 169 | +- When mapping enumerations to database columns, use `@Enumerated(EnumType.STRING)` to store the enum name instead of the ordinal value. |
| 170 | +- Use a property named `createdDate` of type `LocalDateTime` with `@CreationTimestamp` for the creation date. The column description should use `updatabele = false` to prevent updates to the createdDate property. |
| 171 | +- Use a property named `dateUpdated` of type `LocalDateTime` with `@UpdateTimestamp` for the last update date. |
| 172 | +- Do not use the Lombok `@Data` annotation on JPA entities. Use `@Getter` and `@Setter` instead. |
| 173 | +- Do not add the '@Repository' annotation to the repository interface. The Spring Data JPA will automatically create the implementation at runtime. |
| 174 | +- Use the `@Transactional` annotation on the service class to enable transaction management. The `@Transactional` annotation should be used on the service class and not on the repository interface. |
| 175 | +- Use the `@Transactional(readOnly = true)` annotation on the read-only methods of the service class to enable read-only transactions. This will improve performance and reduce locking on the database. |
| 176 | +- When adding methods to the repository interface, try to avoid using the `@Query` annotation. Use the Spring Data JPA method naming conventions to create the query methods. This will improve readability and maintainability of the code. |
| 177 | +- In services when testing the return values of optionals, throw the `NotFoundException` if the optional is empty. This will provide a 404 response to the client. The `NotFoundException` should be thrown in the service class and not in the controller class. |
| 178 | + |
| 179 | +### Mapstruct Conventions |
| 180 | +- When creating mappers for patch operations, use the annotation `@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)` to ignore null values in the source object. This will prevent null values from overwriting existing values in the target object. |
| 181 | +- Mapper implementations are generated at compile time. If the context is not loading because of missing dependencies, compile java/main to generate the mappers. |
| 182 | + |
| 183 | +### Unit Test Conventions |
| 184 | +- When creating unit tests, use datafaker to generate realistic test data values. |
| 185 | +- When creating or updating tests, use the Junit `@DisplayName` annotation to provide a human readable name for the test. This will improve the quality of the test report. |
| 186 | +- When creating or updating tests, use the Junit `@Nested` annotation to group related tests. This will improve the readability of the test report. |
| 187 | +- When investigating test failures of transaction tests, verify the service implementation uses saveAndFlush() to save the entity. This will ensure the entity is saved to the database before the transaction is committed. |
0 commit comments