Architecture¶
calculatecost4 uses a two-layer architecture separating pure business logic from AWS infrastructure.
System Overview¶
flowchart TB
Client["Client\nPOST /calculatecost4"]
APIGW["API Gateway\napi.villaecommerce.com"]
Handler["handler.py\nLambda entry point\nAccount 017176210331"]
subgraph core_group ["Core -- Pure Python"]
Calc[CostCalculator]
OrderModel[Order]
ProductModel[Product]
Totals[totals.py]
ShipCalc[shipping_calc.py]
WeightCalc[weight.py]
end
subgraph iface_group [Interfaces -- Protocols]
IP[PricingService]
IPL[ProductLookupService]
IS[ShippingPriceService]
IC[CouponService]
IV[VoucherService]
ICL[ControlledProductService]
end
subgraph adapter_group ["Adapters -- AWS/HTTP"]
DDBPrice[DynamoDBPricingService]
DDBProd[DynamoDBProductLookup]
HTTPShip[CompositeShippingPrice]
LCoup[LambdaCouponService]
LVouch[LambdaVoucherService]
HTTPCtrl[HTTPControlledProducts]
end
subgraph source_account ["Source Account -- 394922924679"]
DDB1["DynamoDB\nprice-database-2"]
DDB2["DynamoDB\nproduct-table"]
Lamb1["Lambda\ncoupon3-checker-dev"]
Lamb2["Lambda\nget-voucher-master"]
Lamb3["Lambda\nnationwide-delivery"]
PolygonAPI["HTTP\nPolygon API"]
end
STS["cross_account.py\nSTS AssumeRole"]
Client --> APIGW --> Handler
Handler --> core_group
core_group --> iface_group
adapter_group -.->|implements| iface_group
DDBPrice --> DDB1
DDBProd --> DDB2
LCoup --> Lamb1
LVouch --> Lamb2
HTTPShip --> Lamb3
HTTPShip --> PolygonAPI
adapter_group --> STS
STS --> source_account
Request Flow¶
sequenceDiagram
participant C as Client
participant AG as API Gateway
participant H as handler.py
participant CC as CostCalculator
participant P as PricingService
participant S as ShippingPriceService
participant Cp as CouponService
participant V as VoucherService
C->>AG: POST /calculatecost4
AG->>H: Lambda event
H->>CC: calculate(order_dict)
CC->>P: get_price(cprcode, brcode)
P-->>CC: price
CC->>S: get_regular_price(lat, lon, brcode)
S-->>CC: shipping fee
CC->>Cp: check_coupons(order_dict)
Cp-->>CC: DiscountResult
CC->>V: get_voucher(voucher_id)
V-->>CC: Voucher
CC-->>H: order.to_dict()
H-->>AG: {statusCode: 200, body: ...}
AG-->>C: JSON response
Layer Responsibilities¶
Core (calculatecost4/core/)¶
Pure Python. Zero AWS imports. Contains:
- Models: Order, Product, Shipping, Schedule, Voucher, Discount, DiscountResult, TotalSummary
- Calculator: CostCalculator orchestrates the full pipeline
- Formulas: totals.py (grand total, subtotal, discount aggregation)
- Shipping: shipping_calc.py (per-schedule fee calculation)
- Weight: weight.py (product weight lookup and schedule aggregation)
- Coupon: coupon.py (CouponOrder payload builder)
Interfaces (calculatecost4/interfaces/)¶
Python Protocol classes defining abstract contracts:
| Interface | Methods |
|---|---|
| PricingService | get_price, get_original_price |
| ProductLookupService | get_product |
| ControlledProductService | get_controlled_product_list |
| ShippingPriceService | get_regular_price, get_nationwide_price |
| CouponService | check_coupons |
| VoucherService | get_voucher |
Adapters (calculatecost4/adapters/)¶
Concrete implementations using AWS services:
| Adapter | Interface | External Service |
|---|---|---|
| DynamoDBPricingService | PricingService | DynamoDB: price-database-2-dev-manual |
| DynamoDBProductLookup | ProductLookupService | DynamoDB: product-table-dev-manual |
| HTTPControlledProducts | ControlledProductService | HTTP: shop.villamarket.com |
| CompositeShippingPrice | ShippingPriceService | HTTP: Polygon API + Lambda: nationwide |
| LambdaCouponService | CouponService | Lambda: coupon3-checker-dev |
| LambdaVoucherService | VoucherService | Lambda: get-voucher-master |
Cross-Account Access¶
All adapters use cross_account.py which performs STS AssumeRole to access resources in the source account (394922924679) from the villa-ecommerce account (017176210331).
Interactive Diagram¶
Download the architecture.excalidraw file and open it in Excalidraw for an interactive, editable version of the architecture diagram.