- remove backend-old (Medusa), saveinmed-frontend (Next.js/Appwrite) and marketplace dirs - split Go usecases by domain and move notifications/payments to infrastructure - reorganize frontend pages into auth, dashboard and marketplace modules - add Makefile, docker-compose.yml and architecture docs
160 lines
8 KiB
Go
160 lines
8 KiB
Go
package usecase
|
||
|
||
import (
|
||
"context"
|
||
"time"
|
||
|
||
"github.com/gofrs/uuid/v5"
|
||
|
||
"github.com/saveinmed/backend-go/internal/domain"
|
||
"github.com/saveinmed/backend-go/internal/infrastructure/mapbox"
|
||
"github.com/saveinmed/backend-go/internal/infrastructure/notifications"
|
||
)
|
||
|
||
// Repository defines the persistence contract for all core entities.
|
||
// Implementations live in internal/repository/postgres/.
|
||
type Repository interface {
|
||
CreateCompany(ctx context.Context, company *domain.Company) error
|
||
ListCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.Company, int64, error)
|
||
GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error)
|
||
UpdateCompany(ctx context.Context, company *domain.Company) error
|
||
DeleteCompany(ctx context.Context, id uuid.UUID) error
|
||
|
||
CreateProduct(ctx context.Context, product *domain.Product) error
|
||
BatchCreateProducts(ctx context.Context, products []domain.Product) error
|
||
ListProducts(ctx context.Context, filter domain.ProductFilter) ([]domain.Product, int64, error)
|
||
SearchProducts(ctx context.Context, filter domain.ProductSearchFilter) ([]domain.ProductWithDistance, int64, error)
|
||
ListRecords(ctx context.Context, filter domain.RecordSearchFilter) ([]domain.Product, int64, error)
|
||
GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error)
|
||
UpdateProduct(ctx context.Context, product *domain.Product) error
|
||
DeleteProduct(ctx context.Context, id uuid.UUID) error
|
||
AdjustInventory(ctx context.Context, productID uuid.UUID, delta int64, reason string) (*domain.InventoryItem, error)
|
||
ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error)
|
||
CreateInventoryItem(ctx context.Context, item *domain.InventoryItem) error
|
||
GetInventoryItem(ctx context.Context, id uuid.UUID) (*domain.InventoryItem, error)
|
||
UpdateInventoryItem(ctx context.Context, item *domain.InventoryItem) error
|
||
|
||
CreateOrder(ctx context.Context, order *domain.Order) error
|
||
ListOrders(ctx context.Context, filter domain.OrderFilter) ([]domain.Order, int64, error)
|
||
GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error)
|
||
UpdateOrderStatus(ctx context.Context, id uuid.UUID, status domain.OrderStatus) error
|
||
DeleteOrder(ctx context.Context, id uuid.UUID) error
|
||
UpdateOrderItems(ctx context.Context, orderID uuid.UUID, items []domain.OrderItem, totalCents int64) error
|
||
CreateShipment(ctx context.Context, shipment *domain.Shipment) error
|
||
GetShipmentByOrderID(ctx context.Context, orderID uuid.UUID) (*domain.Shipment, error)
|
||
|
||
CreateUser(ctx context.Context, user *domain.User) error
|
||
ListUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error)
|
||
GetUser(ctx context.Context, id uuid.UUID) (*domain.User, error)
|
||
GetUserByUsername(ctx context.Context, username string) (*domain.User, error)
|
||
GetUserByEmail(ctx context.Context, email string) (*domain.User, error)
|
||
UpdateUser(ctx context.Context, user *domain.User) error
|
||
DeleteUser(ctx context.Context, id uuid.UUID) error
|
||
|
||
AddCartItem(ctx context.Context, item *domain.CartItem) (*domain.CartItem, error)
|
||
ListCartItems(ctx context.Context, buyerID uuid.UUID) ([]domain.CartItem, error)
|
||
DeleteCartItem(ctx context.Context, id uuid.UUID, buyerID uuid.UUID) error
|
||
DeleteCartItemByProduct(ctx context.Context, buyerID, productID uuid.UUID) error
|
||
ClearCart(ctx context.Context, buyerID uuid.UUID) error
|
||
ReplaceCart(ctx context.Context, buyerID uuid.UUID, items []domain.CartItem) error
|
||
|
||
CreateReview(ctx context.Context, review *domain.Review) error
|
||
GetCompanyRating(ctx context.Context, companyID uuid.UUID) (*domain.CompanyRating, error)
|
||
ListReviews(ctx context.Context, filter domain.ReviewFilter) ([]domain.Review, int64, error)
|
||
|
||
SellerDashboard(ctx context.Context, sellerID uuid.UUID) (*domain.SellerDashboard, error)
|
||
AdminDashboard(ctx context.Context, since time.Time) (*domain.AdminDashboard, error)
|
||
|
||
GetShippingSettings(ctx context.Context, vendorID uuid.UUID) (*domain.ShippingSettings, error)
|
||
UpsertShippingSettings(ctx context.Context, settings *domain.ShippingSettings) error
|
||
ListShipments(ctx context.Context, filter domain.ShipmentFilter) ([]domain.Shipment, int64, error)
|
||
|
||
CreateDocument(ctx context.Context, doc *domain.CompanyDocument) error
|
||
ListDocuments(ctx context.Context, companyID uuid.UUID) ([]domain.CompanyDocument, error)
|
||
RecordLedgerEntry(ctx context.Context, entry *domain.LedgerEntry) error
|
||
GetLedger(ctx context.Context, companyID uuid.UUID, limit, offset int) ([]domain.LedgerEntry, int64, error)
|
||
GetBalance(ctx context.Context, companyID uuid.UUID) (int64, error)
|
||
CreateWithdrawal(ctx context.Context, withdrawal *domain.Withdrawal) error
|
||
ListWithdrawals(ctx context.Context, companyID uuid.UUID) ([]domain.Withdrawal, error)
|
||
|
||
GetPaymentGatewayConfig(ctx context.Context, provider string) (*domain.PaymentGatewayConfig, error)
|
||
UpsertPaymentGatewayConfig(ctx context.Context, config *domain.PaymentGatewayConfig) error
|
||
GetSellerPaymentAccount(ctx context.Context, sellerID uuid.UUID) (*domain.SellerPaymentAccount, error)
|
||
UpsertSellerPaymentAccount(ctx context.Context, account *domain.SellerPaymentAccount) error
|
||
|
||
CreateAddress(ctx context.Context, address *domain.Address) error
|
||
ListAddresses(ctx context.Context, entityID uuid.UUID) ([]domain.Address, error)
|
||
GetAddress(ctx context.Context, id uuid.UUID) (*domain.Address, error)
|
||
UpdateAddress(ctx context.Context, address *domain.Address) error
|
||
DeleteAddress(ctx context.Context, id uuid.UUID) error
|
||
|
||
ListManufacturers(ctx context.Context) ([]string, error)
|
||
ListCategories(ctx context.Context) ([]string, error)
|
||
GetProductByEAN(ctx context.Context, ean string) (*domain.Product, error)
|
||
}
|
||
|
||
// PaymentGateway abstracts the payment provider (Mercado Pago, Asaas, etc.).
|
||
// Implementations live in internal/infrastructure/payments/.
|
||
type PaymentGateway interface {
|
||
CreatePreference(ctx context.Context, order *domain.Order, payer *domain.User, sellerAcc *domain.SellerPaymentAccount) (*domain.PaymentPreference, error)
|
||
CreatePayment(ctx context.Context, order *domain.Order, token, issuerID, paymentMethodID string, installments int, payer *domain.User, sellerAcc *domain.SellerPaymentAccount) (*domain.PaymentResult, error)
|
||
}
|
||
|
||
// Service orchestrates all business use cases.
|
||
// Methods are split across domain-specific files in this package:
|
||
// - auth_usecase.go – authentication, JWT, password reset
|
||
// - company_usecase.go – company registration, KYC, shipping options
|
||
// - product_usecase.go – catalogue, inventory management
|
||
// - order_usecase.go – order lifecycle and state machine
|
||
// - shipping_usecase.go – shipping calculation and configuration
|
||
// - cart_usecase.go – cart operations and B2B discounts
|
||
// - payment_usecase.go – payment preferences and webhook handling
|
||
// - review_usecase.go – buyer reviews and ratings
|
||
// - user_usecase.go – user CRUD
|
||
// - address_usecase.go – address management
|
||
// - dashboard_usecase.go – seller and admin KPI dashboards
|
||
type Service struct {
|
||
repo Repository
|
||
pay PaymentGateway
|
||
mapbox *mapbox.Client
|
||
notify notifications.NotificationService
|
||
marketplaceCommission float64
|
||
buyerFeeRate float64
|
||
jwtSecret []byte
|
||
tokenTTL time.Duration
|
||
passwordPepper string
|
||
}
|
||
|
||
const (
|
||
// passwordResetTTL is the validity window for password-reset JWTs.
|
||
passwordResetTTL = 30 * time.Minute
|
||
)
|
||
|
||
// NewService wires all dependencies and returns a ready-to-use Service.
|
||
func NewService(
|
||
repo Repository,
|
||
pg PaymentGateway,
|
||
mb *mapbox.Client,
|
||
notify notifications.NotificationService,
|
||
commission, buyerFeeRate float64,
|
||
jwtSecret string,
|
||
tokenTTL time.Duration,
|
||
pepper string,
|
||
) *Service {
|
||
return &Service{
|
||
repo: repo,
|
||
pay: pg,
|
||
mapbox: mb,
|
||
notify: notify,
|
||
marketplaceCommission: commission,
|
||
buyerFeeRate: buyerFeeRate,
|
||
jwtSecret: []byte(jwtSecret),
|
||
tokenTTL: tokenTTL,
|
||
passwordPepper: pepper,
|
||
}
|
||
}
|
||
|
||
// GetNotificationService exposes the notification service for push handlers.
|
||
func (s *Service) GetNotificationService() notifications.NotificationService {
|
||
return s.notify
|
||
}
|