Architecture

Unified types

The shared data model in @prood/types — domain entities, adapter interfaces, and provider contracts.

@prood/types defines the shared vocabulary for all Prood packages. Every adapter, payment provider, and application uses these types — ensuring a product in the platform adapter looks the same as one from an external adapter.

The package contains interfaces only — no runtime code, no database dependencies.

Core domain types

Catalog

TypeDescription
ProductFull product with variants, images, categories, pricing
ProductVariantSKU-level variant with price and inventory
CategoryHierarchical category with localized name/slug
BrandProduct brand with logo and metadata
SearchResult<T>Paginated result wrapper with data, total, page, limit
SearchParamsQuery filters — query, categoryId, sort, pagination

Cart & checkout

TypeDescription
CartActive cart with items, totals, shipping/payment method selections
CartItemLine item with product reference, quantity, unit price
CartTotalsSubtotal, tax, shipping, discount, grand total (major units)
ShippingMethodAvailable shipping option with price and ETA
PaymentMethodAvailable payment option (card, Multibanco, etc.)
AddressStructured address — street, city, country, postal code
CustomerInfoEmail, name, phone for checkout

Orders

TypeDescription
OrderPlaced order with items, status, payment info, addresses
OrderItemOrder line item snapshot
OrderStatuspending, confirmed, processing, shipped, delivered, cancelled, refunded
FulfillmentStatusPer-line fulfillment tracking

Store & customers

TypeDescription
StoreInfoStore name, logo, currency, locales, contact info
CustomerRegistered customer profile
CountryISO country with name and phone prefix

Promotions & reviews

TypeDescription
CouponDiscount code with type (percentage/fixed) and constraints
ReviewProduct review with rating, text, author
PromotionStore-wide or product-specific promotion

Adapter interfaces

The CommerceAdapter interface is the contract every backend must implement:

ts
interface CommerceAdapter {
  // Universal domains
  getProducts(params: SearchParams): Promise<SearchResult<Product>>
  getProduct(id: string): Promise<Product | null>
  getCategories(): Promise<Category[]>
  getStoreInfo(): Promise<StoreInfo>

  // Common domains (optional — checked via supports())
  createCart?(): Promise<Cart>
  getCart?(id: string): Promise<Cart | null>
  addCartItem?(cartId: string, input: AddCartItemInput): Promise<Cart>
  // ... cart, checkout, orders, customers, wishlist, reviews, etc.
}

Domain-specific sub-interfaces exist for granular adapter composition:

InterfaceDomain
CatalogAdapterProducts, categories, brands
CartAdapterCart CRUD, coupons, shipping/payment methods
CheckoutAdapterPlace order, order confirmation
OrdersAdapterOrder listing, detail, status updates
CustomersAdapterCustomer profiles and addresses
StoreAdapterStore settings and info

Provider interfaces

Providers handle side-effect services (payments, notifications, analytics) — distinct from data domains:

PaymentProvider

ts
interface PaymentProvider {
  readonly id: string
  createSession(input: CreatePaymentSessionInput): Promise<PaymentSession>
  confirmSession(sessionId: string): Promise<PaymentSession>
  refund?(input: RefundInput): Promise<void>
  verifyWebhook(event: PaymentWebhookEvent): Promise<boolean>
}

Supporting types:

TypeDescription
PaymentSessionProvider charge/intent with status, amount, redirect URL
CreatePaymentSessionInputAmount, currency, customer, metadata, return URL
RefundInputSession ID, amount, reason
PaymentWebhookEventRaw webhook payload for verification

StorageProvider

ts
interface StorageProvider {
  upload(input: UploadInput): Promise<UploadResult>
  delete(key: string): Promise<void>
  getUrl(key: string): Promise<string>
}

Error handling

ts
class CommerceError extends Error {
  code: CommerceErrorCode  // machine-readable error code
  statusCode?: number      // HTTP status, when it differs from the code's default
  cause?: unknown
}

function toErrorResponse(error: unknown): {
  status: number
  body: { code: string; message: string; errors?: { path: string; message: string }[] }
}

All API routes use toErrorResponse(), so every error body is { code, message }, and a failed validation adds errors.

Price utilities

Price.amount is in major units everywhere in Prood: the database stores numeric(12,2), and PaymentProvider receives the same value (99.99 for €99.99). Each provider converts at its own boundary if the gateway needs something else. Stripe, for example, takes minor units.

Display formatting lives in @prood/ui/lib/commerce (formatPrice, localized).

Admin types

Admin-specific input/output types for dashboard operations:

TypeDescription
CreateProductInputProduct creation payload
UpdateProductInputPartial product update
DashboardStatsRevenue, order count, customer count aggregates
InventoryUpdateStock level adjustment
FulfillOrderInputShipping tracking info
RefundOrderInputRefund amount and reason

These are re-exported from @prood/commerce for convenience.

Specialized domain types

Types exist for advanced commerce patterns (partial platform implementation):

DomainKey types
ReturnsReturnRequest, ReturnStatus

Using types in your code

ts
// Import domain types
import type { Product, Cart, Order } from '@prood/types'

// Import adapter interface (for custom adapters)
import type { CommerceAdapter, SearchParams } from '@prood/types'

// Import payment provider interface
import type { PaymentProvider, CreatePaymentSessionInput } from '@prood/types'

// Import error utilities
import { CommerceError, toErrorResponse } from '@prood/types'