backend-claude-code 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.claude/settings.json +42 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +35 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +33 -0
  4. package/.github/PULL_REQUEST_TEMPLATE.md +32 -0
  5. package/.mcp.json +19 -0
  6. package/CLAUDE.md +126 -0
  7. package/README.md +142 -0
  8. package/agents/code-reviewer.md +84 -0
  9. package/agents/database-reviewer.md +91 -0
  10. package/agents/java-build-resolver.md +127 -0
  11. package/agents/java-performance-reviewer.md +262 -0
  12. package/agents/planner.md +99 -0
  13. package/agents/security-reviewer.md +119 -0
  14. package/agents/tdd-guide.md +189 -0
  15. package/bin/cli.js +144 -0
  16. package/commands/db-migrate.md +134 -0
  17. package/commands/dev-build.md +72 -0
  18. package/commands/dev-coverage.md +73 -0
  19. package/commands/dev-fix.md +75 -0
  20. package/commands/dev-plan.md +501 -0
  21. package/commands/dev-review.md +144 -0
  22. package/commands/dev-run.md +385 -0
  23. package/commands/dev-test.md +89 -0
  24. package/commands/dev-verify.md +95 -0
  25. package/commands/dev.md +45 -0
  26. package/commands/git-commit.md +112 -0
  27. package/commands/git-issue.md +74 -0
  28. package/commands/git-pr.md +184 -0
  29. package/commands/git-push.md +28 -0
  30. package/package.json +24 -0
  31. package/rules/architecture.md +33 -0
  32. package/rules/coding-style.md +113 -0
  33. package/rules/controller-patterns.md +63 -0
  34. package/rules/dto-patterns.md +76 -0
  35. package/rules/entity-patterns.md +70 -0
  36. package/rules/error-handling.md +56 -0
  37. package/rules/hooks.md +73 -0
  38. package/rules/repository-patterns.md +75 -0
  39. package/rules/security.md +101 -0
  40. package/rules/service-patterns.md +70 -0
  41. package/rules/testing.md +174 -0
  42. package/skills/api-design/SKILL.md +523 -0
  43. package/skills/architecture-decision-records/SKILL.md +179 -0
  44. package/skills/database-migrations/SKILL.md +429 -0
  45. package/skills/hexagonal-architecture/SKILL.md +276 -0
  46. package/skills/java-coding-standards/SKILL.md +236 -0
  47. package/skills/jpa-patterns/SKILL.md +218 -0
  48. package/skills/postgres-patterns/SKILL.md +147 -0
  49. package/skills/springboot-patterns/SKILL.md +255 -0
  50. package/skills/springboot-security/SKILL.md +241 -0
  51. package/skills/springboot-tdd/SKILL.md +236 -0
@@ -0,0 +1,236 @@
1
+ ---
2
+ name: java-coding-standards
3
+ description: "Java coding standards for Spring Boot services: naming, immutability, Optional usage, streams, exceptions, generics, and project layout."
4
+ origin: ECC
5
+ ---
6
+
7
+ # Java Coding Standards
8
+
9
+ Spring Boot 서비스에서 읽기 쉽고 유지보수 가능한 Java (17+) 코드 표준.
10
+
11
+ ## When to Activate
12
+
13
+ - Spring Boot 프로젝트에서 Java 코드 작성 또는 리뷰
14
+ - 명명, 불변성, 예외 처리 관례 강제
15
+ - records, sealed classes, pattern matching 작업 (Java 17+)
16
+ - Optional, streams, generics 사용 리뷰
17
+ - 패키지 및 프로젝트 레이아웃 구성
18
+
19
+ ## Core Principles
20
+
21
+ - 영리함보다 명확성 우선
22
+ - 기본적으로 불변; 공유 가변 상태 최소화
23
+ - 의미 있는 예외로 빠른 실패
24
+ - 일관된 명명 및 패키지 구조
25
+
26
+ ## Naming
27
+
28
+ ```java
29
+ // PASS: 클래스/레코드: PascalCase
30
+ public class OrderService {}
31
+ public record Money(BigDecimal amount, Currency currency) {}
32
+
33
+ // PASS: 메서드/필드: camelCase
34
+ private final OrderRepository orderRepository;
35
+ public OrderResponse findByOrderNumber(String orderNumber) {}
36
+
37
+ // PASS: 상수: UPPER_SNAKE_CASE
38
+ private static final int MAX_PAGE_SIZE = 100;
39
+ private static final Duration TOKEN_EXPIRY = Duration.ofHours(24);
40
+
41
+ // PASS: 패키지: 소문자 역방향 도메인
42
+ // com.example.app.service
43
+ // com.example.app.controller
44
+ // com.example.app.domain
45
+ ```
46
+
47
+ ## Immutability
48
+
49
+ ```java
50
+ // PASS: record와 final 필드 선호
51
+ public record OrderDto(Long id, String customerName, BigDecimal amount, OrderStatus status) {}
52
+
53
+ public class Order {
54
+ private final Long id;
55
+ private final String customerName;
56
+ private final BigDecimal amount;
57
+
58
+ // getter만, setter 없음
59
+ public Long getId() { return id; }
60
+ }
61
+
62
+ // PASS: 컬렉션 방어적 복사
63
+ public List<OrderItem> getItems() {
64
+ return List.copyOf(items); // 불변 복사 반환
65
+ }
66
+
67
+ // FAIL: 가변 컬렉션 직접 반환
68
+ public List<OrderItem> getItems() {
69
+ return items; // 외부에서 수정 가능 — 위험
70
+ }
71
+ ```
72
+
73
+ ## Optional Usage
74
+
75
+ ```java
76
+ // PASS: finder 메서드에서 Optional 반환
77
+ Optional<Order> findByOrderNumber(String orderNumber);
78
+
79
+ // PASS: map/flatMap 사용, get() 금지
80
+ return orderRepository.findByOrderNumber(orderNumber)
81
+ .map(OrderResponse::from)
82
+ .orElseThrow(() -> new OrderNotFoundException(orderNumber));
83
+
84
+ // PASS: 기본값
85
+ String name = Optional.ofNullable(dto.name()).orElse("Unknown");
86
+
87
+ // FAIL: Optional.get() 직접 사용
88
+ Order order = repo.findById(id).get(); // NoSuchElementException 위험
89
+
90
+ // FAIL: 매개변수로 Optional
91
+ public void process(Optional<String> name) {} // 그냥 null 허용으로
92
+ ```
93
+
94
+ ## Streams Best Practices
95
+
96
+ ```java
97
+ // PASS: 변환에 스트림 사용, 파이프라인 짧게
98
+ List<String> activeNames = orders.stream()
99
+ .filter(o -> o.status() == OrderStatus.ACTIVE)
100
+ .map(Order::customerName)
101
+ .sorted()
102
+ .toList(); // Java 16+
103
+
104
+ // PASS: 메서드 참조
105
+ List<OrderResponse> responses = orders.stream()
106
+ .map(OrderResponse::from) // 람다보다 간결
107
+ .toList();
108
+
109
+ // FAIL: 복잡한 중첩 스트림 — 루프 사용
110
+ orders.stream()
111
+ .flatMap(o -> o.items().stream()
112
+ .filter(i -> i.price().compareTo(BigDecimal.TEN) > 0)
113
+ .map(i -> new ItemDto(o.id(), i.name(), i.price())))
114
+ .collect(Collectors.toList());
115
+ // → 이런 경우 명시적 루프가 더 명확
116
+ ```
117
+
118
+ ## Exceptions
119
+
120
+ ```java
121
+ // PASS: 도메인 예외 — 컨텍스트 포함
122
+ public class OrderNotFoundException extends RuntimeException {
123
+ public OrderNotFoundException(Long id) {
124
+ super("Order not found: id=" + id);
125
+ }
126
+ public OrderNotFoundException(String orderNumber) {
127
+ super("Order not found: orderNumber=" + orderNumber);
128
+ }
129
+ }
130
+
131
+ // PASS: 기술적 예외 래핑
132
+ try {
133
+ return externalPaymentApi.charge(request);
134
+ } catch (HttpClientErrorException ex) {
135
+ throw new PaymentException("Payment failed: " + ex.getStatusCode(), ex);
136
+ }
137
+
138
+ // FAIL: 빈 catch 블록
139
+ try {
140
+ doSomething();
141
+ } catch (Exception e) {} // 절대 금지
142
+
143
+ // FAIL: 너무 광범위한 예외 포착
144
+ try {
145
+ service.process(request);
146
+ } catch (Exception e) { // RuntimeException 이상을 잡으면 안 됨
147
+ log.error("Error", e);
148
+ }
149
+ ```
150
+
151
+ ## Modern Java Features
152
+
153
+ ```java
154
+ // Records (Java 16+) — DTO에 이상적
155
+ public record CreateOrderRequest(
156
+ @NotBlank String customerName,
157
+ @NotNull @Positive BigDecimal amount) {}
158
+
159
+ // Sealed interfaces (Java 17+) — 닫힌 타입 계층
160
+ public sealed interface PaymentResult
161
+ permits PaymentResult.Success, PaymentResult.Failure {
162
+ record Success(String transactionId) implements PaymentResult {}
163
+ record Failure(String errorCode, String message) implements PaymentResult {}
164
+ }
165
+
166
+ // Pattern matching instanceof (Java 16+)
167
+ if (event instanceof OrderCreatedEvent e) {
168
+ log.info("Order created: id={}", e.orderId()); // 캐스트 불필요
169
+ }
170
+
171
+ // Switch expressions (Java 14+)
172
+ String statusLabel = switch (order.status()) {
173
+ case PENDING -> "대기 중";
174
+ case ACTIVE -> "처리 중";
175
+ case COMPLETED -> "완료";
176
+ case CANCELLED -> "취소됨";
177
+ };
178
+
179
+ // Text blocks (Java 15+) — SQL 쿼리에 유용
180
+ String query = """
181
+ SELECT o.id, o.customer_name, o.amount
182
+ FROM orders o
183
+ WHERE o.status = :status
184
+ ORDER BY o.created_at DESC
185
+ """;
186
+ ```
187
+
188
+ ## Project Structure
189
+
190
+ ```
191
+ src/main/java/com/example/
192
+ ├── controller/ # REST 컨트롤러
193
+ │ └── OrderController.java
194
+ ├── service/ # 비즈니스 로직
195
+ │ └── OrderService.java
196
+ ├── repository/ # 데이터 접근
197
+ │ └── OrderRepository.java
198
+ ├── domain/ # 도메인 모델/엔티티
199
+ │ ├── Order.java # 도메인 객체
200
+ │ └── OrderEntity.java # JPA 엔티티
201
+ ├── dto/ # 요청/응답 DTO
202
+ │ ├── CreateOrderRequest.java
203
+ │ └── OrderResponse.java
204
+ ├── exception/ # 도메인 예외
205
+ │ └── OrderNotFoundException.java
206
+ └── config/ # Spring 설정
207
+ ├── SecurityConfig.java
208
+ └── JpaConfig.java
209
+ ```
210
+
211
+ ## Logging Standards
212
+
213
+ ```java
214
+ // PASS: SLF4J, 구조적 매개변수
215
+ private static final Logger log = LoggerFactory.getLogger(OrderService.class);
216
+
217
+ log.info("order_created id={} customer={}", order.getId(), order.getCustomerName());
218
+ log.warn("order_not_found id={}", id);
219
+ log.error("payment_failed orderId={} error={}", orderId, ex.getMessage(), ex);
220
+
221
+ // FAIL: 문자열 연결 (매개변수 사용)
222
+ log.info("Order created: " + order.getId()); // 성능 낭비
223
+
224
+ // FAIL: 민감 데이터 로깅
225
+ log.info("User login email={} password={}", email, password); // 절대 금지
226
+ ```
227
+
228
+ ## Testing Expectations
229
+
230
+ - `@ExtendWith(MockitoExtension.class)` 서비스 단위 테스트
231
+ - `@WebMvcTest` 컨트롤러 단위 테스트
232
+ - `@DataJpaTest` 레포지토리 테스트
233
+ - `@SpringBootTest` 통합 테스트에만
234
+ - JaCoCo 라인 커버리지 80% 최소
235
+
236
+ **Remember**: 명확하게 명명, 불변성 유지, 빠른 실패, 예외에 컨텍스트 포함, 모던 Java 기능으로 표현력 향상.
@@ -0,0 +1,218 @@
1
+ ---
2
+ name: jpa-patterns
3
+ description: JPA/Hibernate patterns for entity design, relationships, query optimization, transactions, auditing, indexing, pagination, and pooling in Spring Boot.
4
+ origin: ECC
5
+ ---
6
+
7
+ # JPA/Hibernate Patterns
8
+
9
+ Spring Boot에서 데이터 모델링, 레포지토리, 성능 튜닝에 사용.
10
+
11
+ ## When to Activate
12
+
13
+ - JPA 엔티티 및 테이블 매핑 설계
14
+ - 관계 정의 (@OneToMany, @ManyToOne, @ManyToMany)
15
+ - 쿼리 최적화 (N+1 방지, fetch 전략, 프로젝션)
16
+ - 트랜잭션, 감사, 소프트 삭제 설정
17
+ - 페이지네이션, 정렬, 커스텀 레포지토리 메서드 설정
18
+ - HikariCP 연결 풀링 또는 2레벨 캐싱 튜닝
19
+
20
+ ## Entity Design
21
+
22
+ ```java
23
+ @Entity
24
+ @Table(name = "orders", indexes = {
25
+ @Index(name = "idx_orders_customer_id", columnList = "customer_id"),
26
+ @Index(name = "idx_orders_status_created", columnList = "status, created_at")
27
+ })
28
+ @EntityListeners(AuditingEntityListener.class)
29
+ public class OrderEntity {
30
+ @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
31
+ private Long id;
32
+
33
+ @Column(nullable = false, length = 100)
34
+ private String customerName;
35
+
36
+ @Column(nullable = false, precision = 19, scale = 4)
37
+ private BigDecimal amount;
38
+
39
+ @Enumerated(EnumType.STRING)
40
+ @Column(nullable = false, length = 20)
41
+ private OrderStatus status = OrderStatus.PENDING;
42
+
43
+ @CreatedDate
44
+ @Column(updatable = false)
45
+ private Instant createdAt;
46
+
47
+ @LastModifiedDate
48
+ private Instant updatedAt;
49
+
50
+ @Version
51
+ private Long version; // 낙관적 잠금
52
+ }
53
+ ```
54
+
55
+ 감사 활성화:
56
+ ```java
57
+ @Configuration
58
+ @EnableJpaAuditing
59
+ class JpaConfig {}
60
+ ```
61
+
62
+ ## Relationships and N+1 Prevention
63
+
64
+ ```java
65
+ // 부모 엔티티
66
+ @Entity
67
+ public class OrderEntity {
68
+ @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
69
+ private List<OrderItemEntity> items = new ArrayList<>();
70
+ }
71
+
72
+ // N+1 방지 — JOIN FETCH 사용
73
+ @Query("select o from OrderEntity o left join fetch o.items where o.id = :id")
74
+ Optional<OrderEntity> findWithItems(@Param("id") Long id);
75
+
76
+ // 또는 @EntityGraph 사용
77
+ @EntityGraph(attributePaths = {"items"})
78
+ Optional<OrderEntity> findById(Long id);
79
+ ```
80
+
81
+ ## Repository Patterns
82
+
83
+ ```java
84
+ public interface OrderRepository extends JpaRepository<OrderEntity, Long> {
85
+ // 파생 쿼리
86
+ Page<OrderEntity> findByStatus(OrderStatus status, Pageable pageable);
87
+ Optional<OrderEntity> findByOrderNumber(String orderNumber);
88
+
89
+ // JPQL 쿼리
90
+ @Query("select o from OrderEntity o where o.amount >= :minAmount and o.status = :status")
91
+ Page<OrderEntity> findByMinAmountAndStatus(
92
+ @Param("minAmount") BigDecimal minAmount,
93
+ @Param("status") OrderStatus status,
94
+ Pageable pageable);
95
+
96
+ // 집계
97
+ @Query("select count(o) from OrderEntity o where o.status = :status")
98
+ long countByStatus(@Param("status") OrderStatus status);
99
+ }
100
+ ```
101
+
102
+ ## DTO Projections (성능 최적화)
103
+
104
+ 엔티티 전체 로딩 없이 필요한 필드만 조회:
105
+
106
+ ```java
107
+ // 인터페이스 프로젝션
108
+ public interface OrderSummary {
109
+ Long getId();
110
+ String getCustomerName();
111
+ BigDecimal getAmount();
112
+ OrderStatus getStatus();
113
+ }
114
+
115
+ Page<OrderSummary> findAllBy(Pageable pageable);
116
+
117
+ // 클래스 기반 프로젝션 (DTO 생성자)
118
+ public record OrderSummaryDto(Long id, String customerName, OrderStatus status) {}
119
+
120
+ @Query("select new com.example.dto.OrderSummaryDto(o.id, o.customerName, o.status) from OrderEntity o")
121
+ Page<OrderSummaryDto> findSummaries(Pageable pageable);
122
+ ```
123
+
124
+ ## Transactions
125
+
126
+ ```java
127
+ @Service
128
+ public class OrderService {
129
+ @Transactional
130
+ public OrderResponse updateStatus(Long id, OrderStatus newStatus) {
131
+ OrderEntity entity = repo.findById(id)
132
+ .orElseThrow(() -> new OrderNotFoundException(id));
133
+ entity.setStatus(newStatus);
134
+ return OrderResponse.from(entity); // dirty checking으로 자동 저장
135
+ }
136
+
137
+ @Transactional(readOnly = true)
138
+ public Page<OrderResponse> findByStatus(OrderStatus status, Pageable pageable) {
139
+ return repo.findByStatus(status, pageable).map(OrderResponse::from);
140
+ }
141
+
142
+ @Transactional(propagation = Propagation.REQUIRES_NEW)
143
+ public void auditOrderChange(Long orderId, String action) {
144
+ // 별도 트랜잭션에서 감사 로그 저장
145
+ auditRepo.save(new AuditLog(orderId, action));
146
+ }
147
+ }
148
+ ```
149
+
150
+ ## Pagination
151
+
152
+ ```java
153
+ // 기본 페이지네이션
154
+ PageRequest page = PageRequest.of(0, 20, Sort.by("createdAt").descending());
155
+ Page<OrderEntity> orders = repo.findByStatus(OrderStatus.PENDING, page);
156
+
157
+ // 멀티 정렬
158
+ PageRequest page = PageRequest.of(0, 20,
159
+ Sort.by(Sort.Order.desc("status"), Sort.Order.asc("createdAt")));
160
+ ```
161
+
162
+ ## Indexing and Performance
163
+
164
+ - 공통 필터에 인덱스 추가 (`status`, `customerId`, FK)
165
+ - 쿼리 패턴에 맞는 복합 인덱스 (`status, created_at`)
166
+ - `select *` 지양 — 필요한 컬럼만 프로젝션
167
+ - `saveAll`과 `hibernate.jdbc.batch_size`로 배치 쓰기
168
+
169
+ ## Connection Pooling (HikariCP)
170
+
171
+ ```yaml
172
+ spring:
173
+ datasource:
174
+ hikari:
175
+ maximum-pool-size: 20
176
+ minimum-idle: 5
177
+ connection-timeout: 30000
178
+ idle-timeout: 600000
179
+ max-lifetime: 1800000
180
+ validation-timeout: 5000
181
+ jpa:
182
+ properties:
183
+ hibernate:
184
+ jdbc:
185
+ batch_size: 50
186
+ order_inserts: true
187
+ order_updates: true
188
+ ```
189
+
190
+ ## Migrations
191
+
192
+ - Flyway 또는 Liquibase 사용 — 프로덕션에서 Hibernate auto DDL 금지
193
+ - 마이그레이션은 멱등성과 추가적으로 유지; 계획 없이 컬럼 삭제 금지
194
+
195
+ ```sql
196
+ -- V1__create_orders_table.sql
197
+ CREATE TABLE orders (
198
+ id BIGSERIAL PRIMARY KEY,
199
+ customer_name VARCHAR(100) NOT NULL,
200
+ amount NUMERIC(19, 4) NOT NULL,
201
+ status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
202
+ created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
203
+ updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
204
+ version BIGINT NOT NULL DEFAULT 0
205
+ );
206
+
207
+ CREATE INDEX idx_orders_status_created ON orders (status, created_at DESC);
208
+ ```
209
+
210
+ ## Testing Data Access
211
+
212
+ ```bash
213
+ # SQL 디버깅
214
+ logging.level.org.hibernate.SQL=DEBUG
215
+ logging.level.org.hibernate.orm.jdbc.bind=TRACE
216
+ ```
217
+
218
+ **Remember**: 엔티티는 작게, 쿼리는 의도적으로, 트랜잭션은 짧게. fetch 전략과 프로젝션으로 N+1 방지, 읽기/쓰기 경로를 위한 인덱싱.
@@ -0,0 +1,147 @@
1
+ ---
2
+ name: postgres-patterns
3
+ description: PostgreSQL database patterns for query optimization, schema design, indexing, and security. Based on Supabase best practices.
4
+ origin: ECC
5
+ ---
6
+
7
+ # PostgreSQL Patterns
8
+
9
+ Quick reference for PostgreSQL best practices. For detailed guidance, use the `database-reviewer` agent.
10
+
11
+ ## When to Activate
12
+
13
+ - Writing SQL queries or migrations
14
+ - Designing database schemas
15
+ - Troubleshooting slow queries
16
+ - Implementing Row Level Security
17
+ - Setting up connection pooling
18
+
19
+ ## Quick Reference
20
+
21
+ ### Index Cheat Sheet
22
+
23
+ | Query Pattern | Index Type | Example |
24
+ |--------------|------------|---------|
25
+ | `WHERE col = value` | B-tree (default) | `CREATE INDEX idx ON t (col)` |
26
+ | `WHERE col > value` | B-tree | `CREATE INDEX idx ON t (col)` |
27
+ | `WHERE a = x AND b > y` | Composite | `CREATE INDEX idx ON t (a, b)` |
28
+ | `WHERE jsonb @> '{}'` | GIN | `CREATE INDEX idx ON t USING gin (col)` |
29
+ | `WHERE tsv @@ query` | GIN | `CREATE INDEX idx ON t USING gin (col)` |
30
+ | Time-series ranges | BRIN | `CREATE INDEX idx ON t USING brin (col)` |
31
+
32
+ ### Data Type Quick Reference
33
+
34
+ | Use Case | Correct Type | Avoid |
35
+ |----------|-------------|-------|
36
+ | IDs | `bigint` | `int`, random UUID |
37
+ | Strings | `text` | `varchar(255)` |
38
+ | Timestamps | `timestamptz` | `timestamp` |
39
+ | Money | `numeric(10,2)` | `float` |
40
+ | Flags | `boolean` | `varchar`, `int` |
41
+
42
+ ### Common Patterns
43
+
44
+ **Composite Index Order:**
45
+ ```sql
46
+ -- Equality columns first, then range columns
47
+ CREATE INDEX idx ON orders (status, created_at);
48
+ -- Works for: WHERE status = 'pending' AND created_at > '2024-01-01'
49
+ ```
50
+
51
+ **Covering Index:**
52
+ ```sql
53
+ CREATE INDEX idx ON users (email) INCLUDE (name, created_at);
54
+ -- Avoids table lookup for SELECT email, name, created_at
55
+ ```
56
+
57
+ **Partial Index:**
58
+ ```sql
59
+ CREATE INDEX idx ON users (email) WHERE deleted_at IS NULL;
60
+ -- Smaller index, only includes active users
61
+ ```
62
+
63
+ **RLS Policy (Optimized):**
64
+ ```sql
65
+ CREATE POLICY policy ON orders
66
+ USING ((SELECT auth.uid()) = user_id); -- Wrap in SELECT!
67
+ ```
68
+
69
+ **UPSERT:**
70
+ ```sql
71
+ INSERT INTO settings (user_id, key, value)
72
+ VALUES (123, 'theme', 'dark')
73
+ ON CONFLICT (user_id, key)
74
+ DO UPDATE SET value = EXCLUDED.value;
75
+ ```
76
+
77
+ **Cursor Pagination:**
78
+ ```sql
79
+ SELECT * FROM products WHERE id > $last_id ORDER BY id LIMIT 20;
80
+ -- O(1) vs OFFSET which is O(n)
81
+ ```
82
+
83
+ **Queue Processing:**
84
+ ```sql
85
+ UPDATE jobs SET status = 'processing'
86
+ WHERE id = (
87
+ SELECT id FROM jobs WHERE status = 'pending'
88
+ ORDER BY created_at LIMIT 1
89
+ FOR UPDATE SKIP LOCKED
90
+ ) RETURNING *;
91
+ ```
92
+
93
+ ### Anti-Pattern Detection
94
+
95
+ ```sql
96
+ -- Find unindexed foreign keys
97
+ SELECT conrelid::regclass, a.attname
98
+ FROM pg_constraint c
99
+ JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = ANY(c.conkey)
100
+ WHERE c.contype = 'f'
101
+ AND NOT EXISTS (
102
+ SELECT 1 FROM pg_index i
103
+ WHERE i.indrelid = c.conrelid AND a.attnum = ANY(i.indkey)
104
+ );
105
+
106
+ -- Find slow queries
107
+ SELECT query, mean_exec_time, calls
108
+ FROM pg_stat_statements
109
+ WHERE mean_exec_time > 100
110
+ ORDER BY mean_exec_time DESC;
111
+
112
+ -- Check table bloat
113
+ SELECT relname, n_dead_tup, last_vacuum
114
+ FROM pg_stat_user_tables
115
+ WHERE n_dead_tup > 1000
116
+ ORDER BY n_dead_tup DESC;
117
+ ```
118
+
119
+ ### Configuration Template
120
+
121
+ ```sql
122
+ -- Connection limits (adjust for RAM)
123
+ ALTER SYSTEM SET max_connections = 100;
124
+ ALTER SYSTEM SET work_mem = '8MB';
125
+
126
+ -- Timeouts
127
+ ALTER SYSTEM SET idle_in_transaction_session_timeout = '30s';
128
+ ALTER SYSTEM SET statement_timeout = '30s';
129
+
130
+ -- Monitoring
131
+ CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
132
+
133
+ -- Security defaults
134
+ REVOKE ALL ON SCHEMA public FROM public;
135
+
136
+ SELECT pg_reload_conf();
137
+ ```
138
+
139
+ ## Related
140
+
141
+ - Agent: `database-reviewer` - Full database review workflow
142
+ - Skill: `clickhouse-io` - ClickHouse analytics patterns
143
+ - Skill: `backend-patterns` - API and backend patterns
144
+
145
+ ---
146
+
147
+ *Based on Supabase Agent Skills (credit: Supabase team) (MIT License)*