This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
OpenESPI-GreenButton-Java is a monorepo implementation of the NAESB Energy Services Provider Interface (ESPI) 4.0 specification for Green Button energy data standards. The project has been migrated to Java 25, Jakarta EE 10+, and Spring Boot 4.0.
# From repository root - builds all modules (common, datacustodian, thirdparty, authserver)
mvn clean install
# Build only core modules (common, datacustodian, thirdparty) - omits authserver
mvn clean install -Pspring-boot-only# Test all modules
mvn test
# Test specific module with dependencies
mvn test -pl openespi-datacustodian -am
# Test specific module only
cd openespi-common && mvn test
# Integration tests with TestContainers (requires Docker)
mvn verify -pl openespi-common -Pintegration-tests# Data Custodian (default: dev-mysql profile)
cd openespi-datacustodian && mvn spring-boot:run
# With specific profile
cd openespi-datacustodian && mvn spring-boot:run -Dspring-boot.run.profiles=dev-postgresql
# Authorization Server
cd openespi-authserver && mvn spring-boot:run
# Third Party
cd openespi-thirdparty && mvn spring-boot:run# Run specific test class
mvn test -Dtest=UsagePointRepositoryTest
# Run specific test method
mvn test -Dtest=UsagePointRepositoryTest#testFindById
# Run test in specific module
mvn test -pl openespi-common -Dtest=UsagePointRepositoryTestThe monorepo follows a layered architecture with these dependencies:
- openespi-common → Foundation library (no dependencies on other modules)
- openespi-datacustodian → Depends on openespi-common
- openespi-authserver → Independent module (NO dependency on openespi-common)
- openespi-thirdparty → Depends on openespi-common
IMPORTANT: The Authorization Server (openespi-authserver) is completely independent and does NOT depend on openespi-common. It has its own entity definitions, repositories, and services for OAuth2 authorization.
The domain model is organized in openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/:
- domain/common/ - Shared base entities (IdentifiedObject, LinkType, etc.)
- domain/usage/ - ESPI energy usage entities (UsagePoint, MeterReading, IntervalBlock, ReadingType, RetailCustomer, etc.)
- domain/customer/ - Customer entities from customer.xsd schema (CustomerAccount, CustomerAgreement, ServiceSupplier, Meter, etc.)
All ESPI domain entities extend IdentifiedObject which provides:
- UUID primary key (
id) - Self-reference URI (
selfLink) - Up-reference URI (
upLink) - XML marshalling support
Services follow a consistent interface-implementation pattern:
- Interfaces:
openespi-common/src/main/java/org/greenbuttonalliance/espi/common/service/ - Implementations:
openespi-common/src/main/java/org/greenbuttonalliance/espi/common/service/impl/
Services are organized by domain:
Usage Domain Services (energy data from usage.xsd):
UsagePointService- Energy usage point managementMeterReadingService- Meter reading dataIntervalBlockService- Time-series interval dataReadingTypeService- Reading type metadataUsageSummaryService- Usage aggregation summariesElectricPowerQualitySummaryService- Power quality metricsTimeConfigurationService- Timezone and time parametersRetailCustomerService- Retail customer management (part of usage.xsd)
Customer Domain Services (from customer.xsd, in service/customer/):
CustomerAccountService- Customer account managementCustomerService- Customer informationMeterService- Meter device informationServiceLocationService- Service location dataStatementService- Billing statements
Note: Entities exist for CustomerAgreement and ServiceSupplier but services have not been implemented yet.
Cross-Cutting Services:
AuthorizationService- OAuth2 authorization managementSubscriptionService- Third-party subscriptionsApplicationInformationService- Application registrationNotificationService- Event notificationsBatchListService- Batch operationsDtoExportService- Entity to DTO mapping and XML export
REST controllers are in openespi-datacustodian/src/main/java/org/greenbuttonalliance/espi/datacustodian/web/:
- web/api/ - ESPI RESTful API endpoints (many currently
.disabledduring migration) - web/custodian/ - Data custodian-specific endpoints
- web/customer/ - Retail customer portal endpoints
Note: Many REST controllers have .disabled extension during the Spring Boot 4.0 migration. They need to be re-enabled and tested after core functionality is validated.
The project uses MapStruct for entity-to-DTO mappings:
- DTOs:
openespi-common/src/main/java/org/greenbuttonalliance/espi/common/dto/ - Mappers:
openespi-common/src/main/java/org/greenbuttonalliance/espi/common/mapper/
DTOs mirror ESPI XML schema structure and are used exclusively for XML representations. JSON is only used by openespi-authserver for OAuth2 operations.
CRITICAL: JAXB annotations MUST only be applied to DTO classes, NEVER to entity or embeddable classes.
-
Entity/Embeddable Classes (
domain/packages):- Use JPA annotations only:
@Entity,@Table,@Column,@Embeddable, etc. - ABSOLUTELY NO JAXB annotations: Do not use
@XmlType,@XmlAccessorType,@XmlElement,@XmlRootElement - Purpose: JPA persistence layer only
- Use JPA annotations only:
-
DTO Classes (
dto/packages):- Use JAXB annotations:
@XmlType,@XmlAccessorType,@XmlElement,@XmlRootElement - NO JPA annotations
- Purpose: XML marshalling/unmarshalling only
- Use JAXB annotations:
If an embeddable class needs XML serialization but has no DTO: Create a corresponding DTO class rather than adding JAXB annotations to the embeddable. This rule has NO exceptions.
Rationale: When both entity and DTO classes have JAXB annotations with the same XML type name and namespace, JAXB throws IllegalAnnotationsException due to duplicate type definitions when both are loaded in the same context. This strict separation ensures:
- Clean architecture (persistence vs. presentation layers)
- No JAXB namespace conflicts
- Entities can be refactored without affecting XML schema
- DTOs can be optimized for XML without affecting database schema
- MySQL 8.0+ (primary development database)
- PostgreSQL 15+ (production recommended)
- H2 (testing only via TestContainers)
Application behavior is controlled via Spring profiles:
dev-mysql- MySQL development (default)dev-postgresql- PostgreSQL developmentlocal- Local development settingsdocker- Docker container deploymentprod- Production settingstest- Test configuration with H2testcontainers- Integration tests with TestContainers
Flyway manages database schema migrations:
- Location:
openespi-common/src/main/resources/db/migration/ - MySQL scripts:
V1__Create_Base_Tables.sql,V3__Create_additiional_Base_Tables.sql - Run migrations: Automatically on application startup with
spring.flyway.enabled=true
IMPORTANT: When adding/modifying entities, ensure Flyway migration scripts are updated to match JPA entity definitions.
- Spring Boot: 4.0.1
- Spring Security: 7.x (OAuth2 Resource Server and Client)
- Spring Data JPA: 4.x with Hibernate 7.x
- Spring Authorization Server: Latest (for openespi-authserver only)
- JPA/Hibernate: 7.x with Jakarta Persistence API 3.2
- UUID Primary Keys: All entities use UUID Version 5 instead of Long IDs
- Flyway: Database migration management
- HikariCP: Connection pooling
- JUnit 5: Test framework
- Mockito: Mocking framework
- TestContainers: Docker-based integration testing for MySQL and PostgreSQL
- Spring Boot Test: Auto-configuration for testing
- Maven: 3.9+
- MapStruct: 1.6.3 for DTO mapping
- Lombok: 1.18.42 for reducing boilerplate
This codebase implements the NAESB ESPI 4.0 specification for Green Button data exchange.
- Location:
openespi-common/src/main/resources/schema/ESPI_4.0/ - Files:
espi.xsd(usage data),customer.xsd(customer data)
ESPI uses Atom XML feeds for data exchange. Key patterns:
- Each resource has both feed (collection) and entry (single item) representations
- Feed and Entry self-links use pattern:
https://{host}/DataCustodian/espi/1_1/resource/{resource}/{id}(where {resource} is the entity being received or sent) - Entry links include
rel="self"(resource URL),rel="up"(parent collection),rel="related"(related resources) - All IDs are Type 5 UUIDs in format:
urn:uuid:xxxxxxxx-xxxx-5xxx-xxxx-xxxxxxxxxxxx - Link type attributes use
espi-entry/{resource}orespi-feed/{resource}format
Usage Domain Resources (from usage.xsd):
- UsagePoint: Represents a metering point (e.g., electric meter)
- MeterReading: Collection of interval blocks for a usage point
- IntervalBlock: Time-series data with individual reading intervals
- ReadingType: Metadata describing measurement characteristics
- ElectricPowerQualitySummary: Power quality metrics
- UsageSummary: Aggregated usage statistics
- LocalTimeParameters: Timezone configuration
- RetailCustomer: Retail customer information
Customer Domain Resources (from customer.xsd):
- CustomerAccount: Customer billing account
- CustomerAgreement: Agreement between customer and supplier
- ServiceSupplier: Utility or energy service provider
- Meter: Physical meter device information
- ServiceLocation: Physical location of service delivery
- Statement: Billing statement information
- Main branch:
main(production-ready code) - Feature branches:
feature/descriptionfor new features - Bug fixes:
fix/descriptionfor bug fixes - Always create feature branch before making changes - never commit directly to main
- See BRANCH_STRATEGY.md for detailed workflow
- All tests must pass before committing:
mvn test - Run tests for affected module and its dependents:
mvn test -pl <module> -am - Integration tests should pass before PR merge:
mvn verify -Pfull-integration - IMPORTANT: Use AssertJ chained assertions - combine all assertions for a single object into one assertion chain
- Good:
assertThat(retrieved).isPresent().hasValueSatisfying(device -> assertThat(device).extracting(...).containsExactly(...)) - Bad: Multiple separate
assertThat()statements for the same object - This improves readability and provides better failure messages
- Good:
CRITICAL: Always use the Edit tool with visible diffs instead of sed/awk for file modifications
-
NEVER use sed, awk, or bash text manipulation for modifying source code or test files
-
ALWAYS use the Edit tool which shows explicit diffs for review
-
Benefits of Edit tool:
- Changes are visible and reviewable before execution
- Prevents cascading errors from bulk updates
- Easy to verify correctness with explicit old_string → new_string diff
- Catches errors immediately rather than discovering them during compilation
-
When multiple files need the same change:
- Use multiple Edit tool calls (one per file) in a single message
- Show exactly what's changing in each file
- Do NOT use sed/awk loops even if it seems more efficient
-
Exception: Only use bash text tools (grep, find) for searching/analysis, never for modifications
Example - WRONG approach:
# DON'T DO THIS - sed makes changes invisibly
sed -i '' 's/OldClass/NewClass/g' src/**/*.javaExample - CORRECT approach:
# DO THIS - Use Edit tool with explicit diffs
Edit tool call showing:
old_string: "import com.example.OldClass;"
new_string: "import com.example.NewClass;"
This practice prevents issues like missing imports, broken references, and compilation errors that are difficult to track down.
- Create entity in
openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/usage/(or/customer/) - Extend
IdentifiedObjectbase class - Add JPA annotations (
@Entity,@Table,@Column) - Create repository interface in
repositories/ - Create service interface and implementation in
service/andservice/impl/ - Create DTO in
dto/package - Create MapStruct mapper interface in
mapper/ - Add Flyway migration script in
db/migration/ - Write unit tests and integration tests
- All entities use
@IdwithUUIDtype, notLong - Use
@JoinColumnfor foreign keys with explicitnameattribute - Avoid
@Whereannotation conflicts with@JoinColumnon the same field - Be careful with
@ElementCollectionand@CollectionTablefor embedded collections - Phone numbers and addresses are embedded collections using
@ElementCollection - toString() method sequencing: Entity toString() methods MUST follow the exact database field sequence from Flyway migration scripts. Standard sequence is: id, description, created, updated, published, upLink, selfLink, [type-specific fields in database column order], relatedLinks (if present as last field). Always verify toString() matches the CREATE TABLE statement column order.
- Controllers in
openespi-datacustodianimplement ESPI REST API - Use
@RestControllerand@RequestMappingannotations - Follow existing patterns in enabled controllers (e.g.,
UsagePointController,MeterReadingController) - Many controllers currently disabled (
.disabledextension) - re-enable after testing core functionality
The codebase has been migrated to Spring Boot 4.0.1 and Java 25. Key migration achievements:
- Java 25 upgrade complete across all modules
- Jakarta EE 10+ migration complete (javax → jakarta namespace)
- Spring Boot 4.0.1 migration complete for common, datacustodian, authserver
- UUID Version 5 primary keys migrated from Long IDs
- OAuth2 modernized with Spring Security 7.x patterns
- RestTemplate replaced with WebClient
- Spring Data JPA 4.x with Hibernate 7.x
Check migration status documents for current issues:
2025-07-15_Claude_Code_Spring_Boot_3.5_Migration_Plan.md- Historical migration planopenespi-common/SPRING_BOOT_3.5_MIGRATION_STATUS.md- Historical common module statusopenespi-authserver/MIGRATION_ROADMAP.md- Auth server status
Current versions:
- Java: 25
- Spring Boot: 4.0.1
- Spring Security: 7.x
- Spring Data JPA: 4.x
- Hibernate: 7.x
- Jakarta EE: 10+
The system implements OAuth2 authorization code flow:
- Third-party application requests authorization
- Retail customer authenticates with openespi-authserver
- Authorization server issues authorization code
- Third-party exchanges code for access token
- Third-party accesses data custodian resources with token
- Authorization Server:
openespi-authserver- Spring Authorization Server (independent module) - Resource Server:
openespi-datacustodian- Validates OAuth2 tokens - OAuth2 Client:
openespi-thirdparty- Third-party application using WebClient with OAuth2
- Ensure Java 25 is installed:
java -version - Clean build:
mvn clean install - Check for profile-specific issues: review active Spring profile
- Ensure Docker is running for TestContainers tests
- Check database connection settings in application-test.yml
- Review test logs in
target/surefire-reports/
- Check Spring profile is correctly set:
SPRING_PROFILES_ACTIVE - Verify database is accessible and schema is current
- Review application logs for JPA mapping errors
- Check for duplicate column mappings in entities
- Look for duplicate
@Columnor@JoinColumndefinitions - Check for conflicts between
@Whereand relationship mappings - Verify Flyway migration scripts match entity definitions
- Review entity inheritance structure for mapping conflicts
- README.md - Project overview and quick start
- BRANCH_STRATEGY.md - Git workflow and branching strategy
- 2025-07-15_Claude_Code_Spring_Boot_3.5_Migration_Plan.md - Historical migration status (Spring Boot 3.5 to 4.0)
- openespi-common/CONTRIBUTING.md - Contribution guidelines
- openespi-authserver/DEPLOYMENT_GUIDE.md - Production deployment
- openespi-authserver/CERTIFICATE_AUTHENTICATION.md - Client certificate auth