Capa de interoperabilidad · Prueba técnica de arquitectura

gRPC de inventario

Contrato Protocol Buffers de inventory-service. Es la única llamada síncrona interna: order-service reserva, confirma y libera. Decisión en ADR-014.

syntax = "proto3";

package andesretail.inventory.v1;

option java_multiple_files = true;
option java_package = "com.andesretail.inventory.v1";

import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";

// API interna de reservas. Unico punto sincrono entre servicios de dominio:
// order-service llama a inventory-service.
// Diseno en docs/to-be/03-stock-vendible-y-reservas.md.
// Todas las operaciones son idempotentes por order_id.
service InventoryService {
  // Reserva todas las lineas o ninguna.
  rpc Reserve(ReserveRequest) returns (ReserveResponse);
  // Confirma tras el pago aprobado. Si la reserva vencio, intenta reservar de nuevo.
  rpc Confirm(ConfirmRequest) returns (ConfirmResponse);
  // Libera por pago rechazado, vencimiento o cancelacion.
  rpc Release(ReleaseRequest) returns (ReleaseResponse);
  rpc GetReservation(GetReservationRequest) returns (GetReservationResponse);
}

enum ReservationStatus {
  RESERVATION_STATUS_UNSPECIFIED = 0;
  RESERVATION_STATUS_HELD = 1;
  RESERVATION_STATUS_CONFIRMED = 2;
  RESERVATION_STATUS_RELEASED = 3;
  RESERVATION_STATUS_EXPIRED = 4;
  RESERVATION_STATUS_CONSUMED = 5;
}

enum ReserveOutcome {
  RESERVE_OUTCOME_UNSPECIFIED = 0;
  RESERVE_OUTCOME_HELD = 1;
  RESERVE_OUTCOME_INSUFFICIENT_STOCK = 2;
  RESERVE_OUTCOME_UNKNOWN_SKU = 3;
  // El canal no vende desde la ubicación de la línea (política `locations` del canal).
  RESERVE_OUTCOME_LOCATION_NOT_ALLOWED = 4;
}

message ReservationLine {
  string sku = 1;
  string location_id = 2;
  int32 quantity = 3;
}

message ReserveRequest {
  string order_id = 1;
  string partner_id = 2;
  string channel = 3;
  repeated ReservationLine lines = 4;
  // Vigencia de la reserva. Si falta, se usa la del canal (15 minutos por defecto).
  google.protobuf.Duration ttl = 5;
  string correlation_id = 6;
}

message LineShortage {
  string sku = 1;
  string location_id = 2;
  int32 requested = 3;
  int32 available = 4;
}

message ReserveResponse {
  ReserveOutcome outcome = 1;
  Reservation reservation = 2;
  // Lineas que impidieron reservar, cuando outcome no es HELD.
  repeated LineShortage shortages = 3;
}

message ConfirmRequest {
  string order_id = 1;
  string correlation_id = 2;
}

message ReleaseRequest {
  string order_id = 1;
  // PAYMENT_REJECTED, PAYMENT_TIMEOUT, ORDER_CANCELLED.
  string reason = 2;
  string correlation_id = 3;
}

message GetReservationRequest {
  string order_id = 1;
}

message Reservation {
  string reservation_id = 1;
  string order_id = 2;
  ReservationStatus status = 3;
  google.protobuf.Timestamp expires_at = 4;
  repeated ReservationLine lines = 5;
}

// Una respuesta por RPC (ADR-014): cada una puede crecer sin tocar a las otras.
message ConfirmResponse {
  Reservation reservation = 1;
}

message ReleaseResponse {
  Reservation reservation = 1;
}

message GetReservationResponse {
  Reservation reservation = 1;
}

inventory.proto