agentsclimarketplace

Allra database schema

Skill ComeOnOliver/skillshub/skills/aiskillstore/marketplace/allra-fintech/allra-database-schema

๐Ÿง  The right skill, one API call. AI agent skills registry with token-efficient skill resolution. 5,000+ skills from 500+ top repos.

Install
npx -y skills add ComeOnOliver/skillshub --skill allra-database-schema

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Allra ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„ ๋ฐ QueryDSL ์‚ฌ์šฉ ๊ทœ์น™. Use when creating JPA entities, writing QueryDSL queries, or adding @Transactional annotations.

SKILL.md

8.0 KB, as published. Nobody here has run it

Allra Database ์„ค๊ณ„ ๋ฐ QueryDSL ๊ทœ์น™

Allra ๋ฐฑ์—”๋“œ ํŒ€์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„, JPA, QueryDSL, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ํ‘œ์ค€์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ ๊ธฐ๋ณธ ์ •๋ณด

์ด ๊ฐ€์ด๋“œ๋Š” ๋‹ค์Œ ํ™˜๊ฒฝ์„ ๊ธฐ์ค€์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  • Java: 17 ์ด์ƒ
  • Spring Boot: 3.2 ์ด์ƒ
  • ORM: JPA/Hibernate
  • Query Library: QueryDSL (์„ ํƒ ์‚ฌํ•ญ)
  • Testing: Testcontainers (์„ ํƒ ์‚ฌํ•ญ)

์ฐธ๊ณ : ํ”„๋กœ์ ํŠธ๋ณ„๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(MariaDB, PostgreSQL, MySQL ๋“ฑ)์™€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

QueryDSL ์‚ฌ์šฉ ๊ทœ์น™

1. Repository ๊ตฌ์กฐ (Allra ๊ถŒ์žฅ ํŒจํ„ด)

JPA Repository์™€ Support ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉ:

// JPA Repository ์ธํ„ฐํŽ˜์ด์Šค
public interface UserRepository extends JpaRepository<User, Long>, UserRepositorySupport {
}

// QueryDSL Support ์ธํ„ฐํŽ˜์ด์Šค
public interface UserRepositorySupport {
    List<UserSummaryDto> findUserSummaries(UserSearchCondition condition);
}

// QueryDSL Support ๊ตฌํ˜„์ฒด
@Repository
public class UserRepositoryImpl implements UserRepositorySupport {

    private final JPAQueryFactory queryFactory;

    @Override
    public List<UserSummaryDto> findUserSummaries(UserSearchCondition condition) {
        return queryFactory
            .select(new QUserSummaryDto(
                user.id,
                user.email,
                user.name
            ))
            .from(user)
            .where(
                emailContains(condition.email()),
                nameContains(condition.name())
            )
            .fetch();
    }

    private BooleanExpression emailContains(String email) {
        return email != null ? user.email.contains(email) : null;
    }
}

์ฐธ๊ณ : Support ํŒจํ„ด์€ ์„ ํƒ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ์— ๋”ฐ๋ผ @Query ์–ด๋…ธํ…Œ์ด์…˜์ด๋‚˜ ๋‹ค๋ฅธ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. QueryDSL DTO Projection

Record์™€ @QueryProjection ์‚ฌ์šฉ:

public record UserSummaryDto(
    Long id,
    String email,
    String name
) {
    @QueryProjection
    public UserSummaryDto {}
}

๋นŒ๋“œ ์„ค์ •:

Gradle:

annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"

Maven:

<plugin>
    <groupId>com.mysema.maven</groupId>
    <artifactId>apt-maven-plugin</artifactId>
    <version>1.1.3</version>
    <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>target/generated-sources/java</outputDirectory>
                <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
        </execution>
    </executions>
</plugin>

3. From ์ ˆ์— ๋งž๋Š” Repository ์œ„์น˜

From์ ˆ์— ํ•ด๋‹นํ•˜๋Š” Repository์— ์ •์˜ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅ:

// โŒ ํ”ผํ•˜๊ธฐ: Order์—์„œ User๋ฅผ ์กฐํšŒ
public interface OrderRepositorySupport {
    List<UserDto> findUsersByOrderDate(LocalDate date); // From user
}

// โœ… ๊ถŒ์žฅ: User์—์„œ Order๋ฅผ ์กฐ์ธ
public interface UserRepositorySupport {
    List<UserOrderDto> findUsersWithOrders(LocalDate date); // From user
}

4. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ˜ธํ™˜์„ฑ

QueryDSL ์ž‘์„ฑ ์‹œ ์‚ฌ์šฉ ์ค‘์ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํŠน์„ฑ์„ ๊ณ ๋ ค:

// ์ผ๋ฐ˜์ ์ธ ์ฟผ๋ฆฌ
queryFactory
    .selectFrom(user)
    .where(user.createdAt.between(startDate, endDate))
    .fetch();

// LIMIT/OFFSET
queryFactory
    .selectFrom(user)
    .limit(10)
    .offset(0)
    .fetch();

์ฐธ๊ณ : ์œˆ๋„์šฐ ํ•จ์ˆ˜๋‚˜ ํŠน์ • DB ํ•จ์ˆ˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฒ„์ „์— ๋”ฐ๋ผ ์ง€์› ์—ฌ๋ถ€๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5. xxxRepositorySupport ์ง์ ‘ ์˜์กด ๊ธˆ์ง€

๋ฐ˜๋“œ์‹œ JPA Repository ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ:

// โŒ ์ž˜๋ชป๋œ ์˜ˆ
@Service
public class UserService {
    private final UserRepositoryImpl userRepositoryImpl; // ๊ตฌํ˜„์ฒด ์ง์ ‘ ์ฃผ์ž…
}

// โœ… ์˜ฌ๋ฐ”๋ฅธ ์˜ˆ
@Service
public class UserService {
    private final UserRepository userRepository; // ์ธํ„ฐํŽ˜์ด์Šค ์ฃผ์ž…
}

@Transactional ์‚ฌ์šฉ ๊ฐ€์ด๋“œ

ํ•„์ˆ˜ ๊ทœ์น™

๊ฐ ์„œ๋น„์Šค ๋ฉ”์„œ๋“œ์— ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธ:

  1. ์กฐํšŒ ์ฟผ๋ฆฌ๋งŒ: @Transactional(readOnly = true)
  2. ๋ณ€๊ฒฝ ์ฟผ๋ฆฌ ํฌํ•จ: @Transactional

์˜ˆ์ œ

@Service
public class UserService {

    private final UserRepository userRepository;

    // ์ฝ๊ธฐ ์ „์šฉ ํŠธ๋žœ์žญ์…˜
    @Transactional(readOnly = true)
    public List<User> findAllUsers() {
        return userRepository.findAll();
    }

    // ์“ฐ๊ธฐ ํŠธ๋žœ์žญ์…˜
    @Transactional
    public User createUser(SignUpRequest request) {
        User user = User.create(request.email(), request.password());
        return userRepository.save(user);
    }

    // ์กฐํšŒ + ๋ณ€๊ฒฝ
    @Transactional
    public User activateUser(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException(id));
        user.activate(); // ๋ณ€๊ฒฝ
        return user;
    }
}

์ฐธ๊ณ : ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ(Propagation)๋Š” ๊ธฐ๋ณธ๊ฐ’(REQUIRED)์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ํŠน์ˆ˜ํ•œ ๊ฒฝ์šฐ์—๋งŒ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.

JPA Entity ์„ค๊ณ„ ๊ฐ€์ด๋“œ

๊ธฐ๋ณธ ๊ตฌ์กฐ

@Entity
@Table(name = "users")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true, length = 100)
    private String email;

    @Column(nullable = false, length = 100)
    private String name;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 20)
    private UserStatus status;

    @CreatedDate
    @Column(nullable = false, updatable = false)
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column(nullable = false)
    private LocalDateTime updatedAt;

    // ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ
    public static User create(String email, String password, String name) {
        User user = new User();
        user.email = email;
        user.password = password;
        user.name = name;
        user.status = UserStatus.ACTIVE;
        return user;
    }

    // ๋น„์ฆˆ๋‹ˆ์Šค ๋ฉ”์„œ๋“œ
    public void activate() {
        this.status = UserStatus.ACTIVE;
    }
}

์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘

@Entity
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // ManyToOne - ์ง€์—ฐ ๋กœ๋”ฉ ๊ถŒ์žฅ
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    // OneToMany - ์ง€์—ฐ ๋กœ๋”ฉ, Cascade ์„ค์ •
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<OrderItem> items = new ArrayList<>();

    // ์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ
    public void addItem(OrderItem item) {
        items.add(item);
        item.setOrder(this);
    }
}

์ฐธ๊ณ : ์—ฐ๊ด€๊ด€๊ณ„๋Š” ์ง€์—ฐ ๋กœ๋”ฉ(LAZY)์„ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

When to Use This Skill

์ด skill์€ ๋‹ค์Œ ์ƒํ™ฉ์—์„œ ์ž๋™์œผ๋กœ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค:

  • JPA Entity ์ƒ์„ฑ ๋ฐ ์ˆ˜์ •
  • QueryDSL ์ฟผ๋ฆฌ ์ž‘์„ฑ
  • Repository ์ธํ„ฐํŽ˜์ด์Šค ๋ฐ ๊ตฌํ˜„์ฒด ์ž‘์„ฑ
  • Service ๋ฉ”์„œ๋“œ์— @Transactional ์ถ”๊ฐ€
  • DTO Projection ์ž‘์„ฑ

Checklist

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ ํ™•์ธ์‚ฌํ•ญ:

  • QueryDSL Support๊ฐ€ JPA Repository์— ์ƒ์†๋˜์–ด ์žˆ๋Š”๊ฐ€? (Support ํŒจํ„ด ์‚ฌ์šฉ ์‹œ)
  • QueryDSL ๊ตฌํ˜„์ฒด๊ฐ€ From์ ˆ์— ๋งž๋Š” Repository์— ์žˆ๋Š”๊ฐ€?
  • DTO Projection์— @QueryProjection์ด ์ ์šฉ๋˜์—ˆ๋Š”๊ฐ€? (QueryDSL ์‚ฌ์šฉ ์‹œ)
  • Service์˜ ๋ชจ๋“  public ๋ฉ”์„œ๋“œ์— @Transactional์ด ๋ช…์‹œ๋˜์—ˆ๋Š”๊ฐ€?
  • ์ฝ๊ธฐ ์ „์šฉ ๋ฉ”์„œ๋“œ์— readOnly = true๊ฐ€ ์ ์šฉ๋˜์—ˆ๋Š”๊ฐ€?
  • MariaDB ํ˜ธํ™˜์„ฑ์„ ๊ณ ๋ คํ–ˆ๋Š”๊ฐ€?
  • Entity์˜ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์ง€์—ฐ ๋กœ๋”ฉ(LAZY)์œผ๋กœ ์„ค์ •๋˜์—ˆ๋Š”๊ฐ€?
  • xxxRepositorySupport ๊ตฌํ˜„์ฒด๋ฅผ ์ง์ ‘ ์ฃผ์ž…ํ•˜์ง€ ์•Š์•˜๋Š”๊ฐ€?

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.