Claude-skill-registry ecom-integrations
Ecommerce integration patterns and decomposer/composer
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/ecom-integrations" ~/.claude/skills/majiayu000-claude-skill-registry-ecom-integrations && rm -rf "$T"
manifest:
skills/data/ecom-integrations/SKILL.mdsource content
Decomposer/Composer Patterns
Decomposer Pattern
Decomposers transform external platform data → Violet canonical models.
Interface
public interface Decomposer<P, V> { V decompose(P platformEntity); List<V> decomposeList(List<P> platformEntities); }
Example: Shopify Product Decomposer
public class ShopifyProductDecomposer implements Decomposer<ShopifyProduct, Offer> { public static Offer decompose(ShopifyProduct shopifyProduct) { Offer offer = new Offer(); offer.setExternalId(String.valueOf(shopifyProduct.getId())); offer.setName(shopifyProduct.getTitle()); offer.setDescription(shopifyProduct.getBodyHtml()); offer.setVendor(shopifyProduct.getVendor()); offer.setSkus(decomposeVariants(shopifyProduct.getVariants())); offer.setImages(decomposeImages(shopifyProduct.getImages())); offer.setTags(parseTags(shopifyProduct.getTags())); offer.setStatus(mapStatus(shopifyProduct.getStatus())); return offer; } private static OfferStatus mapStatus(String shopifyStatus) { return switch (shopifyStatus) { case "active" -> OfferStatus.AVAILABLE; case "draft" -> OfferStatus.DRAFT; case "archived" -> OfferStatus.UNAVAILABLE; default -> OfferStatus.UNKNOWN; }; } }
Key Principles
- Pure functions - No side effects, static methods
- Null safety - Check every field before accessing
- Status mapping - Translate platform statuses to Violet statuses
- Field normalization - Convert to consistent formats (currency, units)
Composer Pattern
Composers transform Violet canonical models → external platform formats.
Interface
public interface Composer<V, P> { P compose(V violetEntity); List<P> composeList(List<V> violetEntities); }
Example: Shopify Order Composer
public class ShopifyOrderComposer implements Composer<Order, ShopifyOrderInput> { public static ShopifyOrderInput compose(Order violetOrder) { ShopifyOrderInput input = new ShopifyOrderInput(); input.setEmail(violetOrder.getCustomer().getEmail()); input.setLineItems(composeLineItems(violetOrder.getItems())); input.setShippingAddress(composeAddress(violetOrder.getShippingAddress())); input.setBillingAddress(composeAddress(violetOrder.getBillingAddress())); input.setFinancialStatus(mapFinancialStatus(violetOrder.getPaymentStatus())); input.setFulfillmentStatus(mapFulfillmentStatus(violetOrder.getFulfillmentStatus())); return input; } private static String mapFinancialStatus(PaymentStatus status) { return switch (status) { case PAID -> "paid"; case PENDING -> "pending"; case REFUNDED -> "refunded"; case PARTIALLY_REFUNDED -> "partially_refunded"; default -> "pending"; }; } }
Key Principles
- Idempotent - Same input always produces same output
- Complete - Include all required platform fields
- Validated - Output should pass platform validation
- Documented - Every field mapping documented
Testing Patterns
Decomposer Tests
@Test void decompose_shouldMapAllFields() { ShopifyProduct input = createTestProduct(); Offer result = ShopifyProductDecomposer.decompose(input); assertThat(result.getExternalId()).isEqualTo("123"); assertThat(result.getName()).isEqualTo("Test Product"); assertThat(result.getStatus()).isEqualTo(OfferStatus.AVAILABLE); } @Test void decompose_shouldHandleNullFields() { ShopifyProduct input = new ShopifyProduct(); input.setId(123L); // Other fields null Offer result = ShopifyProductDecomposer.decompose(input); assertThat(result.getExternalId()).isEqualTo("123"); assertThat(result.getName()).isNull(); }
Composer Tests
@Test void compose_shouldProduceValidPlatformInput() { Order violetOrder = createTestOrder(); ShopifyOrderInput result = ShopifyOrderComposer.compose(violetOrder); assertThat(result.getEmail()).isNotNull(); assertThat(result.getLineItems()).isNotEmpty(); } @Test void compose_shouldMapStatusCorrectly() { Order order = new Order(); order.setPaymentStatus(PaymentStatus.PAID); ShopifyOrderInput result = ShopifyOrderComposer.compose(order); assertThat(result.getFinancialStatus()).isEqualTo("paid"); }
Status Mapping Tables
Every integration must document status mappings:
Order Status Example
| Violet Status | Shopify | BigCommerce | WooCommerce |
|---|---|---|---|
| PENDING | unfulfilled | Awaiting Fulfillment | pending |
| PROCESSING | in_progress | Awaiting Shipment | processing |
| SHIPPED | fulfilled | Shipped | completed |
| DELIVERED | fulfilled | Delivered | completed |
| CANCELLED | cancelled | Cancelled | cancelled |