chore: initial commit

This commit is contained in:
2024-04-16 22:27:52 +01:00
commit 531b5dabe2
194 changed files with 27071 additions and 0 deletions

View File

@@ -0,0 +1,781 @@
swagger: "2.0"
info:
title: Stocklet
version: 0.1.0
contact:
name: GitHub Repository
url: https://github.com/hexolan/stocklet
license:
name: AGPL-3.0
url: https://github.com/hexolan/stocklet/blob/main/LICENSE
tags:
- name: AuthService
- name: OrderService
- name: PaymentService
- name: ProductService
- name: ShippingService
- name: UserService
- name: WarehouseService
host: localhost
schemes:
- http
consumes:
- application/json
produces:
- application/json
paths:
/v1/auth/jwks:
get:
operationId: AuthService_GetJwks
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1GetJwksResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
tags:
- AuthService
/v1/auth/login:
post:
operationId: AuthService_LoginPassword
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1LoginPasswordResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: body
in: body
required: true
schema:
$ref: '#/definitions/v1LoginPasswordRequest'
tags:
- AuthService
/v1/auth/password:
post:
operationId: AuthService_SetPassword
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1SetPasswordResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: body
in: body
required: true
schema:
$ref: '#/definitions/v1SetPasswordRequest'
tags:
- AuthService
/v1/auth/service:
get:
summary: View information about the service.
description: buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
operationId: AuthService_ServiceInfo
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ServiceInfoResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
tags:
- AuthService
/v1/order/list:
get:
summary: |-
Get a list of a customer's orders.
If accessed through the gateway - shows the current user's orders.
operationId: OrderService_ViewOrders
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewOrdersResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: customerId
in: query
required: false
type: string
tags:
- OrderService
/v1/order/orders/{orderId}:
get:
operationId: OrderService_ViewOrder
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewOrderResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: orderId
in: path
required: true
type: string
tags:
- OrderService
/v1/order/place:
post:
operationId: OrderService_PlaceOrder
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1PlaceOrderResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: cart
in: body
required: true
schema:
type: object
additionalProperties:
type: integer
format: int32
- name: customerId
in: query
required: false
type: string
tags:
- OrderService
/v1/order/service:
get:
summary: View information about the service.
description: buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
operationId: OrderService_ServiceInfo
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ServiceInfoResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
tags:
- OrderService
/v1/payment/balance/{customerId}:
get:
operationId: PaymentService_ViewBalance
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewBalanceResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: customerId
in: path
required: true
type: string
tags:
- PaymentService
/v1/payment/service:
get:
summary: View information about the service.
description: buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
operationId: PaymentService_ServiceInfo
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ServiceInfoResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
tags:
- PaymentService
/v1/payment/transaction/{transactionId}:
get:
operationId: PaymentService_ViewTransaction
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewTransactionResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: transactionId
in: path
required: true
type: string
tags:
- PaymentService
/v1/product/list:
get:
operationId: ProductService_ViewProducts
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewProductsResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
tags:
- ProductService
/v1/product/service:
get:
summary: View information about the service.
description: buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
operationId: ProductService_ServiceInfo
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ServiceInfoResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
tags:
- ProductService
/v1/product/{id}:
get:
operationId: ProductService_ViewProduct
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewProductResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: id
in: path
required: true
type: string
tags:
- ProductService
/v1/shipping/service:
get:
summary: View information about the service.
description: buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
operationId: ShippingService_ServiceInfo
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ServiceInfoResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
tags:
- ShippingService
/v1/shipping/shipment/{shipmentId}:
get:
operationId: ShippingService_ViewShipment
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewShipmentResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: shipmentId
in: path
required: true
type: string
tags:
- ShippingService
/v1/shipping/shipment/{shipmentId}/manifest:
get:
operationId: ShippingService_ViewShipmentManifest
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewShipmentManifestResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: shipmentId
in: path
required: true
type: string
tags:
- ShippingService
/v1/user/register:
post:
operationId: UserService_RegisterUser
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1RegisterUserResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: firstName
in: query
required: true
type: string
- name: lastName
in: query
required: true
type: string
- name: email
in: query
required: true
type: string
- name: password
in: query
required: true
type: string
tags:
- UserService
/v1/user/service:
get:
summary: View information about the service.
description: buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
operationId: UserService_ServiceInfo
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ServiceInfoResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
tags:
- UserService
/v1/user/users/{id}:
get:
operationId: UserService_ViewUser
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewUserResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: id
in: path
required: true
type: string
tags:
- UserService
/v1/warehouse/product/{productId}:
get:
operationId: WarehouseService_ViewProductStock
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewProductStockResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: productId
in: path
required: true
type: string
tags:
- WarehouseService
/v1/warehouse/reservation/{reservationId}:
get:
operationId: WarehouseService_ViewReservation
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ViewReservationResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: reservationId
in: path
required: true
type: string
tags:
- WarehouseService
/v1/warehouse/service:
get:
summary: View information about the service.
description: buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
operationId: WarehouseService_ServiceInfo
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ServiceInfoResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
tags:
- WarehouseService
definitions:
protobufAny:
type: object
properties:
'@type':
type: string
additionalProperties: {}
rpcStatus:
type: object
properties:
code:
type: integer
format: int32
message:
type: string
details:
type: array
items:
type: object
$ref: '#/definitions/protobufAny'
v1AuthToken:
type: object
properties:
tokenType:
type: string
accessToken:
type: string
expiresIn:
type: string
format: int64
v1CustomerBalance:
type: object
properties:
customerId:
type: string
balance:
type: number
format: float
v1GetJwksResponse:
type: object
properties:
keys:
type: array
items:
type: object
$ref: '#/definitions/v1PublicEcJWK'
v1LoginPasswordRequest:
type: object
properties:
userId:
type: string
password:
type: string
required:
- userId
- password
v1LoginPasswordResponse:
type: object
properties:
detail:
type: string
data:
$ref: '#/definitions/v1AuthToken'
v1Order:
type: object
properties:
id:
type: string
status:
$ref: '#/definitions/v1OrderStatus'
items:
type: object
additionalProperties:
type: integer
format: int32
description: '''items'' consists of a mapping of Product ID to Quantity.'
customerId:
type: string
transactionId:
type: string
shippingId:
type: string
createdAt:
type: string
format: int64
updatedAt:
type: string
format: int64
v1OrderStatus:
type: string
enum:
- ORDER_STATUS_UNSPECIFIED
- ORDER_STATUS_PROCESSING
- ORDER_STATUS_PENDING
- ORDER_STATUS_REJECTED
- ORDER_STATUS_APPROVED
- ORDER_STATUS_COMPLETED
default: ORDER_STATUS_UNSPECIFIED
title: |-
- ORDER_STATUS_PROCESSING: awaiting price quotes for products
- ORDER_STATUS_PENDING: awaiting stock allocation, shipping allotment and payment
v1PlaceOrderResponse:
type: object
properties:
order:
$ref: '#/definitions/v1Order'
v1Product:
type: object
properties:
id:
type: string
name:
type: string
description:
type: string
price:
type: number
format: float
createdAt:
type: string
format: int64
updatedAt:
type: string
format: int64
v1ProductStock:
type: object
properties:
productId:
type: string
quantity:
type: integer
format: int32
v1PublicEcJWK:
type: object
properties:
kty:
type: string
use:
type: string
alg:
type: string
crv:
type: string
x:
type: string
"y":
type: string
v1RegisterUserResponse:
type: object
properties:
user:
$ref: '#/definitions/v1User'
v1Reservation:
type: object
properties:
id:
type: string
orderId:
type: string
reservedStock:
type: array
items:
type: object
$ref: '#/definitions/v1ReservationStock'
createdAt:
type: string
format: int64
v1ReservationStock:
type: object
properties:
productId:
type: string
quantity:
type: integer
format: int32
v1ServiceInfoResponse:
type: object
properties:
name:
type: string
source:
type: string
sourceLicense:
type: string
v1SetPasswordRequest:
type: object
properties:
userId:
type: string
password:
type: string
required:
- userId
- password
v1SetPasswordResponse:
type: object
properties:
detail:
type: string
v1Shipment:
type: object
properties:
id:
type: string
orderId:
type: string
dispatched:
type: boolean
createdAt:
type: string
format: int64
updatedAt:
type: string
format: int64
v1ShipmentItem:
type: object
properties:
shipmentId:
type: string
productId:
type: string
quantity:
type: integer
format: int32
v1Transaction:
type: object
properties:
id:
type: string
amount:
type: number
format: float
orderId:
type: string
customerId:
type: string
reversedAt:
type: string
format: int64
description: Optional - If set, then the transaction has been refunded.
processedAt:
type: string
format: int64
v1User:
type: object
properties:
id:
type: string
email:
type: string
firstName:
type: string
lastName:
type: string
createdAt:
type: string
format: int64
updatedAt:
type: string
format: int64
v1ViewBalanceResponse:
type: object
properties:
balance:
$ref: '#/definitions/v1CustomerBalance'
v1ViewOrderResponse:
type: object
properties:
order:
$ref: '#/definitions/v1Order'
v1ViewOrdersResponse:
type: object
properties:
orders:
type: array
items:
type: object
$ref: '#/definitions/v1Order'
v1ViewProductResponse:
type: object
properties:
product:
$ref: '#/definitions/v1Product'
v1ViewProductStockResponse:
type: object
properties:
stock:
$ref: '#/definitions/v1ProductStock'
v1ViewProductsResponse:
type: object
properties:
products:
type: array
items:
type: object
$ref: '#/definitions/v1Product'
v1ViewReservationResponse:
type: object
properties:
reservation:
$ref: '#/definitions/v1Reservation'
v1ViewShipmentManifestResponse:
type: object
properties:
manifest:
type: array
items:
type: object
$ref: '#/definitions/v1ShipmentItem'
v1ViewShipmentResponse:
type: object
properties:
shipment:
$ref: '#/definitions/v1Shipment'
v1ViewTransactionResponse:
type: object
properties:
transaction:
$ref: '#/definitions/v1Transaction'
v1ViewUserResponse:
type: object
properties:
user:
$ref: '#/definitions/v1User'

18
schema/protobufs/buf.lock Normal file
View File

@@ -0,0 +1,18 @@
# Generated by buf. DO NOT EDIT.
version: v1
deps:
- remote: buf.build
owner: bufbuild
repository: protovalidate
commit: e097f827e65240ac9fd4b1158849a8fc
digest: shake256:f19252436fd9ded945631e2ffaaed28247a92c9015ccf55ae99db9fb3d9600c4fdb00fd2d3bd7701026ec2fd4715c5129e6ae517c25a59ba690020cfe80bf8ad
- remote: buf.build
owner: googleapis
repository: googleapis
commit: b30c5775bfb3485d9da2e87b26590ac9
digest: shake256:9d0caaf056949a0e1c883b9849d8a2fa66e22f18a2a48f867d1a8c700aa22abee50ad3ef0d8171637457cadc43c584998bdf3adac55da0f9e4614c72686b057d
- remote: buf.build
owner: grpc-ecosystem
repository: grpc-gateway
commit: 3f42134f4c564983838425bc43c7a65f
digest: shake256:3d11d4c0fe5e05fda0131afefbce233940e27f0c31c5d4e385686aea58ccd30f72053f61af432fa83f1fc11cda57f5f18ca3da26a29064f73c5a0d076bba8d92

12
schema/protobufs/buf.yaml Normal file
View File

@@ -0,0 +1,12 @@
version: v1
deps:
- buf.build/googleapis/googleapis
- buf.build/grpc-ecosystem/grpc-gateway
- buf.build/bufbuild/protovalidate
lint:
use:
- DEFAULT
allow_comment_ignores: true
breaking:
use:
- FILE

View File

@@ -0,0 +1,110 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.auth.v1;
import "buf/validate/validate.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/api/visibility.proto";
import "google/protobuf/empty.proto";
import "stocklet/auth/v1/types.proto";
import "stocklet/common/v1/requests.proto";
import "stocklet/events/v1/user.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/auth/v1;auth_v1";
service AuthService {
// View information about the service.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
rpc ServiceInfo(stocklet.common.v1.ServiceInfoRequest) returns (stocklet.common.v1.ServiceInfoResponse) {
option (google.api.http) = {get: "/v1/auth/service"};
}
rpc GetJwks(GetJwksRequest) returns (GetJwksResponse) {
option (google.api.http) = {get: "/v1/auth/jwks"};
}
rpc LoginPassword(LoginPasswordRequest) returns (LoginPasswordResponse) {
option (google.api.http) = {
post: "/v1/auth/login"
body: "*"
};
}
rpc SetPassword(SetPasswordRequest) returns (SetPasswordResponse) {
option (google.api.http) = {
post: "/v1/auth/password"
body: "*"
};
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessUserDeletedEvent(stocklet.events.v1.UserDeletedEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
}
message GetJwksRequest {}
message GetJwksResponse {
repeated PublicEcJWK keys = 1;
}
message LoginPasswordRequest {
string user_id = 1 [
(google.api.field_behavior) = REQUIRED,
(buf.validate.field).string.min_len = 1
];
string password = 2 [
(google.api.field_behavior) = REQUIRED,
(buf.validate.field).string = {
min_len: 1;
max_len: 64;
}
];
}
message LoginPasswordResponse {
string detail = 1;
AuthToken data = 2;
}
message SetPasswordRequest {
string user_id = 1 [
(google.api.field_behavior) = REQUIRED,
(buf.validate.field).string.min_len = 1
];
string password = 2 [
(google.api.field_behavior) = REQUIRED,
(buf.validate.field).string = {
min_len: 1;
max_len: 64;
}
];
}
message SetPasswordResponse {
string detail = 1;
}

View File

@@ -0,0 +1,35 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.auth.v1;
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/auth/v1;auth_v1";
message PublicEcJWK {
string kty = 1;
string use = 2;
string alg = 3;
string crv = 4;
string x = 5;
string y = 6;
}
message AuthToken {
string token_type = 1;
string access_token = 2;
int64 expires_in = 3;
}

View File

@@ -0,0 +1,28 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.common.v1;
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/common/v1;common_v1";
message ServiceInfoRequest {}
message ServiceInfoResponse {
string name = 1;
string source = 2;
string source_license = 3;
}

View File

@@ -0,0 +1,63 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.events.v1;
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/events/v1;events_v1";
// Order Status = processing
message OrderCreatedEvent {
int32 revision = 1;
string order_id = 2;
string customer_id = 3;
map<string, int32> item_quantities = 4;
}
// Order Status = pending
message OrderPendingEvent {
int32 revision = 1;
string order_id = 2;
string customer_id = 3;
map<string, int32> item_quantities = 4;
float items_price = 5;
float total_price = 6;
}
// Order Status = rejected
message OrderRejectedEvent {
int32 revision = 1;
string order_id = 2;
optional string transaction_id = 3;
optional string shipping_id = 4;
}
// Order Status = approved
message OrderApprovedEvent {
int32 revision = 1;
string order_id = 2;
string transaction_id = 3;
string shipping_id = 4;
}

View File

@@ -0,0 +1,88 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.events.v1;
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/events/v1;events_v1";
message BalanceCreatedEvent {
int32 revision = 1;
string customer_id = 2;
float balance = 3;
}
message BalanceCreditedEvent {
int32 revision = 1;
string customer_id = 2;
float amount = 3;
float new_balance = 4;
}
message BalanceDebitedEvent {
int32 revision = 1;
string customer_id = 2;
float amount = 3;
float new_balance = 4;
}
message BalanceClosedEvent {
int32 revision = 1;
string customer_id = 2;
float balance = 3;
}
message TransactionLoggedEvent {
int32 revision = 1;
string transaction_id = 2;
float amount = 3;
string order_id = 4;
string customer_id = 5;
}
message TransactionReversedEvent {
int32 revision = 1;
string transaction_id = 2;
float amount = 3;
string order_id = 4;
string customer_id = 5;
}
message PaymentProcessedEvent {
enum Type {
TYPE_UNSPECIFIED = 0;
TYPE_FAILED = 1;
TYPE_SUCCESS = 2;
}
int32 revision = 1;
Type type = 2;
string order_id = 3;
string customer_id = 4;
float amount = 5;
optional string transaction_id = 6;
}

View File

@@ -0,0 +1,63 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.events.v1;
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/events/v1;events_v1";
message ProductCreatedEvent {
int32 revision = 1;
string product_id = 2;
string name = 3;
string description = 4;
float price = 5;
}
message ProductPriceUpdatedEvent {
int32 revision = 1;
string product_id = 2;
float price = 3;
}
message ProductDeletedEvent {
int32 revision = 1;
string product_id = 2;
}
message ProductPriceQuoteEvent {
enum Type {
TYPE_UNSPECIFIED = 0;
TYPE_UNAVALIABLE = 1;
TYPE_AVALIABLE = 2;
}
int32 revision = 1;
Type type = 2;
string order_id = 3;
// Product ID: Quantity
map<string, int32> product_quantities = 4;
// Product ID: Unit Price
map<string, float> product_prices = 5;
float total_price = 6;
}

View File

@@ -0,0 +1,52 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.events.v1;
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/events/v1;events_v1";
message ShipmentAllocationEvent {
enum Type {
TYPE_UNSPECIFIED = 0;
TYPE_FAILED = 1;
TYPE_ALLOCATED = 2;
TYPE_ALLOCATION_RELEASED = 3;
}
int32 revision = 1;
Type type = 2;
message OrderMetadata {
string customer_id = 1;
float items_price = 2;
float total_price = 3;
}
string order_id = 3;
OrderMetadata order_metadata = 4;
string shipment_id = 5; // provided with type enum value 2+
map<string, int32> product_quantities = 6;
}
message ShipmentDispatchedEvent {
int32 revision = 1;
string shipment_id = 2;
string order_id = 3;
map<string, int32> product_quantities = 4;
}

View File

@@ -0,0 +1,43 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.events.v1;
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/events/v1;events_v1";
message UserCreatedEvent {
int32 revision = 1;
string user_id = 2;
string email = 3;
string first_name = 4;
string last_name = 5;
}
message UserEmailUpdatedEvent {
int32 revision = 1;
string user_id = 2;
string email = 3;
}
message UserDeletedEvent {
int32 revision = 1;
string user_id = 2;
string email = 3;
}

View File

@@ -0,0 +1,75 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.events.v1;
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/events/v1;events_v1";
message StockCreatedEvent {
int32 revision = 1;
string product_id = 2;
int32 quantity = 3;
}
message StockAddedEvent {
int32 revision = 1;
string product_id = 2;
int32 amount = 3;
// If the stock is returned as a result of a stock reservation outcome,
// then the reservation id will be included for reference.
optional string reservation_id = 4;
}
message StockRemovedEvent {
int32 revision = 1;
string product_id = 2;
int32 amount = 3;
// If the stock is removed as a result of a stock reservation being closed,
// then the reservation id will be included for reference.
optional string reservation_id = 4;
}
message StockReservationEvent {
enum Type {
TYPE_UNSPECIFIED = 0;
TYPE_INSUFFICIENT_STOCK = 1;
TYPE_STOCK_RESERVED = 2;
TYPE_STOCK_RETURNED = 3;
TYPE_STOCK_CONSUMED = 4;
}
int32 revision = 1;
Type type = 2;
message OrderMetadata {
string customer_id = 1;
float items_price = 2;
float total_price = 3;
}
string order_id = 3;
OrderMetadata order_metadata = 4;
string reservation_id = 5; // provided with type enum value 2+
map<string, int32> reservation_stock = 6; // Product ID: Quantity (provided with type enum value 2+)
repeated string insufficient_stock = 7; // Product IDs (only provided with TYPE_INSUFFICIENT_STOCK)
}

View File

@@ -0,0 +1,126 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.order.v1;
import "buf/validate/validate.proto";
import "google/api/annotations.proto";
import "google/api/visibility.proto";
import "google/protobuf/empty.proto";
import "stocklet/common/v1/requests.proto";
import "stocklet/events/v1/payment.proto";
import "stocklet/events/v1/product.proto";
import "stocklet/events/v1/shipping.proto";
import "stocklet/events/v1/warehouse.proto";
import "stocklet/order/v1/types.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/order/v1;order_v1";
service OrderService {
// View information about the service.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
rpc ServiceInfo(stocklet.common.v1.ServiceInfoRequest) returns (stocklet.common.v1.ServiceInfoResponse) {
option (google.api.http) = {get: "/v1/order/service"};
}
rpc ViewOrder(ViewOrderRequest) returns (ViewOrderResponse) {
option (google.api.http) = {get: "/v1/order/orders/{order_id}"};
}
// Get a list of a customer's orders.
// If accessed through the gateway - shows the current user's orders.
rpc ViewOrders(ViewOrdersRequest) returns (ViewOrdersResponse) {
option (google.api.http) = {get: "/v1/order/list"};
}
rpc PlaceOrder(PlaceOrderRequest) returns (PlaceOrderResponse) {
option (google.api.http) = {
post: "/v1/order/place"
body: "cart"
};
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessProductPriceQuoteEvent(stocklet.events.v1.ProductPriceQuoteEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessStockReservationEvent(stocklet.events.v1.StockReservationEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessShipmentAllocationEvent(stocklet.events.v1.ShipmentAllocationEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessPaymentProcessedEvent(stocklet.events.v1.PaymentProcessedEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
}
message ViewOrderRequest {
string order_id = 1 [(buf.validate.field).string.min_len = 1];
}
message ViewOrderResponse {
Order order = 1;
}
message ViewOrdersRequest {
string customer_id = 1 [(buf.validate.field).string.min_len = 1];
}
message ViewOrdersResponse {
repeated Order orders = 1;
}
message GetOrderItemsRequest {
string id = 1 [(buf.validate.field).string.min_len = 1];
}
message GetOrderItemsResponse {
map<string, int32> items = 1 [(buf.validate.field).map.values.int32.gt = 0];
}
message PlaceOrderRequest {
map<string, int32> cart = 1 [(buf.validate.field).map.values.int32.gt = 0];
string customer_id = 2;
}
message PlaceOrderResponse {
Order order = 1;
}

View File

@@ -0,0 +1,51 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.order.v1;
import "buf/validate/validate.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/order/v1;order_v1";
enum OrderStatus {
ORDER_STATUS_UNSPECIFIED = 0;
ORDER_STATUS_PROCESSING = 1; // awaiting price quotes for products
ORDER_STATUS_PENDING = 2; // awaiting stock allocation, shipping allotment and payment
ORDER_STATUS_REJECTED = 3;
ORDER_STATUS_APPROVED = 4;
ORDER_STATUS_COMPLETED = 5;
}
message Order {
string id = 1 [(buf.validate.field).string.min_len = 1];
OrderStatus status = 2 [(buf.validate.field).enum = {
defined_only: true,
not_in: [0]
}];
// 'items' consists of a mapping of Product ID to Quantity.
map<string, int32> items = 3 [(buf.validate.field).map.values.int32.gt = 0];
string customer_id = 4 [(buf.validate.field).string.min_len = 1];
optional string transaction_id = 5 [(buf.validate.field).string.min_len = 1];
optional string shipping_id = 6 [(buf.validate.field).string.min_len = 1];
int64 created_at = 7;
optional int64 updated_at = 8;
}

View File

@@ -0,0 +1,89 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.payment.v1;
import "buf/validate/validate.proto";
import "google/api/annotations.proto";
import "google/api/visibility.proto";
import "google/protobuf/empty.proto";
import "stocklet/common/v1/requests.proto";
import "stocklet/events/v1/shipping.proto";
import "stocklet/events/v1/user.proto";
import "stocklet/payment/v1/types.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/payment/v1;payment_v1";
service PaymentService {
// View information about the service.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
rpc ServiceInfo(stocklet.common.v1.ServiceInfoRequest) returns (stocklet.common.v1.ServiceInfoResponse) {
option (google.api.http) = {get: "/v1/payment/service"};
}
rpc ViewTransaction(ViewTransactionRequest) returns (ViewTransactionResponse) {
option (google.api.http) = {get: "/v1/payment/transaction/{transaction_id}"};
}
rpc ViewBalance(ViewBalanceRequest) returns (ViewBalanceResponse) {
option (google.api.http) = {get: "/v1/payment/balance/{customer_id}"};
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessUserCreatedEvent(stocklet.events.v1.UserCreatedEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessUserDeletedEvent(stocklet.events.v1.UserDeletedEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessShipmentAllocationEvent(stocklet.events.v1.ShipmentAllocationEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
}
message ViewTransactionRequest {
string transaction_id = 1 [(buf.validate.field).string.min_len = 1];
}
message ViewTransactionResponse {
Transaction transaction = 1;
}
message ViewBalanceRequest {
string customer_id = 1 [(buf.validate.field).string.min_len = 1];
}
message ViewBalanceResponse {
CustomerBalance balance = 1;
}

View File

@@ -0,0 +1,41 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.payment.v1;
import "buf/validate/validate.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/payment/v1;payment_v1";
message Transaction {
string id = 1 [(buf.validate.field).string.min_len = 1];
float amount = 2 [(buf.validate.field).float.gte = 0.0];
string order_id = 3 [(buf.validate.field).string.min_len = 1];
string customer_id = 4 [(buf.validate.field).string.min_len = 1];
// Optional - If set, then the transaction has been refunded.
optional int64 reversed_at = 5;
int64 processed_at = 6;
}
message CustomerBalance {
string customer_id = 1 [(buf.validate.field).string.min_len = 1];
float balance = 2 [(buf.validate.field).float.gte = 0.0];
}

View File

@@ -0,0 +1,68 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.product.v1;
import "buf/validate/validate.proto";
import "google/api/annotations.proto";
import "google/api/visibility.proto";
import "google/protobuf/empty.proto";
import "stocklet/common/v1/requests.proto";
import "stocklet/events/v1/order.proto";
import "stocklet/product/v1/types.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/product/v1;product_v1";
service ProductService {
// View information about the service.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
rpc ServiceInfo(stocklet.common.v1.ServiceInfoRequest) returns (stocklet.common.v1.ServiceInfoResponse) {
option (google.api.http) = {get: "/v1/product/service"};
}
rpc ViewProduct(ViewProductRequest) returns (ViewProductResponse) {
option (google.api.http) = {get: "/v1/product/{id}"};
}
rpc ViewProducts(ViewProductsRequest) returns (ViewProductsResponse) {
option (google.api.http) = {get: "/v1/product/list"};
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessOrderCreatedEvent(stocklet.events.v1.OrderCreatedEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
}
message ViewProductRequest {
string id = 1 [(buf.validate.field).string.min_len = 1];
}
message ViewProductResponse {
Product product = 1;
}
message ViewProductsRequest {}
message ViewProductsResponse {
repeated Product products = 1;
}

View File

@@ -0,0 +1,34 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.product.v1;
import "buf/validate/validate.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/product/v1;product_v1";
message Product {
string id = 1 [(buf.validate.field).string.min_len = 1];
string name = 2 [(buf.validate.field).string.min_len = 1];
string description = 3 [(buf.validate.field).string.min_len = 1];
float price = 4 [(buf.validate.field).float.gte = 0.0];
int64 created_at = 5;
optional int64 updated_at = 6;
}

View File

@@ -0,0 +1,80 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.shipping.v1;
import "buf/validate/validate.proto";
import "google/api/annotations.proto";
import "google/api/visibility.proto";
import "google/protobuf/empty.proto";
import "stocklet/common/v1/requests.proto";
import "stocklet/events/v1/payment.proto";
import "stocklet/events/v1/warehouse.proto";
import "stocklet/shipping/v1/types.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/shipping/v1;shipping_v1";
service ShippingService {
// View information about the service.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
rpc ServiceInfo(stocklet.common.v1.ServiceInfoRequest) returns (stocklet.common.v1.ServiceInfoResponse) {
option (google.api.http) = {get: "/v1/shipping/service"};
}
rpc ViewShipment(ViewShipmentRequest) returns (ViewShipmentResponse) {
option (google.api.http) = {get: "/v1/shipping/shipment/{shipment_id}"};
}
rpc ViewShipmentManifest(ViewShipmentManifestRequest) returns (ViewShipmentManifestResponse) {
option (google.api.http) = {get: "/v1/shipping/shipment/{shipment_id}/manifest"};
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessStockReservationEvent(stocklet.events.v1.StockReservationEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessPaymentProcessedEvent(stocklet.events.v1.PaymentProcessedEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
}
message ViewShipmentRequest {
string shipment_id = 1 [(buf.validate.field).string.min_len = 1];
}
message ViewShipmentResponse {
Shipment shipment = 1;
}
message ViewShipmentManifestRequest {
string shipment_id = 1 [(buf.validate.field).string.min_len = 1];
}
message ViewShipmentManifestResponse {
repeated ShipmentItem manifest = 1;
}

View File

@@ -0,0 +1,39 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.shipping.v1;
import "buf/validate/validate.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/shipping/v1;shipping_v1";
message Shipment {
string id = 1 [(buf.validate.field).string.min_len = 1];
string order_id = 2 [(buf.validate.field).string.min_len = 1];
bool dispatched = 3;
int64 created_at = 5;
optional int64 updated_at = 6;
}
message ShipmentItem {
string shipment_id = 1 [(buf.validate.field).string.min_len = 1];
string product_id = 2 [(buf.validate.field).string.min_len = 1];
int32 quantity = 3 [(buf.validate.field).int32.gt = 0];
}

View File

@@ -0,0 +1,39 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
// buf:lint:ignore PACKAGE_VERSION_SUFFIX
package stocklet;
import "protoc-gen-openapiv2/options/annotations.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen";
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
info: {
title: "Stocklet";
version: "0.1.0";
contact: {
name: "GitHub Repository";
url: "https://github.com/hexolan/stocklet";
};
license: {
name: "AGPL-3.0";
url: "https://github.com/hexolan/stocklet/blob/main/LICENSE";
}
};
host: "localhost";
schemes: HTTP;
};

View File

@@ -0,0 +1,86 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.user.v1;
import "buf/validate/validate.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "stocklet/common/v1/requests.proto";
import "stocklet/user/v1/types.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/user/v1;user_v1";
service UserService {
// View information about the service.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
rpc ServiceInfo(stocklet.common.v1.ServiceInfoRequest) returns (stocklet.common.v1.ServiceInfoResponse) {
option (google.api.http) = {get: "/v1/user/service"};
}
rpc ViewUser(ViewUserRequest) returns (ViewUserResponse) {
option (google.api.http) = {get: "/v1/user/users/{id}"};
}
rpc RegisterUser(RegisterUserRequest) returns (RegisterUserResponse) {
option (google.api.http) = {post: "/v1/user/register"};
}
}
message ViewUserRequest {
string id = 1 [(buf.validate.field).string.min_len = 1];
}
message ViewUserResponse {
User user = 1;
}
message RegisterUserRequest {
string first_name = 1 [
(google.api.field_behavior) = REQUIRED,
(buf.validate.field).string = {
min_len: 1;
max_len: 35;
}
];
string last_name = 2 [
(google.api.field_behavior) = REQUIRED,
(buf.validate.field).string = {
min_len: 1;
max_len: 35;
}
];
string email = 3 [
(google.api.field_behavior) = REQUIRED,
(buf.validate.field).string.email = true
];
string password = 4 [
(google.api.field_behavior) = REQUIRED,
(buf.validate.field).string = {
min_len: 1;
max_len: 64;
}
];
}
message RegisterUserResponse {
User user = 1;
}

View File

@@ -0,0 +1,40 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.user.v1;
import "buf/validate/validate.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/user/v1;user_v1";
message User {
string id = 1 [(buf.validate.field).string.min_len = 1];
string email = 2 [(buf.validate.field).string.email = true];
string first_name = 3 [(buf.validate.field).string = {
min_len: 1;
max_len: 35;
}];
string last_name = 4 [(buf.validate.field).string = {
min_len: 1;
max_len: 35;
}];
int64 created_at = 5;
optional int64 updated_at = 6;
}

View File

@@ -0,0 +1,100 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.warehouse.v1;
import "buf/validate/validate.proto";
import "google/api/annotations.proto";
import "google/api/visibility.proto";
import "google/protobuf/empty.proto";
import "stocklet/common/v1/requests.proto";
import "stocklet/events/v1/order.proto";
import "stocklet/events/v1/payment.proto";
import "stocklet/events/v1/product.proto";
import "stocklet/events/v1/shipping.proto";
import "stocklet/warehouse/v1/types.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/warehouse/v1;warehouse_v1";
service WarehouseService {
// View information about the service.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
rpc ServiceInfo(stocklet.common.v1.ServiceInfoRequest) returns (stocklet.common.v1.ServiceInfoResponse) {
option (google.api.http) = {get: "/v1/warehouse/service"};
}
rpc ViewProductStock(ViewProductStockRequest) returns (ViewProductStockResponse) {
option (google.api.http) = {get: "/v1/warehouse/product/{product_id}"};
}
rpc ViewReservation(ViewReservationRequest) returns (ViewReservationResponse) {
option (google.api.http) = {get: "/v1/warehouse/reservation/{reservation_id}"};
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessProductCreatedEvent(stocklet.events.v1.ProductCreatedEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessOrderPendingEvent(stocklet.events.v1.OrderPendingEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessShipmentAllocationEvent(stocklet.events.v1.ShipmentAllocationEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
// A consumer will call this method to process events.
//
// buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE
// buf:lint:ignore RPC_REQUEST_STANDARD_NAME
// buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
rpc ProcessPaymentProcessedEvent(stocklet.events.v1.PaymentProcessedEvent) returns (google.protobuf.Empty) {
option (google.api.method_visibility).restriction = "INTERNAL";
}
}
message ViewProductStockRequest {
string product_id = 1 [(buf.validate.field).string.min_len = 1];
}
message ViewProductStockResponse {
ProductStock stock = 1;
}
message ViewReservationRequest {
string reservation_id = 1 [(buf.validate.field).string.min_len = 1];
}
message ViewReservationResponse {
Reservation reservation = 1;
}

View File

@@ -0,0 +1,41 @@
// Copyright (C) 2024 Declan Teevan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
package stocklet.warehouse.v1;
import "buf/validate/validate.proto";
option go_package = "github.com/hexolan/stocklet/internal/pkg/protogen/warehouse/v1;warehouse_v1";
message ProductStock {
string product_id = 1 [(buf.validate.field).string.min_len = 1];
int32 quantity = 2 [(buf.validate.field).int32.gte = 0];
}
message Reservation {
string id = 1 [(buf.validate.field).string.min_len = 1];
string order_id = 2 [(buf.validate.field).string.min_len = 1];
repeated ReservationStock reserved_stock = 3;
int64 created_at = 4;
}
message ReservationStock {
string product_id = 1 [(buf.validate.field).string.min_len = 1];
int32 quantity = 2 [(buf.validate.field).int32.gte = 0];
}

View File

@@ -0,0 +1 @@
DROP TABLE IF EXISTS auth_methods CASCADE;

View File

@@ -0,0 +1,4 @@
CREATE TABLE auth_methods (
user_id varchar(64) PRIMARY KEY,
hashed_password varchar(128) NOT NULL
);

View File

@@ -0,0 +1,3 @@
DROP TABLE IF EXISTS orders CASCADE;
DROP TABLE IF EXISTS order_items CASCADE;
DROP TABLE IF EXISTS event_outbox CASCADE;

View File

@@ -0,0 +1,32 @@
CREATE TABLE orders (
id bigserial PRIMARY KEY,
status smallint NOT NULL,
customer_id varchar(64) NOT NULL,
shipment_id varchar(64),
transaction_id varchar(64),
items_price money,
total_price money,
created_at timestamp NOT NULL DEFAULT timezone('utc', now()),
updated_at timestamp
);
CREATE TABLE order_items (
order_id bigserial,
product_id varchar(64),
quantity integer NOT NULL,
PRIMARY KEY (order_id, product_id),
FOREIGN KEY (order_id) REFERENCES orders (id) ON DELETE CASCADE
);
CREATE TABLE event_outbox (
id bigserial PRIMARY KEY,
aggregateid varchar(128) NOT NULL,
aggregatetype varchar(128) NOT NULL,
payload bytea NOT NULL
);

View File

@@ -0,0 +1,3 @@
DROP TABLE IF EXISTS transactions CASCADE;
DROP TABLE IF EXISTS customer_balances CASCADE;
DROP TABLE IF EXISTS event_outbox CASCADE;

View File

@@ -0,0 +1,24 @@
CREATE TABLE transactions (
id bigserial PRIMARY KEY,
order_id varchar(64),
customer_id varchar(64) NOT NULL,
amount money NOT NULL,
reversed_at timestamp,
processed_at timestamp NOT NULL DEFAULT timezone('utc', now())
);
CREATE TABLE customer_balances (
customer_id varchar(64) PRIMARY KEY,
balance money NOT NULL
);
CREATE TABLE event_outbox (
id bigserial PRIMARY KEY,
aggregateid varchar(128) NOT NULL,
aggregatetype varchar(128) NOT NULL,
payload bytea NOT NULL
);

View File

@@ -0,0 +1,2 @@
DROP TABLE IF EXISTS products CASCADE;
DROP TABLE IF EXISTS event_outbox CASCADE;

View File

@@ -0,0 +1,18 @@
CREATE TABLE products (
id bigserial PRIMARY KEY,
name varchar(128) NOT NULL,
description varchar(256) NOT NULL,
price money NOT NULL,
created_at timestamp NOT NULL DEFAULT timezone('utc', now()),
updated_at timestamp
);
CREATE TABLE event_outbox (
id bigserial PRIMARY KEY,
aggregateid varchar(128) NOT NULL,
aggregatetype varchar(128) NOT NULL,
payload bytea NOT NULL
);

View File

@@ -0,0 +1,3 @@
DROP TABLE IF EXISTS shipments CASCADE;
DROP TABLE IF EXISTS shipment_items CASCADE;
DROP TABLE IF EXISTS event_outbox CASCADE;

View File

@@ -0,0 +1,26 @@
CREATE TABLE shipments (
id bigserial PRIMARY KEY,
order_id varchar(64) NOT NULL,
dispatched boolean DEFAULT FALSE,
created_at timestamp NOT NULL DEFAULT timezone('utc', now())
);
CREATE TABLE shipment_items (
shipment_id bigserial,
product_id varchar(64),
quantity integer NOT NULL,
PRIMARY KEY (shipment_id, product_id),
FOREIGN KEY (shipment_id) REFERENCES shipments (id) ON DELETE CASCADE
);
CREATE TABLE event_outbox (
id bigserial PRIMARY KEY,
aggregateid varchar(128) NOT NULL,
aggregatetype varchar(128) NOT NULL,
payload bytea NOT NULL
);

View File

@@ -0,0 +1,2 @@
DROP TABLE IF EXISTS users CASCADE;
DROP TABLE IF EXISTS event_outbox CASCADE;

View File

@@ -0,0 +1,19 @@
CREATE TABLE users (
id bigserial PRIMARY KEY,
first_name varchar(64) NOT NULL,
last_name varchar(64) NOT NULL,
email varchar NOT NULL UNIQUE,
created_at timestamp NOT NULL DEFAULT timezone('utc', now()),
updated_at timestamp
);
CREATE TABLE event_outbox (
id bigserial PRIMARY KEY,
aggregateid varchar(128) NOT NULL,
aggregatetype varchar(128) NOT NULL,
payload bytea NOT NULL
);

View File

@@ -0,0 +1,4 @@
DROP TABLE IF EXISTS product_stock CASCADE;
DROP TABLE IF EXISTS reservations CASCADE;
DROP TABLE IF EXISTS reservation_items CASCADE;
DROP TABLE IF EXISTS event_outbox CASCADE;

View File

@@ -0,0 +1,30 @@
CREATE TABLE product_stock (
product_id varchar(64) PRIMARY KEY,
quantity integer NOT NULL
);
CREATE TABLE reservations (
id bigserial PRIMARY KEY,
order_id varchar(64) NOT NULL,
created_at timestamp NOT NULL DEFAULT timezone('utc', now())
);
CREATE TABLE reservation_items (
reservation_id bigserial,
product_id varchar(64),
quantity integer NOT NULL,
PRIMARY KEY (reservation_id, product_id),
FOREIGN KEY (reservation_id) REFERENCES reservations (id) ON DELETE CASCADE
);
CREATE TABLE event_outbox (
id bigserial PRIMARY KEY,
aggregateid varchar(128) NOT NULL,
aggregatetype varchar(128) NOT NULL,
payload bytea NOT NULL
);