# Persistence

> Persistence Layer

- Skill: `harshamendu/persistence` (Agent Skill, multi-file: 11 files)
- Install (CLI): `npx skillmds@latest add harshamendu/persistence`
- Raw SKILL.md: https://api.skillmd.com/api/skills/harshamendu/persistence/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Harshamendu (https://skillmd.com/u/harshamendu)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/harshamendu/persistence

---

# Persistence Layer

> **📝 Note:** This guide uses generic placeholder names to be reusable across any Spring Boot microservice.
> Replace with your actual implementation:
> - `{YourService}` → Your service name (e.g., `OrderService`, `PaymentService`)
> - `BusinessService` → Your core service (e.g., `OrderService`, `UserService`)
> - `DataService` → Your data processing service (e.g., `PaymentService`, `InventoryService`)
> - `IntegrationService` → Your external integration (e.g., `PaymentGatewayService`)
> - `{RequestType}` → Your request DTO (e.g., `CreateOrderRequest`)
> - `{ResponseType}` → Your response DTO (e.g., `OrderResponse`)


## Overview
Spring Data JPA persistence layer for workflow activation history tracking. Implements repository pattern with entity auditing and Flyway migrations.

**Package:** `com.example.microserviceorch.persistence.example`

## Quick Reference

### Key Components
- **Entities**: JPA models extending `BaseEntity` (from lib-rds)
- **Repositories**: Spring Data JPA interfaces with derived query methods
- **Migrations**: Flyway scripts in `src/main/resources/db/migration/`
- **Pattern**: Repository pattern with Specification support

### Entity Pattern
```java
@Entity
@Table(name = "MVPD_ACTIVATION_HISTORY")
public class MvpdActivationHistory extends BaseEntity implements Persistable<Long> {
    @Id
    @Column(name = "id")
    private Long id;
    
    @Column(name = "account_id")
    private UUID accountId;
    
    @Transient 
    private boolean isNew = false;
    
    // Override isNew() for INSERT/UPDATE control
}
```

### Repository Pattern
```java
@Repository
public interface MvpdActivationHistoryRepository
        extends JpaRepository<MvpdActivationHistory, Long>,
                JpaSpecificationExecutor<MvpdActivationHistory> {
    boolean existsByAccountIdAndMvpd(UUID uuid, String mvpd);
}
```

## Conventions

### Naming
- **Database columns**: `snake_case` (e.g., `account_id`, `date_inserted`)
- **Entity fields**: `camelCase` (e.g., `accountId`, `dateInserted`)
- **Tables**: `UPPER_SNAKE_CASE` (e.g., `MVPD_ACTIVATION_HISTORY`)

### Auditing
All entities extend `BaseEntity` for automatic timestamps:
- `date_inserted`: Set on @PrePersist
- `date_updated`: Set on @PreUpdate

### Formatting
Code formatted with Spotless (Google Java Format AOSP):
```bash
./gradlew spotlessApply
```

## Common Tasks

**Add new entity:**
1. Create entity in `model/` extending `BaseEntity`
2. Create repository interface
3. Create Flyway migration script
4. Run `./gradlew spotlessApply`

**Add custom query:**
Use method naming convention in repository:
```java
boolean existsByAccountIdAndMvpd(UUID accountId, String mvpd);
List<Entity> findByFieldName(String value);
```

**Create migration:**
Format: `V{number}__{Description}.sql`
Example: `V2__AddIndexes.sql`

## Anti-Patterns
- ❌ Business logic in repositories
- ❌ Missing @Transactional on service methods
- ❌ N+1 queries (use fetch joins)
- ❌ Lazy loading outside transaction
- ❌ Setting nullable=false on columns (keep all nullable)

## Key Files
- Entities: `src/main/java/.../persistence/model/`
- Repositories: `src/main/java/.../persistence/`
- Migrations: `src/main/resources/db/migration/`

## Learn More
- See `guides/` for detailed patterns and best practices
- See `examples/` for complete code examples

