원클릭으로
grpc-patterns
gRPC patterns Java Spring Boot. CONDITIONAL — loads only if project has grpc-spring-boot-starter in build.gradle.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
gRPC patterns Java Spring Boot. CONDITIONAL — loads only if project has grpc-spring-boot-starter in build.gradle.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
| name | grpc-patterns |
| description | gRPC patterns Java Spring Boot. CONDITIONAL — loads only if project has grpc-spring-boot-starter in build.gradle. |
| triggers | {"natural":["grpc","protobuf","rpc service","grpc streaming"],"code":["@GrpcService","@GrpcClient",".proto","StreamObserver","ManagedChannel"]} |
| applicability | {"always":false,"triggers":{"project_profile":["grpc:true"],"files_match":["**/*.proto","**/*GrpcService*.java","**/*GrpcClient*.java"],"code_patterns":["@GrpcService","@GrpcClient","StreamObserver","grpc.netty"],"task_keywords":["gRPC","protobuf","stream","bidirectional"],"related_rules":["rules/java/api-design.md","rules/java/security.md"]}} |
| relevance_assessment | HIGH 100%: project has grpc dep (verified grpc-spring-boot-starter in build.gradle) AND code touches @GrpcService/@GrpcClient/.proto MEDIUM 40-79%: project has grpc dep, tangential touch ZERO: no grpc dep (verify: grep grpc-spring-boot build.gradle = 0 results) — skip entirely |
gRPC patterns for Java 17+ / Spring Boot 3.x.
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.salesforce.servicelibs</groupId>
<artifactId>reactor-grpc-stub</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-testing</artifactId>
<scope>test</scope>
</dependency>
syntax = "proto3";
package com.example.order.v1;
option java_multiple_files = true;
option java_package = "com.example.order.v1";
service OrderService {
rpc CreateOrder (CreateOrderRequest) returns (CreateOrderResponse);
rpc GetOrder (GetOrderRequest) returns (OrderResponse);
rpc ListOrders (ListOrdersRequest) returns (stream OrderResponse); // server streaming
rpc StreamOrders(stream OrderEvent) returns (stream OrderResponse); // bidirectional
}
message CreateOrderRequest {
string customer_id = 1;
repeated OrderItem items = 2;
string idempotency_key = 3; // always include for mutations
}
message CreateOrderResponse {
string order_id = 1;
OrderStatus status = 2;
google.protobuf.Timestamp created_at = 3;
}
enum OrderStatus {
ORDER_STATUS_UNSPECIFIED = 0; // always define 0 as UNSPECIFIED
ORDER_STATUS_CREATED = 1;
ORDER_STATUS_CONFIRMED = 2;
ORDER_STATUS_CANCELLED = 3;
}
@GrpcService
@RequiredArgsConstructor
public class OrderGrpcService extends OrderServiceGrpc.OrderServiceImplBase {
private final OrderService orderService;
@Override
public void createOrder(CreateOrderRequest request,
StreamObserver<CreateOrderResponse> responseObserver) {
try {
var command = toCommand(request);
var result = orderService.create(command);
responseObserver.onNext(toProto(result));
responseObserver.onCompleted();
} catch (ValidationException e) {
responseObserver.onError(Status.INVALID_ARGUMENT
.withDescription(e.getMessage()).asRuntimeException());
} catch (NotFoundException e) {
responseObserver.onError(Status.NOT_FOUND
.withDescription(e.getMessage()).asRuntimeException());
} catch (Exception e) {
responseObserver.onError(Status.INTERNAL
.withDescription("Internal error").asRuntimeException());
}
}
@Override
public void listOrders(ListOrdersRequest request,
StreamObserver<OrderResponse> responseObserver) {
orderService.findByCustomer(request.getCustomerId())
.forEach(order -> responseObserver.onNext(toProto(order)));
responseObserver.onCompleted();
}
}
@Configuration
public class GrpcClientConfig {
@Bean
public OrderServiceGrpc.OrderServiceBlockingStub orderBlockingStub(
@GrpcClient("order-service") ManagedChannel channel) {
return OrderServiceGrpc.newBlockingStub(channel);
}
}
// application.yml
// grpc.client.order-service.address=static://order-service:9090
// grpc.client.order-service.negotiation-type=plaintext
// Map domain exceptions to gRPC Status codes
private Status toStatus(Throwable e) {
return switch (e) {
case NotFoundException ex -> Status.NOT_FOUND.withDescription(ex.getMessage());
case ValidationException ex -> Status.INVALID_ARGUMENT.withDescription(ex.getMessage());
case UnauthorizedException ex -> Status.UNAUTHENTICATED.withDescription(ex.getMessage());
default -> Status.INTERNAL.withDescription("Internal server error");
// ⚠️ Never expose internal details to client
};
}
@GrpcService
public class ReactiveOrderService extends ReactorOrderServiceGrpc.OrderServiceImplBase {
@Override
public Mono<CreateOrderResponse> createOrder(Mono<CreateOrderRequest> request) {
return request
.map(req -> toCommand(req))
.flatMap(orderService::create)
.map(order -> CreateOrderResponse.newBuilder()
.setOrderId(order.getId())
.setStatus(OrderStatus.ORDER_STATUS_CREATED)
.build());
}
@Override
public Flux<OrderResponse> listOrders(Mono<ListOrdersRequest> request) {
return request
.flatMapMany(req -> orderService.findByCustomer(req.getCustomerId()))
.map(this::toProto);
}
}
// Server-side auth interceptor
@Component
public class AuthInterceptor implements ServerInterceptor {
@Override
public <R, S> ServerCall.Listener<R> interceptCall(
ServerCall<R, S> call, Metadata headers, ServerCallHandler<R, S> next) {
String token = headers.get(AUTHORIZATION_METADATA_KEY);
if (!validateToken(token)) {
call.close(Status.UNAUTHENTICATED.withDescription("Invalid token"), new Metadata());
return new ServerCall.Listener<>() {};
}
Context ctx = Context.current().withValue(USER_ID_CTX_KEY, extractUserId(token));
return Contexts.interceptCall(ctx, call, headers, next);
}
}
@SpringBootTest
class OrderGrpcServiceTest {
private static Server server;
private static ManagedChannel channel;
@BeforeAll
static void setup() throws IOException {
OrderGrpcService service = new OrderGrpcService(mockOrderService());
server = InProcessServerBuilder.forName("test")
.directExecutor().addService(service).build().start();
channel = InProcessChannelBuilder.forName("test")
.directExecutor().build();
}
@Test
void shouldCreateOrder() {
var stub = OrderServiceGrpc.newBlockingStub(channel);
var request = CreateOrderRequest.newBuilder()
.setCustomerId("customer-1")
.addItems(OrderItem.newBuilder().setProductId("P1").setQuantity(2).build())
.build();
var response = stub.createOrder(request);
assertThat(response.getStatus()).isEqualTo(OrderStatus.ORDER_STATUS_CREATED);
}
}
grpc:
server:
port: 9090
security:
certificateChain: classpath:tls/server.crt
privateKey: classpath:tls/server.key
client:
order-service:
address: static://order-service:9090
negotiation-type: tls
keepAliveTime: 30s
keepAliveTimeout: 5s
| gRPC Status | HTTP Equivalent | Use When |
|---|---|---|
OK | 200 | Success |
INVALID_ARGUMENT | 400 | Bad input |
UNAUTHENTICATED | 401 | No/invalid auth |
PERMISSION_DENIED | 403 | Forbidden |
NOT_FOUND | 404 | Resource missing |
ALREADY_EXISTS | 409 | Duplicate |
RESOURCE_EXHAUSTED | 429 | Rate limited |
INTERNAL | 500 | Server error (never expose details) |
UNAVAILABLE | 503 | Downstream down |
DEADLINE_EXCEEDED | 504 | Timeout |
Unified Java code review + coding standards skill (alias "code-review"). Enforces ALL six rule sets — CORE-*, MVC-*, RX-*, WFL-*, XCT-*, JKS-* — across BUILD (REFACTOR self-check) and REVIEW (Stage 2 findings). Every finding cites [<P0-P4>][<RULE-ID>]. Also encodes Java 17+ patterns (records, sealed, pattern matching), naming, Lombok, immutability, Optional/Stream rules. Use whenever Claude writes new Java code, reviews a diff, refactors, or audits style. MANDATORY TRIGGERS — Java, Spring Boot, Spring MVC, Spring WebFlux, Project Reactor, Jackson, ObjectMapper, @JsonProperty, @JsonCreator, @JsonTypeInfo, @JsonFormat, JSON, BigDecimal, money, @Transactional, R2DBC, JpaRepository, Mono, Flux, WebClient, code review, audit, refactor, REFACTOR step, /dc-review, /build.
Mandatory pre-flight discovery before every workflow gate. Enumerate ALL skills + rules ≥1% relevant. Justify every SKIP with concrete evidence. Produces artifact downstream gates + subagents consume. Meta-skill — fires before all other skills.
Surface ambiguity, missing requirements, hidden assumptions BEFORE planning. Fires after triage for standard (vague request) or high-stakes (always). Updates CONTEXT.md vocabulary. Produces agreed-requirements artifact feeding Plan gate.
REST API design patterns for Spring Boot — HTTP methods, status codes, URL conventions, RFC 7807 ProblemDetail errors, pagination, versioning, validation, and OpenAPI documentation. Use when designing REST endpoints, choosing HTTP status codes, implementing error responses, adding pagination to list APIs, versioning APIs, or generating OpenAPI/Swagger specs.
Hexagonal architecture, DDD, CQRS, and event sourcing for Java Spring applications. Use when designing package structure, creating Aggregate Roots or Value Objects, implementing ports and adapters, setting up CQRS command/query separation, wiring domain events, writing ArchUnit tests, or creating solution architecture documents and ADRs.
Foundation skill — auto-loads at SessionStart. Teaches 5-layer adaptive workflow, 1% pre-flight discovery rule, triage routing, skill announcement contract, project detection. All other skills depend on this. Do NOT manually load.
SOC 직업 분류 기준