@rune-kit/rune 2.10.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +65 -6
  3. package/commands/rune.md +168 -168
  4. package/compiler/__tests__/detect-invariants.test.js +136 -0
  5. package/compiler/__tests__/doctor-mesh.test.js +229 -0
  6. package/compiler/__tests__/hook-dispatch.test.js +91 -0
  7. package/compiler/__tests__/hooks-antigravity.test.js +118 -0
  8. package/compiler/__tests__/hooks-cursor.test.js +139 -0
  9. package/compiler/__tests__/hooks-install.test.js +305 -0
  10. package/compiler/__tests__/hooks-merge.test.js +204 -0
  11. package/compiler/__tests__/hooks-tiers.test.js +519 -0
  12. package/compiler/__tests__/hooks-windsurf.test.js +115 -0
  13. package/compiler/__tests__/inject-claude-md.test.js +152 -0
  14. package/compiler/__tests__/load-invariants.test.js +408 -0
  15. package/compiler/__tests__/onboard-invariants.test.js +240 -0
  16. package/compiler/adapters/hooks/antigravity.js +140 -0
  17. package/compiler/adapters/hooks/claude.js +166 -0
  18. package/compiler/adapters/hooks/cursor.js +191 -0
  19. package/compiler/adapters/hooks/index.js +82 -0
  20. package/compiler/adapters/hooks/tier-emitter.js +182 -0
  21. package/compiler/adapters/hooks/windsurf.js +202 -0
  22. package/compiler/bin/rune.js +196 -6
  23. package/compiler/commands/hook-dispatch.js +87 -0
  24. package/compiler/commands/hooks/install.js +120 -0
  25. package/compiler/commands/hooks/merge.js +211 -0
  26. package/compiler/commands/hooks/presets.js +116 -0
  27. package/compiler/commands/hooks/status.js +112 -0
  28. package/compiler/commands/hooks/tiers.js +221 -0
  29. package/compiler/commands/hooks/uninstall.js +94 -0
  30. package/compiler/doctor.js +236 -0
  31. package/contexts/dev.md +34 -34
  32. package/contexts/research.md +43 -43
  33. package/contexts/review.md +55 -55
  34. package/extensions/ai-ml/PACK.md +88 -88
  35. package/extensions/ai-ml/skills/ai-agents.md +172 -172
  36. package/extensions/ai-ml/skills/code-sandbox.md +187 -187
  37. package/extensions/ai-ml/skills/deep-research.md +146 -146
  38. package/extensions/ai-ml/skills/embedding-search.md +66 -66
  39. package/extensions/ai-ml/skills/fine-tuning-guide.md +74 -74
  40. package/extensions/ai-ml/skills/llm-architect.md +125 -125
  41. package/extensions/ai-ml/skills/llm-integration.md +64 -64
  42. package/extensions/ai-ml/skills/prompt-patterns.md +72 -72
  43. package/extensions/ai-ml/skills/rag-patterns.md +66 -66
  44. package/extensions/ai-ml/skills/web-extraction.md +114 -114
  45. package/extensions/analytics/PACK.md +92 -92
  46. package/extensions/analytics/skills/ab-testing.md +72 -72
  47. package/extensions/analytics/skills/dashboard-patterns.md +83 -83
  48. package/extensions/analytics/skills/data-validation.md +68 -68
  49. package/extensions/analytics/skills/funnel-analysis.md +81 -81
  50. package/extensions/analytics/skills/sql-patterns.md +57 -57
  51. package/extensions/analytics/skills/statistical-analysis.md +79 -79
  52. package/extensions/analytics/skills/tracking-setup.md +71 -71
  53. package/extensions/backend/PACK.md +104 -104
  54. package/extensions/backend/skills/api-patterns.md +84 -84
  55. package/extensions/backend/skills/async-pipeline.md +193 -193
  56. package/extensions/backend/skills/auth-patterns.md +97 -97
  57. package/extensions/backend/skills/background-jobs.md +133 -133
  58. package/extensions/backend/skills/caching-patterns.md +108 -108
  59. package/extensions/backend/skills/cli-generation.md +133 -133
  60. package/extensions/backend/skills/database-patterns.md +87 -87
  61. package/extensions/backend/skills/middleware-patterns.md +104 -104
  62. package/extensions/chrome-ext/PACK.md +93 -93
  63. package/extensions/chrome-ext/skills/cws-preflight.md +143 -143
  64. package/extensions/chrome-ext/skills/cws-publish.md +104 -104
  65. package/extensions/chrome-ext/skills/ext-ai-integration.md +251 -251
  66. package/extensions/chrome-ext/skills/ext-messaging.md +139 -139
  67. package/extensions/chrome-ext/skills/ext-storage.md +133 -133
  68. package/extensions/chrome-ext/skills/mv3-scaffold.md +164 -164
  69. package/extensions/content/PACK.md +96 -96
  70. package/extensions/content/skills/blog-patterns.md +88 -88
  71. package/extensions/content/skills/cms-integration.md +131 -131
  72. package/extensions/content/skills/content-scoring.md +107 -107
  73. package/extensions/content/skills/i18n.md +83 -83
  74. package/extensions/content/skills/mdx-authoring.md +137 -137
  75. package/extensions/content/skills/reference.md +1014 -1014
  76. package/extensions/content/skills/seo-patterns.md +67 -67
  77. package/extensions/content/skills/video-repurpose.md +153 -153
  78. package/extensions/devops/PACK.md +101 -101
  79. package/extensions/devops/skills/chaos-testing.md +67 -67
  80. package/extensions/devops/skills/ci-cd.md +75 -75
  81. package/extensions/devops/skills/docker.md +58 -58
  82. package/extensions/devops/skills/edge-serverless.md +163 -163
  83. package/extensions/devops/skills/infra-as-code.md +158 -158
  84. package/extensions/devops/skills/kubernetes.md +110 -110
  85. package/extensions/devops/skills/monitoring.md +57 -57
  86. package/extensions/devops/skills/server-setup.md +64 -64
  87. package/extensions/devops/skills/ssl-domain.md +42 -42
  88. package/extensions/ecommerce/PACK.md +116 -116
  89. package/extensions/ecommerce/skills/cart-system.md +79 -79
  90. package/extensions/ecommerce/skills/inventory-mgmt.md +102 -102
  91. package/extensions/ecommerce/skills/order-management.md +126 -126
  92. package/extensions/ecommerce/skills/payment-integration.md +472 -472
  93. package/extensions/ecommerce/skills/shopify-dev.md +69 -69
  94. package/extensions/ecommerce/skills/subscription-billing.md +93 -93
  95. package/extensions/ecommerce/skills/tax-compliance.md +117 -117
  96. package/extensions/gamedev/PACK.md +142 -142
  97. package/extensions/gamedev/skills/asset-pipeline.md +74 -74
  98. package/extensions/gamedev/skills/audio-system.md +129 -129
  99. package/extensions/gamedev/skills/camera-system.md +87 -87
  100. package/extensions/gamedev/skills/ecs.md +98 -98
  101. package/extensions/gamedev/skills/game-loops.md +72 -72
  102. package/extensions/gamedev/skills/input-system.md +199 -199
  103. package/extensions/gamedev/skills/multiplayer.md +180 -180
  104. package/extensions/gamedev/skills/particles.md +105 -105
  105. package/extensions/gamedev/skills/physics-engine.md +89 -89
  106. package/extensions/gamedev/skills/scene-management.md +146 -146
  107. package/extensions/gamedev/skills/threejs-patterns.md +90 -90
  108. package/extensions/gamedev/skills/webgl.md +71 -71
  109. package/extensions/mobile/PACK.md +106 -106
  110. package/extensions/mobile/skills/app-store-connect.md +152 -152
  111. package/extensions/mobile/skills/app-store-prep.md +66 -66
  112. package/extensions/mobile/skills/deep-linking.md +109 -109
  113. package/extensions/mobile/skills/flutter.md +60 -60
  114. package/extensions/mobile/skills/ios-build-pipeline.md +142 -142
  115. package/extensions/mobile/skills/native-bridge.md +66 -66
  116. package/extensions/mobile/skills/ota-updates.md +97 -97
  117. package/extensions/mobile/skills/push-notifications.md +111 -111
  118. package/extensions/mobile/skills/react-native.md +82 -82
  119. package/extensions/saas/PACK.md +116 -116
  120. package/extensions/saas/skills/billing-integration.md +200 -200
  121. package/extensions/saas/skills/feature-flags.md +130 -130
  122. package/extensions/saas/skills/multi-tenant.md +103 -103
  123. package/extensions/saas/skills/onboarding-flow.md +139 -139
  124. package/extensions/saas/skills/subscription-flow.md +95 -95
  125. package/extensions/saas/skills/team-management.md +144 -144
  126. package/extensions/security/PACK.md +99 -99
  127. package/extensions/security/skills/api-security.md +140 -140
  128. package/extensions/security/skills/compliance.md +68 -68
  129. package/extensions/security/skills/owasp-audit.md +64 -64
  130. package/extensions/security/skills/pentest-patterns.md +77 -77
  131. package/extensions/security/skills/secret-mgmt.md +65 -65
  132. package/extensions/security/skills/supply-chain.md +65 -65
  133. package/extensions/trading/PACK.md +80 -80
  134. package/extensions/trading/skills/chart-components.md +55 -55
  135. package/extensions/trading/skills/experiment-loop.md +125 -125
  136. package/extensions/trading/skills/fintech-patterns.md +47 -47
  137. package/extensions/trading/skills/indicator-library.md +58 -58
  138. package/extensions/trading/skills/quant-analysis.md +111 -111
  139. package/extensions/trading/skills/realtime-data.md +58 -58
  140. package/extensions/trading/skills/trade-logic.md +104 -104
  141. package/extensions/ui/PACK.md +130 -130
  142. package/extensions/ui/skills/a11y-audit.md +91 -91
  143. package/extensions/ui/skills/animation-patterns.md +127 -127
  144. package/extensions/ui/skills/component-patterns.md +100 -100
  145. package/extensions/ui/skills/design-decision.md +108 -108
  146. package/extensions/ui/skills/design-system.md +68 -68
  147. package/extensions/ui/skills/landing-patterns.md +155 -155
  148. package/extensions/ui/skills/palette-picker.md +173 -173
  149. package/extensions/ui/skills/react-health.md +90 -90
  150. package/extensions/ui/skills/type-system.md +125 -125
  151. package/extensions/ui/skills/web-vitals.md +153 -153
  152. package/extensions/zalo/PACK.md +145 -145
  153. package/extensions/zalo/skills/zalo-oa-mcp.md +317 -317
  154. package/extensions/zalo/skills/zalo-oa-messaging.md +429 -429
  155. package/extensions/zalo/skills/zalo-oa-setup.md +236 -236
  156. package/extensions/zalo/skills/zalo-oa-webhook.md +189 -189
  157. package/extensions/zalo/skills/zalo-personal-messaging.md +194 -194
  158. package/extensions/zalo/skills/zalo-personal-setup.md +153 -153
  159. package/extensions/zalo/skills/zalo-rate-guard.md +219 -219
  160. package/hooks/auto-format/index.cjs +48 -48
  161. package/hooks/hooks.json +111 -111
  162. package/hooks/post-session-reflect/index.cjs +189 -189
  163. package/hooks/pre-compact/index.cjs +95 -95
  164. package/hooks/run-hook.cmd +1 -1
  165. package/hooks/secrets-scan/index.cjs +100 -100
  166. package/hooks/session-start/index.cjs +71 -71
  167. package/hooks/typecheck/index.cjs +65 -65
  168. package/package.json +63 -63
  169. package/references/ui-pro-max-data/LICENSE-UI-PRO-MAX +21 -21
  170. package/references/ui-pro-max-data/charts.csv +26 -26
  171. package/references/ui-pro-max-data/colors.csv +161 -161
  172. package/references/ui-pro-max-data/styles.csv +68 -68
  173. package/references/ui-pro-max-data/typography.csv +74 -74
  174. package/references/ui-pro-max-data/ui-reasoning.csv +162 -162
  175. package/references/ui-pro-max-data/ux-guidelines.csv +99 -99
  176. package/skills/adversary/SKILL.md +283 -283
  177. package/skills/asset-creator/SKILL.md +157 -157
  178. package/skills/audit/SKILL.md +147 -2
  179. package/skills/autopsy/SKILL.md +335 -335
  180. package/skills/ba/SKILL.md +85 -1
  181. package/skills/brainstorm/SKILL.md +380 -342
  182. package/skills/browser-pilot/SKILL.md +169 -168
  183. package/skills/constraint-check/SKILL.md +165 -165
  184. package/skills/context-engine/SKILL.md +408 -404
  185. package/skills/cook/SKILL.md +917 -863
  186. package/skills/db/SKILL.md +273 -273
  187. package/skills/debug/SKILL.md +465 -465
  188. package/skills/dependency-doctor/SKILL.md +265 -235
  189. package/skills/deploy/SKILL.md +274 -231
  190. package/skills/design/DESIGN-REFERENCE.md +365 -365
  191. package/skills/design/SKILL.md +590 -589
  192. package/skills/doc-processor/SKILL.md +254 -254
  193. package/skills/docs/SKILL.md +374 -374
  194. package/skills/docs-seeker/SKILL.md +178 -177
  195. package/skills/fix/SKILL.md +332 -330
  196. package/skills/git/SKILL.md +339 -339
  197. package/skills/hallucination-guard/SKILL.md +220 -219
  198. package/skills/incident/SKILL.md +254 -253
  199. package/skills/integrity-check/SKILL.md +169 -169
  200. package/skills/journal/SKILL.md +241 -240
  201. package/skills/launch/SKILL.md +344 -344
  202. package/skills/logic-guardian/SKILL.md +269 -251
  203. package/skills/marketing/SKILL.md +351 -289
  204. package/skills/mcp-builder/SKILL.md +425 -425
  205. package/skills/neural-memory/SKILL.md +359 -362
  206. package/skills/onboard/SKILL.md +432 -403
  207. package/skills/onboard/references/invariants-template.md +76 -0
  208. package/skills/onboard/scripts/detect-invariants.js +439 -0
  209. package/skills/onboard/scripts/inject-claude-md.js +150 -0
  210. package/skills/onboard/scripts/onboard-invariants.js +194 -0
  211. package/skills/perf/SKILL.md +347 -346
  212. package/skills/plan/SKILL.md +435 -428
  213. package/skills/preflight/SKILL.md +415 -415
  214. package/skills/problem-solver/SKILL.md +380 -284
  215. package/skills/rescue/SKILL.md +474 -474
  216. package/skills/research/SKILL.md +4 -0
  217. package/skills/retro/SKILL.md +3 -1
  218. package/skills/review/SKILL.md +614 -588
  219. package/skills/review-intake/SKILL.md +249 -249
  220. package/skills/safeguard/SKILL.md +200 -200
  221. package/skills/sast/SKILL.md +190 -190
  222. package/skills/scaffold/SKILL.md +328 -287
  223. package/skills/scope-guard/SKILL.md +183 -180
  224. package/skills/scout/SKILL.md +269 -263
  225. package/skills/sentinel/SKILL.md +384 -381
  226. package/skills/sentinel-env/SKILL.md +254 -254
  227. package/skills/sequential-thinking/SKILL.md +234 -234
  228. package/skills/session-bridge/SKILL.md +595 -543
  229. package/skills/session-bridge/scripts/load-invariants.js +397 -0
  230. package/skills/skill-forge/SKILL.md +581 -581
  231. package/skills/skill-router/SKILL.md +3 -0
  232. package/skills/slides/SKILL.md +19 -0
  233. package/skills/surgeon/SKILL.md +215 -215
  234. package/skills/team/SKILL.md +557 -537
  235. package/skills/test/SKILL.md +620 -614
  236. package/skills/trend-scout/SKILL.md +145 -145
  237. package/skills/verification/SKILL.md +334 -326
  238. package/skills/video-creator/SKILL.md +201 -201
  239. package/skills/watchdog/SKILL.md +168 -168
  240. package/skills/worktree/SKILL.md +140 -140
@@ -1,116 +1,116 @@
1
- ---
2
- name: "@rune/ecommerce"
3
- description: E-commerce patterns — Shopify development, payment integration, subscription billing, shopping cart, inventory management, order lifecycle, and tax compliance.
4
- metadata:
5
- author: runedev
6
- version: "0.3.0"
7
- layer: L4
8
- price: "$12"
9
- target: E-commerce developers
10
- format: split
11
- ---
12
-
13
- # @rune/ecommerce
14
-
15
- ## Purpose
16
-
17
- E-commerce codebases fail at the seams between systems: payment intents that succeed but order records that don't get created, inventory counts that go negative during flash sales, subscription proration that charges the wrong amount mid-cycle, tax calculations that use cart-time rates instead of checkout-time rates, carts that lose items when users sign in, and webhook handlers that process the same event twice. This pack addresses the full order lifecycle — storefront to payment to fulfillment — with patterns that handle the race conditions, state machines, and distributed system problems that every commerce platform eventually hits.
18
-
19
- ## Triggers
20
-
21
- - Auto-trigger: when `shopify.app.toml`, `*.liquid`, `cart`, `checkout`, `stripe` in payment context, `inventory` schema detected
22
- - `/rune shopify-dev` — audit Shopify theme or app architecture
23
- - `/rune payment-integration` — set up or audit payment flows
24
- - `/rune subscription-billing` — set up or audit recurring billing
25
- - `/rune cart-system` — build or audit cart architecture
26
- - `/rune inventory-mgmt` — audit inventory tracking and stock management
27
- - `/rune order-management` — audit order lifecycle and fulfillment
28
- - `/rune tax-compliance` — set up or audit tax calculation
29
- - Called by `cook` (L1) when e-commerce project detected
30
- - Called by `launch` (L1) when preparing storefront for production
31
-
32
- ## Skills Included
33
-
34
- | Skill | Model | Description |
35
- |-------|-------|-------------|
36
- | [shopify-dev](skills/shopify-dev.md) | sonnet | Shopify theme, Hydrogen, app architecture — Liquid templates, Storefront API, metafields, webhook HMAC verification. |
37
- | [payment-integration](skills/payment-integration.md) | sonnet | Stripe, 3DS, webhooks, fraud detection, multi-currency, Vietnamese gateways (SePay, VNPay, MoMo). |
38
- | [subscription-billing](skills/subscription-billing.md) | sonnet | Trials, proration, dunning, plan changes mid-cycle, usage-based billing, cancellation flows. |
39
- | [cart-system](skills/cart-system.md) | sonnet | Persistent carts, guest-to-auth merge, server-authoritative totals, coupon engine. |
40
- | [inventory-mgmt](skills/inventory-mgmt.md) | sonnet | Atomic stock with optimistic locking, reservations, low-stock alerts, backorder handling. |
41
- | [order-management](skills/order-management.md) | sonnet | State machine, fulfillment, refund/return flows, reconciliation, webhook fan-out. |
42
- | [tax-compliance](skills/tax-compliance.md) | sonnet | Tax APIs, EU VAT reverse charge, digital goods tax, audit trail per order line item. |
43
-
44
- ## Common Workflows
45
-
46
- | Workflow | Skills Involved | Description |
47
- |----------|----------------|-------------|
48
- | Full checkout | cart-system → tax-compliance → payment-integration → order-management | Complete purchase from cart to confirmation |
49
- | Flash sale | inventory-mgmt → cart-system → payment-integration | High-concurrency stock control |
50
- | Subscription signup | cart-system → payment-integration → subscription-billing | Free trial with payment method upfront |
51
- | Plan upgrade | subscription-billing → payment-integration → tax-compliance | Mid-cycle upgrade with proration invoice |
52
- | Order cancellation | order-management → inventory-mgmt → payment-integration | Cancel + release stock + issue refund |
53
- | New market launch | tax-compliance → payment-integration (multi-currency) → shopify-dev | Localization, VAT, FX pricing |
54
- | Fraud review | payment-integration (fraud patterns) → order-management | Risk scoring before order fulfilment |
55
- | Product catalog | shopify-dev → inventory-mgmt | Variant structure + stock sync |
56
-
57
- ## Tech Stack Support
58
-
59
- | Platform | Framework | Payment | Notes |
60
- |----------|-----------|---------|-------|
61
- | Shopify | Hydrogen 2.x (Remix) | Shopify Payments | Storefront + Admin API |
62
- | Custom | Next.js 16 / SvelteKit | Stripe | Most flexible |
63
- | Headless | Any frontend | Stripe / PayPal | API-first commerce |
64
- | Medusa.js | Next.js | Stripe / PayPal | Open-source alternative |
65
- | Saleor | React / Next.js | Stripe / Braintree | GraphQL-first |
66
-
67
- ## Connections
68
-
69
- ```
70
- Calls → sentinel (L2): PCI compliance audit on payment code, webhook security
71
- Calls → db (L2): schema design for orders, inventory, carts, subscriptions
72
- Calls → perf (L2): audit checkout page load, cart update latency
73
- Calls → verification (L3): run payment flow integration tests
74
- Called By ← cook (L1): when e-commerce project detected
75
- Called By ← launch (L1): pre-launch checkout verification
76
- Called By ← review (L2): when payment or cart code under review
77
- Called By ← ba (L2): requirements elicitation for e-commerce features
78
- ```
79
-
80
- ## Sharp Edges
81
-
82
- | Failure Mode | Severity | Mitigation |
83
- |---|---|---|
84
- | Double charge from retried Payment Intent without idempotency key | CRITICAL | Derive idempotencyKey from `cartId-v${version}`, not timestamp; check for existing succeeded intent |
85
- | Webhook signature fails because `req.body` is parsed JSON instead of raw bytes | CRITICAL | Use `express.raw({ type: 'application/json' })` for webhook route; verify with `req.body` as Buffer |
86
- | Overselling during flash sale (stock goes negative) | CRITICAL | Use optimistic locking with version field; serializable isolation for high-contention items |
87
- | Payment succeeded but order creation fails (money taken, no order record) | HIGH | Wrap in transaction; run reconciliation job matching payment intents to orders every hour |
88
- | Same webhook processed twice creates duplicate orders | HIGH | Store `event.id` in database; check before processing; wrap in transaction |
89
- | Guest cart items lost on login (separate cart created for auth user) | HIGH | Implement cart merge in auth callback; prefer server cart state over local |
90
- | Subscription proration charges wrong amount on mid-cycle plan change | HIGH | Explicitly set `proration_behavior`; preview proration with `stripe.invoices.retrieveUpcoming` |
91
- | Trial-to-paid conversion fails silently (no payment method on file) | HIGH | Require payment method at trial signup; set `missing_payment_method: 'cancel'` in trial settings |
92
- | Tax calculated at cart time but rate changed by checkout (wrong amount charged) | MEDIUM | Recalculate tax at payment creation time using shipping address, not cart-add time |
93
- | Liquid template outputs unescaped metafield content (XSS in Shopify theme) | HIGH | Always use `| escape` filter on user-generated metafield values |
94
- | Cancelled order stock not returned to inventory | MEDIUM | Use order state machine with side effects — cancellation always triggers `releaseOrderReservations` |
95
- | Reservation never expires for abandoned checkout (stock locked forever) | MEDIUM | Run reservation expiry job every 5 minutes; default reservation TTL = 15 minutes |
96
- | Stolen card fraud passes payment but triggers chargeback later | HIGH | Apply fraud scoring before confirmation; hold high-risk orders for manual review |
97
- | FX rate stale on multi-currency display — user sees wrong price | MEDIUM | Cache FX rates max 15 minutes; show rate timestamp to user; always charge in store base currency |
98
-
99
- ## Done When
100
-
101
- - Checkout flow completes end-to-end: cart → tax → payment → order confirmation
102
- - Subscription lifecycle handles trial → active → past_due → cancelled with proper dunning
103
- - Inventory accurately tracks stock with no overselling under concurrent load
104
- - Order state machine enforces valid transitions with side effects (stock release, refunds, notifications)
105
- - Webhooks are idempotent, signature-verified, and handle all payment/subscription lifecycle events
106
- - Tax calculated at checkout with audit trail stored per order line item
107
- - Guest-to-authenticated cart merge works without data loss
108
- - All prices, discounts, and coupons validated server-side
109
- - Reconciliation job catches payment/order mismatches
110
- - Fraud scoring applied to all orders; high-risk orders flagged for review
111
- - Multi-currency display works with cached FX rates; charges always in base currency
112
- - Structured report emitted for each skill invoked
113
-
114
- ## Cost Profile
115
-
116
- ~14,000–26,000 tokens per full pack run (all 7 skills). Individual skill: ~2,000–4,000 tokens. Sonnet default. Use haiku for detection scans; escalate to sonnet for payment flow, subscription lifecycle, and order state machine generation.
1
+ ---
2
+ name: "@rune/ecommerce"
3
+ description: E-commerce patterns — Shopify development, payment integration, subscription billing, shopping cart, inventory management, order lifecycle, and tax compliance.
4
+ metadata:
5
+ author: runedev
6
+ version: "0.3.0"
7
+ layer: L4
8
+ price: "$12"
9
+ target: E-commerce developers
10
+ format: split
11
+ ---
12
+
13
+ # @rune/ecommerce
14
+
15
+ ## Purpose
16
+
17
+ E-commerce codebases fail at the seams between systems: payment intents that succeed but order records that don't get created, inventory counts that go negative during flash sales, subscription proration that charges the wrong amount mid-cycle, tax calculations that use cart-time rates instead of checkout-time rates, carts that lose items when users sign in, and webhook handlers that process the same event twice. This pack addresses the full order lifecycle — storefront to payment to fulfillment — with patterns that handle the race conditions, state machines, and distributed system problems that every commerce platform eventually hits.
18
+
19
+ ## Triggers
20
+
21
+ - Auto-trigger: when `shopify.app.toml`, `*.liquid`, `cart`, `checkout`, `stripe` in payment context, `inventory` schema detected
22
+ - `/rune shopify-dev` — audit Shopify theme or app architecture
23
+ - `/rune payment-integration` — set up or audit payment flows
24
+ - `/rune subscription-billing` — set up or audit recurring billing
25
+ - `/rune cart-system` — build or audit cart architecture
26
+ - `/rune inventory-mgmt` — audit inventory tracking and stock management
27
+ - `/rune order-management` — audit order lifecycle and fulfillment
28
+ - `/rune tax-compliance` — set up or audit tax calculation
29
+ - Called by `cook` (L1) when e-commerce project detected
30
+ - Called by `launch` (L1) when preparing storefront for production
31
+
32
+ ## Skills Included
33
+
34
+ | Skill | Model | Description |
35
+ |-------|-------|-------------|
36
+ | [shopify-dev](skills/shopify-dev.md) | sonnet | Shopify theme, Hydrogen, app architecture — Liquid templates, Storefront API, metafields, webhook HMAC verification. |
37
+ | [payment-integration](skills/payment-integration.md) | sonnet | Stripe, 3DS, webhooks, fraud detection, multi-currency, Vietnamese gateways (SePay, VNPay, MoMo). |
38
+ | [subscription-billing](skills/subscription-billing.md) | sonnet | Trials, proration, dunning, plan changes mid-cycle, usage-based billing, cancellation flows. |
39
+ | [cart-system](skills/cart-system.md) | sonnet | Persistent carts, guest-to-auth merge, server-authoritative totals, coupon engine. |
40
+ | [inventory-mgmt](skills/inventory-mgmt.md) | sonnet | Atomic stock with optimistic locking, reservations, low-stock alerts, backorder handling. |
41
+ | [order-management](skills/order-management.md) | sonnet | State machine, fulfillment, refund/return flows, reconciliation, webhook fan-out. |
42
+ | [tax-compliance](skills/tax-compliance.md) | sonnet | Tax APIs, EU VAT reverse charge, digital goods tax, audit trail per order line item. |
43
+
44
+ ## Common Workflows
45
+
46
+ | Workflow | Skills Involved | Description |
47
+ |----------|----------------|-------------|
48
+ | Full checkout | cart-system → tax-compliance → payment-integration → order-management | Complete purchase from cart to confirmation |
49
+ | Flash sale | inventory-mgmt → cart-system → payment-integration | High-concurrency stock control |
50
+ | Subscription signup | cart-system → payment-integration → subscription-billing | Free trial with payment method upfront |
51
+ | Plan upgrade | subscription-billing → payment-integration → tax-compliance | Mid-cycle upgrade with proration invoice |
52
+ | Order cancellation | order-management → inventory-mgmt → payment-integration | Cancel + release stock + issue refund |
53
+ | New market launch | tax-compliance → payment-integration (multi-currency) → shopify-dev | Localization, VAT, FX pricing |
54
+ | Fraud review | payment-integration (fraud patterns) → order-management | Risk scoring before order fulfilment |
55
+ | Product catalog | shopify-dev → inventory-mgmt | Variant structure + stock sync |
56
+
57
+ ## Tech Stack Support
58
+
59
+ | Platform | Framework | Payment | Notes |
60
+ |----------|-----------|---------|-------|
61
+ | Shopify | Hydrogen 2.x (Remix) | Shopify Payments | Storefront + Admin API |
62
+ | Custom | Next.js 16 / SvelteKit | Stripe | Most flexible |
63
+ | Headless | Any frontend | Stripe / PayPal | API-first commerce |
64
+ | Medusa.js | Next.js | Stripe / PayPal | Open-source alternative |
65
+ | Saleor | React / Next.js | Stripe / Braintree | GraphQL-first |
66
+
67
+ ## Connections
68
+
69
+ ```
70
+ Calls → sentinel (L2): PCI compliance audit on payment code, webhook security
71
+ Calls → db (L2): schema design for orders, inventory, carts, subscriptions
72
+ Calls → perf (L2): audit checkout page load, cart update latency
73
+ Calls → verification (L3): run payment flow integration tests
74
+ Called By ← cook (L1): when e-commerce project detected
75
+ Called By ← launch (L1): pre-launch checkout verification
76
+ Called By ← review (L2): when payment or cart code under review
77
+ Called By ← ba (L2): requirements elicitation for e-commerce features
78
+ ```
79
+
80
+ ## Sharp Edges
81
+
82
+ | Failure Mode | Severity | Mitigation |
83
+ |---|---|---|
84
+ | Double charge from retried Payment Intent without idempotency key | CRITICAL | Derive idempotencyKey from `cartId-v${version}`, not timestamp; check for existing succeeded intent |
85
+ | Webhook signature fails because `req.body` is parsed JSON instead of raw bytes | CRITICAL | Use `express.raw({ type: 'application/json' })` for webhook route; verify with `req.body` as Buffer |
86
+ | Overselling during flash sale (stock goes negative) | CRITICAL | Use optimistic locking with version field; serializable isolation for high-contention items |
87
+ | Payment succeeded but order creation fails (money taken, no order record) | HIGH | Wrap in transaction; run reconciliation job matching payment intents to orders every hour |
88
+ | Same webhook processed twice creates duplicate orders | HIGH | Store `event.id` in database; check before processing; wrap in transaction |
89
+ | Guest cart items lost on login (separate cart created for auth user) | HIGH | Implement cart merge in auth callback; prefer server cart state over local |
90
+ | Subscription proration charges wrong amount on mid-cycle plan change | HIGH | Explicitly set `proration_behavior`; preview proration with `stripe.invoices.retrieveUpcoming` |
91
+ | Trial-to-paid conversion fails silently (no payment method on file) | HIGH | Require payment method at trial signup; set `missing_payment_method: 'cancel'` in trial settings |
92
+ | Tax calculated at cart time but rate changed by checkout (wrong amount charged) | MEDIUM | Recalculate tax at payment creation time using shipping address, not cart-add time |
93
+ | Liquid template outputs unescaped metafield content (XSS in Shopify theme) | HIGH | Always use `| escape` filter on user-generated metafield values |
94
+ | Cancelled order stock not returned to inventory | MEDIUM | Use order state machine with side effects — cancellation always triggers `releaseOrderReservations` |
95
+ | Reservation never expires for abandoned checkout (stock locked forever) | MEDIUM | Run reservation expiry job every 5 minutes; default reservation TTL = 15 minutes |
96
+ | Stolen card fraud passes payment but triggers chargeback later | HIGH | Apply fraud scoring before confirmation; hold high-risk orders for manual review |
97
+ | FX rate stale on multi-currency display — user sees wrong price | MEDIUM | Cache FX rates max 15 minutes; show rate timestamp to user; always charge in store base currency |
98
+
99
+ ## Done When
100
+
101
+ - Checkout flow completes end-to-end: cart → tax → payment → order confirmation
102
+ - Subscription lifecycle handles trial → active → past_due → cancelled with proper dunning
103
+ - Inventory accurately tracks stock with no overselling under concurrent load
104
+ - Order state machine enforces valid transitions with side effects (stock release, refunds, notifications)
105
+ - Webhooks are idempotent, signature-verified, and handle all payment/subscription lifecycle events
106
+ - Tax calculated at checkout with audit trail stored per order line item
107
+ - Guest-to-authenticated cart merge works without data loss
108
+ - All prices, discounts, and coupons validated server-side
109
+ - Reconciliation job catches payment/order mismatches
110
+ - Fraud scoring applied to all orders; high-risk orders flagged for review
111
+ - Multi-currency display works with cached FX rates; charges always in base currency
112
+ - Structured report emitted for each skill invoked
113
+
114
+ ## Cost Profile
115
+
116
+ ~14,000–26,000 tokens per full pack run (all 7 skills). Individual skill: ~2,000–4,000 tokens. Sonnet default. Use haiku for detection scans; escalate to sonnet for payment flow, subscription lifecycle, and order state machine generation.
@@ -1,79 +1,79 @@
1
- ---
2
- name: "cart-system"
3
- pack: "@rune/ecommerce"
4
- description: "Shopping cart architecture — state management, persistent carts, guest checkout, coupon/discount engine, guest-to-auth cart merge."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # cart-system
10
-
11
- Shopping cart architecture — state management, persistent carts, guest checkout, coupon/discount engine, guest-to-auth cart merge.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Detect cart architecture**
16
- Use Grep to find cart state: `cartStore`, `useCart`, `addToCart`, `localStorage.*cart`, `session.*cart`. Read cart-related components and API routes to understand: client vs server cart, persistence strategy, and discount handling.
17
-
18
- **Step 2 — Audit cart integrity**
19
- Check for:
20
- - Cart total calculated client-side only (price manipulation — attacker changes localStorage price)
21
- - No cart TTL (stale carts hold inventory reservations indefinitely)
22
- - Missing guest-to-authenticated cart merge (items lost on login)
23
- - Race conditions on concurrent cart updates (two tabs adding items, last write wins)
24
- - Coupons validated client-side (attacker applies any discount code)
25
- - No stock check at add-to-cart time (user adds 100 items, stock is 3)
26
- - Cart stored in localStorage only (lost on device switch, no cross-device)
27
-
28
- **Step 3 — Emit cart patterns**
29
- Emit: server-authoritative cart with client cache, guest-to-auth merge flow, coupon validation middleware, and optimistic UI with server reconciliation.
30
-
31
- #### Example
32
-
33
- ```typescript
34
- // Server-authoritative cart with Zustand client cache
35
- import { create } from 'zustand';
36
- import { persist } from 'zustand/middleware';
37
-
38
- interface CartStore {
39
- items: CartItem[];
40
- cartId: string | null;
41
- addItem: (productId: string, variantId: string, qty: number) => Promise<void>;
42
- mergeGuestCart: (userId: string) => Promise<void>;
43
- }
44
-
45
- const useCart = create<CartStore>()(persist((set, get) => ({
46
- items: [], cartId: null,
47
-
48
- addItem: async (productId, variantId, qty) => {
49
- // Optimistic update (show item immediately)
50
- set(state => ({ items: [...state.items, { productId, variantId, qty, pending: true }] }));
51
- // Server reconciliation (validates stock, calculates price, applies discounts)
52
- const cart = await fetch('/api/cart/add', {
53
- method: 'POST',
54
- body: JSON.stringify({ cartId: get().cartId, productId, variantId, qty }),
55
- }).then(r => r.json());
56
- set({ items: cart.items, cartId: cart.id }); // server is source of truth
57
- },
58
-
59
- mergeGuestCart: async (userId) => {
60
- const { cartId } = get();
61
- if (!cartId) return;
62
- const merged = await fetch('/api/cart/merge', {
63
- method: 'POST', body: JSON.stringify({ guestCartId: cartId, userId }),
64
- }).then(r => r.json());
65
- set({ items: merged.items, cartId: merged.id });
66
- },
67
- }), { name: 'cart-storage' }));
68
-
69
- // Server — coupon validation (NEVER trust client)
70
- app.post('/api/cart/apply-coupon', async (req, res) => {
71
- const { cartId, code } = req.body;
72
- const coupon = await couponService.validate(code); // checks: exists, not expired, usage limit
73
- if (!coupon) return res.status(400).json({ error: 'INVALID_COUPON' });
74
-
75
- const cart = await cartService.applyCoupon(cartId, coupon);
76
- // Recalculate totals server-side after discount
77
- res.json({ cart: cartService.calculateTotals(cart) });
78
- });
79
- ```
1
+ ---
2
+ name: "cart-system"
3
+ pack: "@rune/ecommerce"
4
+ description: "Shopping cart architecture — state management, persistent carts, guest checkout, coupon/discount engine, guest-to-auth cart merge."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # cart-system
10
+
11
+ Shopping cart architecture — state management, persistent carts, guest checkout, coupon/discount engine, guest-to-auth cart merge.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Detect cart architecture**
16
+ Use Grep to find cart state: `cartStore`, `useCart`, `addToCart`, `localStorage.*cart`, `session.*cart`. Read cart-related components and API routes to understand: client vs server cart, persistence strategy, and discount handling.
17
+
18
+ **Step 2 — Audit cart integrity**
19
+ Check for:
20
+ - Cart total calculated client-side only (price manipulation — attacker changes localStorage price)
21
+ - No cart TTL (stale carts hold inventory reservations indefinitely)
22
+ - Missing guest-to-authenticated cart merge (items lost on login)
23
+ - Race conditions on concurrent cart updates (two tabs adding items, last write wins)
24
+ - Coupons validated client-side (attacker applies any discount code)
25
+ - No stock check at add-to-cart time (user adds 100 items, stock is 3)
26
+ - Cart stored in localStorage only (lost on device switch, no cross-device)
27
+
28
+ **Step 3 — Emit cart patterns**
29
+ Emit: server-authoritative cart with client cache, guest-to-auth merge flow, coupon validation middleware, and optimistic UI with server reconciliation.
30
+
31
+ #### Example
32
+
33
+ ```typescript
34
+ // Server-authoritative cart with Zustand client cache
35
+ import { create } from 'zustand';
36
+ import { persist } from 'zustand/middleware';
37
+
38
+ interface CartStore {
39
+ items: CartItem[];
40
+ cartId: string | null;
41
+ addItem: (productId: string, variantId: string, qty: number) => Promise<void>;
42
+ mergeGuestCart: (userId: string) => Promise<void>;
43
+ }
44
+
45
+ const useCart = create<CartStore>()(persist((set, get) => ({
46
+ items: [], cartId: null,
47
+
48
+ addItem: async (productId, variantId, qty) => {
49
+ // Optimistic update (show item immediately)
50
+ set(state => ({ items: [...state.items, { productId, variantId, qty, pending: true }] }));
51
+ // Server reconciliation (validates stock, calculates price, applies discounts)
52
+ const cart = await fetch('/api/cart/add', {
53
+ method: 'POST',
54
+ body: JSON.stringify({ cartId: get().cartId, productId, variantId, qty }),
55
+ }).then(r => r.json());
56
+ set({ items: cart.items, cartId: cart.id }); // server is source of truth
57
+ },
58
+
59
+ mergeGuestCart: async (userId) => {
60
+ const { cartId } = get();
61
+ if (!cartId) return;
62
+ const merged = await fetch('/api/cart/merge', {
63
+ method: 'POST', body: JSON.stringify({ guestCartId: cartId, userId }),
64
+ }).then(r => r.json());
65
+ set({ items: merged.items, cartId: merged.id });
66
+ },
67
+ }), { name: 'cart-storage' }));
68
+
69
+ // Server — coupon validation (NEVER trust client)
70
+ app.post('/api/cart/apply-coupon', async (req, res) => {
71
+ const { cartId, code } = req.body;
72
+ const coupon = await couponService.validate(code); // checks: exists, not expired, usage limit
73
+ if (!coupon) return res.status(400).json({ error: 'INVALID_COUPON' });
74
+
75
+ const cart = await cartService.applyCoupon(cartId, coupon);
76
+ // Recalculate totals server-side after discount
77
+ res.json({ cart: cartService.calculateTotals(cart) });
78
+ });
79
+ ```
@@ -1,102 +1,102 @@
1
- ---
2
- name: "inventory-mgmt"
3
- pack: "@rune/ecommerce"
4
- description: "Inventory management — stock tracking with optimistic locking, variant management, low stock alerts, backorder handling, reservation expiry."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # inventory-mgmt
10
-
11
- Inventory management — stock tracking with optimistic locking, variant management, low stock alerts, backorder handling, reservation expiry.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Detect inventory model**
16
- Use Grep to find stock-related code: `stock`, `inventory`, `quantity`, `variant`, `warehouse`, `sku`. Read schema files to understand: single vs multi-warehouse, variant structure, and reservation model.
17
-
18
- **Step 2 — Audit stock integrity**
19
- Check for:
20
- - Stock decremented without transaction (oversell risk under concurrent load)
21
- - No optimistic locking on concurrent updates (version field or `FOR UPDATE` lock)
22
- - Inventory checked at cart-add but not at checkout (stale check — stock sold out between add and pay)
23
- - Missing low-stock alerts (ops team discovers stockout from customer complaints)
24
- - No reservation expiry for abandoned checkouts (stock locked forever)
25
- - No backorder handling for out-of-stock items (zero stock = hard error vs queue)
26
- - Flash sale race condition: 10 users checkout simultaneously with 3 items left = 7 oversold orders
27
-
28
- **Step 3 — Emit inventory patterns**
29
- Emit: atomic stock reservation with optimistic locking (version field), reservation expiry job for abandoned checkouts, low-stock alert trigger, and backorder queue.
30
-
31
- #### Example
32
-
33
- ```typescript
34
- // Atomic stock reservation with optimistic locking (Prisma)
35
- async function reserveStock(variantId: string, qty: number, orderId: string) {
36
- const MAX_RETRIES = 3;
37
- for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
38
- const variant = await prisma.variant.findUniqueOrThrow({ where: { id: variantId } });
39
-
40
- if (variant.stock < qty && !variant.allowBackorder) {
41
- throw new Error(`Insufficient stock: ${variant.stock} available, ${qty} requested`);
42
- }
43
-
44
- try {
45
- const updated = await prisma.variant.update({
46
- where: { id: variantId, version: variant.version }, // optimistic lock
47
- data: {
48
- stock: { decrement: qty },
49
- version: { increment: 1 },
50
- reservations: { create: { orderId, qty, expiresAt: addMinutes(new Date(), 15) } },
51
- },
52
- });
53
-
54
- if (updated.stock <= updated.lowStockThreshold) {
55
- await alertService.trigger('LOW_STOCK', { variantId, currentStock: updated.stock });
56
- }
57
- return updated;
58
- } catch (e) {
59
- if (attempt === MAX_RETRIES - 1) throw new Error('Stock reservation failed: concurrent modification');
60
- }
61
- }
62
- }
63
-
64
- // Reservation expiry job — release stock from abandoned checkouts
65
- async function releaseExpiredReservations() {
66
- const expired = await prisma.reservation.findMany({
67
- where: { expiresAt: { lt: new Date() }, status: 'PENDING' },
68
- });
69
-
70
- for (const reservation of expired) {
71
- await prisma.$transaction([
72
- prisma.variant.update({
73
- where: { id: reservation.variantId },
74
- data: { stock: { increment: reservation.qty } },
75
- }),
76
- prisma.reservation.update({
77
- where: { id: reservation.id },
78
- data: { status: 'EXPIRED' },
79
- }),
80
- ]);
81
- }
82
- }
83
-
84
- // Inventory webhook — push stock changes to external systems (3PL, ERP)
85
- async function emitInventoryWebhook(variantId: string, newStock: number, event: string) {
86
- const variant = await prisma.variant.findUniqueOrThrow({
87
- where: { id: variantId },
88
- include: { product: true },
89
- });
90
- const payload = {
91
- event, // 'STOCK_UPDATED' | 'LOW_STOCK' | 'OUT_OF_STOCK'
92
- sku: variant.sku,
93
- variantId,
94
- productId: variant.productId,
95
- stock: newStock,
96
- threshold: variant.lowStockThreshold,
97
- timestamp: new Date().toISOString(),
98
- };
99
- // Fan-out to all registered webhook endpoints
100
- await webhookFanOut(payload, 'inventory.*');
101
- }
102
- ```
1
+ ---
2
+ name: "inventory-mgmt"
3
+ pack: "@rune/ecommerce"
4
+ description: "Inventory management — stock tracking with optimistic locking, variant management, low stock alerts, backorder handling, reservation expiry."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # inventory-mgmt
10
+
11
+ Inventory management — stock tracking with optimistic locking, variant management, low stock alerts, backorder handling, reservation expiry.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Detect inventory model**
16
+ Use Grep to find stock-related code: `stock`, `inventory`, `quantity`, `variant`, `warehouse`, `sku`. Read schema files to understand: single vs multi-warehouse, variant structure, and reservation model.
17
+
18
+ **Step 2 — Audit stock integrity**
19
+ Check for:
20
+ - Stock decremented without transaction (oversell risk under concurrent load)
21
+ - No optimistic locking on concurrent updates (version field or `FOR UPDATE` lock)
22
+ - Inventory checked at cart-add but not at checkout (stale check — stock sold out between add and pay)
23
+ - Missing low-stock alerts (ops team discovers stockout from customer complaints)
24
+ - No reservation expiry for abandoned checkouts (stock locked forever)
25
+ - No backorder handling for out-of-stock items (zero stock = hard error vs queue)
26
+ - Flash sale race condition: 10 users checkout simultaneously with 3 items left = 7 oversold orders
27
+
28
+ **Step 3 — Emit inventory patterns**
29
+ Emit: atomic stock reservation with optimistic locking (version field), reservation expiry job for abandoned checkouts, low-stock alert trigger, and backorder queue.
30
+
31
+ #### Example
32
+
33
+ ```typescript
34
+ // Atomic stock reservation with optimistic locking (Prisma)
35
+ async function reserveStock(variantId: string, qty: number, orderId: string) {
36
+ const MAX_RETRIES = 3;
37
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
38
+ const variant = await prisma.variant.findUniqueOrThrow({ where: { id: variantId } });
39
+
40
+ if (variant.stock < qty && !variant.allowBackorder) {
41
+ throw new Error(`Insufficient stock: ${variant.stock} available, ${qty} requested`);
42
+ }
43
+
44
+ try {
45
+ const updated = await prisma.variant.update({
46
+ where: { id: variantId, version: variant.version }, // optimistic lock
47
+ data: {
48
+ stock: { decrement: qty },
49
+ version: { increment: 1 },
50
+ reservations: { create: { orderId, qty, expiresAt: addMinutes(new Date(), 15) } },
51
+ },
52
+ });
53
+
54
+ if (updated.stock <= updated.lowStockThreshold) {
55
+ await alertService.trigger('LOW_STOCK', { variantId, currentStock: updated.stock });
56
+ }
57
+ return updated;
58
+ } catch (e) {
59
+ if (attempt === MAX_RETRIES - 1) throw new Error('Stock reservation failed: concurrent modification');
60
+ }
61
+ }
62
+ }
63
+
64
+ // Reservation expiry job — release stock from abandoned checkouts
65
+ async function releaseExpiredReservations() {
66
+ const expired = await prisma.reservation.findMany({
67
+ where: { expiresAt: { lt: new Date() }, status: 'PENDING' },
68
+ });
69
+
70
+ for (const reservation of expired) {
71
+ await prisma.$transaction([
72
+ prisma.variant.update({
73
+ where: { id: reservation.variantId },
74
+ data: { stock: { increment: reservation.qty } },
75
+ }),
76
+ prisma.reservation.update({
77
+ where: { id: reservation.id },
78
+ data: { status: 'EXPIRED' },
79
+ }),
80
+ ]);
81
+ }
82
+ }
83
+
84
+ // Inventory webhook — push stock changes to external systems (3PL, ERP)
85
+ async function emitInventoryWebhook(variantId: string, newStock: number, event: string) {
86
+ const variant = await prisma.variant.findUniqueOrThrow({
87
+ where: { id: variantId },
88
+ include: { product: true },
89
+ });
90
+ const payload = {
91
+ event, // 'STOCK_UPDATED' | 'LOW_STOCK' | 'OUT_OF_STOCK'
92
+ sku: variant.sku,
93
+ variantId,
94
+ productId: variant.productId,
95
+ stock: newStock,
96
+ threshold: variant.lowStockThreshold,
97
+ timestamp: new Date().toISOString(),
98
+ };
99
+ // Fan-out to all registered webhook endpoints
100
+ await webhookFanOut(payload, 'inventory.*');
101
+ }
102
+ ```