AI-first engineering workflows for Spring Data JPA and Hibernate
The data layer is where N+1 queries hide, migrations break production,
and entity design mistakes compound silently for months.
FetchType.EAGER turns every single-entity query into a Cartesian joinEnumType.ORDINAL silently breaks when enum values are reorderedProduction incidents from migrations gone wrong
Slow endpoints that were fine in code review
Schema drift between JPA entities and the actual database
Deep JPA/Hibernate knowledge — entity lifecycle, relationships, queries, performance. 7 skills
Each skill file encodes deep expertise for one area of JPA and Hibernate. The AI loads only what's relevant — no bloated context, no guessed patterns.
Each agent focuses on one concern. Use the right one for the right PR — or let /review-jpa coordinate them automatically.
Entity design, relationships, fetch strategy, N+1, transaction placement — the general JPA review for any PR touching the data layer.
Flyway script review — naming, NOT NULL safety, index concurrency, rollback risk, large-table operations, zero-downtime compatibility.
Detects N+1 patterns, missing indexes, unbounded queries, inefficient batch operations, and connection pool risks at scale.
Validates that JPA annotations (@Column, @Index, @JoinColumn) match the actual DDL defined in migration files. Catches schema drift before deploy.
Rules are always-on. They apply to every agent output, every code suggestion, every migration — without being invoked explicitly.
Hooks are shell scripts that execute automatically on Claude Code events. Anti-patterns get caught before they're committed.
Scans entity files for ORDINAL enums, EAGER fetching, open-in-view, and dangerous ddl-auto values.
Validates Flyway naming conventions and detects duplicate version numbers before they reach the CI pipeline.
Runs mvn test including JPA integration tests. Build failure blocks the next action.
Configure in .claude/settings.json — hooks run outside the AI context, deterministically.
Reviews the current branch diff against main. Covers entity design, relationships, queries, transactions, migrations, and performance.
Actual files from the repository — not pseudocode. Drop them into any Spring Boot project and they work immediately.
# @OneToMany — Use Set, not List
## Why Set?
## List triggers Hibernate "bag" semantics — duplicate JOIN rows
## when combined with multiple JOIN FETCH operations.
@OneToMany(mappedBy = "customer",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY)
private Set<Order> orders = new HashSet<>();
## Bidirectional helper methods — always sync both sides
public void addOrder(Order order) {
orders.add(order);
order.setCustomer(this);
}
# Fetch Strategy Rules
@ManyToOne default: EAGER → always override to LAZY
@OneToOne default: EAGER → always override to LAZY
@OneToMany default: LAZY → keep
@ManyToMany default: LAZY → keep
## Migration safety checklist
**Safety rules**
- [ ] New NOT NULL columns: nullable first → backfill → constraint
- [ ] Renames: expand–contract across separate releases
- [ ] No DROP COLUMN in same release as removing code that uses it
**Index operations**
- [ ] Indexes on large tables use CREATE INDEX CONCURRENTLY
- [ ] CONCURRENTLY runs outside a transaction block
**Output format**
[BLOCKER|RISK|SUGGESTION] File: V{n}__{name}.sql
Issue: <what is wrong>
Risk: <what could go wrong in production>
Fix: <safe alternative>
End with: SAFE TO RUN / REVIEW REQUIRED / DO NOT RUN# JPA Review — feature/add-order-items
## Summary
Adds the OrderItem entity with a ManyToOne to Product and Order.
Two blocking issues in entity design and one migration risk.
## Risk Level
High
## Entity Design Review
⚠ BLOCKER — OrderItem.java: @ManyToOne on `product` uses
FetchType.EAGER. Change to LAZY. Accessing product data
in a list of 1000 items triggers 1000 extra SQL queries.
## Relationship Review
⚠ BLOCKER — Order.java: @OneToMany items uses List<OrderItem>.
Use Set<OrderItem> to prevent Hibernate bag semantics when
JOIN FETCHing multiple collections.
## Migration Review
⚠ RISK — V8__add_unit_price_not_null.sql adds a NOT NULL column
directly. If order_items has existing rows, this will fail.
Add as nullable in V8, backfill in V9, add constraint in V10.
## Final Recommendation
REQUEST CHANGESSenior Software Engineer and international speaker. Building AI-first engineering systems for Java, Spring Boot, and Drupal platforms.
This is the system that makes those problems visible before they reach production. Use it. Fork it. Adapt it.
Sponsored by heydru! — Enterprise backend engineering and AI-assisted development workflows.