@rovela-ai/sdk 0.21.0 → 0.23.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 (124) hide show
  1. package/dist/admin/api/email-sending.d.ts +24 -0
  2. package/dist/admin/api/email-sending.d.ts.map +1 -0
  3. package/dist/admin/api/email-sending.js +155 -0
  4. package/dist/admin/api/email-sending.js.map +1 -0
  5. package/dist/admin/api/index.d.ts +2 -0
  6. package/dist/admin/api/index.d.ts.map +1 -1
  7. package/dist/admin/api/index.js +4 -0
  8. package/dist/admin/api/index.js.map +1 -1
  9. package/dist/admin/api/integrations-brevo.d.ts +24 -0
  10. package/dist/admin/api/integrations-brevo.d.ts.map +1 -0
  11. package/dist/admin/api/integrations-brevo.js +286 -0
  12. package/dist/admin/api/integrations-brevo.js.map +1 -0
  13. package/dist/admin/api/integrations.d.ts +2 -0
  14. package/dist/admin/api/integrations.d.ts.map +1 -1
  15. package/dist/admin/api/integrations.js +1 -0
  16. package/dist/admin/api/integrations.js.map +1 -1
  17. package/dist/admin/api/products.d.ts.map +1 -1
  18. package/dist/admin/api/products.js +4 -0
  19. package/dist/admin/api/products.js.map +1 -1
  20. package/dist/admin/api/settings.d.ts.map +1 -1
  21. package/dist/admin/api/settings.js +4 -1
  22. package/dist/admin/api/settings.js.map +1 -1
  23. package/dist/admin/api/tax-zones.d.ts.map +1 -1
  24. package/dist/admin/api/tax-zones.js +7 -0
  25. package/dist/admin/api/tax-zones.js.map +1 -1
  26. package/dist/admin/components/EmailsManager.d.ts.map +1 -1
  27. package/dist/admin/components/EmailsManager.js +2 -1
  28. package/dist/admin/components/EmailsManager.js.map +1 -1
  29. package/dist/admin/components/IntegrationsManager.d.ts.map +1 -1
  30. package/dist/admin/components/IntegrationsManager.js +98 -2
  31. package/dist/admin/components/IntegrationsManager.js.map +1 -1
  32. package/dist/admin/components/OrderDetails.d.ts.map +1 -1
  33. package/dist/admin/components/OrderDetails.js +5 -1
  34. package/dist/admin/components/OrderDetails.js.map +1 -1
  35. package/dist/admin/components/ProductForm.d.ts.map +1 -1
  36. package/dist/admin/components/ProductForm.js +36 -1
  37. package/dist/admin/components/ProductForm.js.map +1 -1
  38. package/dist/admin/components/TaxSettings.d.ts.map +1 -1
  39. package/dist/admin/components/TaxSettings.js +16 -4
  40. package/dist/admin/components/TaxSettings.js.map +1 -1
  41. package/dist/admin/components/emails/EmailSendingPanel.d.ts +2 -0
  42. package/dist/admin/components/emails/EmailSendingPanel.d.ts.map +1 -0
  43. package/dist/admin/components/emails/EmailSendingPanel.js +131 -0
  44. package/dist/admin/components/emails/EmailSendingPanel.js.map +1 -0
  45. package/dist/admin/integrations/registry.d.ts +2 -0
  46. package/dist/admin/integrations/registry.d.ts.map +1 -1
  47. package/dist/admin/integrations/registry.js +41 -0
  48. package/dist/admin/integrations/registry.js.map +1 -1
  49. package/dist/admin/types.d.ts +15 -0
  50. package/dist/admin/types.d.ts.map +1 -1
  51. package/dist/checkout/api/manual.d.ts.map +1 -1
  52. package/dist/checkout/api/manual.js +7 -0
  53. package/dist/checkout/api/manual.js.map +1 -1
  54. package/dist/checkout/api/shipping.d.ts +0 -18
  55. package/dist/checkout/api/shipping.d.ts.map +1 -1
  56. package/dist/checkout/api/shipping.js +33 -3
  57. package/dist/checkout/api/shipping.js.map +1 -1
  58. package/dist/checkout/components/CheckoutFlow.d.ts.map +1 -1
  59. package/dist/checkout/components/CheckoutFlow.js +30 -13
  60. package/dist/checkout/components/CheckoutFlow.js.map +1 -1
  61. package/dist/checkout/components/OrderSummary.d.ts +1 -1
  62. package/dist/checkout/components/OrderSummary.d.ts.map +1 -1
  63. package/dist/checkout/components/OrderSummary.js +5 -2
  64. package/dist/checkout/components/OrderSummary.js.map +1 -1
  65. package/dist/checkout/server/create-checkout-session.d.ts.map +1 -1
  66. package/dist/checkout/server/create-checkout-session.js +38 -9
  67. package/dist/checkout/server/create-checkout-session.js.map +1 -1
  68. package/dist/checkout/server/handle-webhook.js +6 -0
  69. package/dist/checkout/server/handle-webhook.js.map +1 -1
  70. package/dist/checkout/server/order-service.d.ts.map +1 -1
  71. package/dist/checkout/server/order-service.js +21 -0
  72. package/dist/checkout/server/order-service.js.map +1 -1
  73. package/dist/checkout/server/pricing.d.ts +28 -1
  74. package/dist/checkout/server/pricing.d.ts.map +1 -1
  75. package/dist/checkout/server/pricing.js +84 -6
  76. package/dist/checkout/server/pricing.js.map +1 -1
  77. package/dist/checkout/types.d.ts +32 -0
  78. package/dist/checkout/types.d.ts.map +1 -1
  79. package/dist/core/db/queries.d.ts +114 -25
  80. package/dist/core/db/queries.d.ts.map +1 -1
  81. package/dist/core/db/queries.js +124 -2
  82. package/dist/core/db/queries.js.map +1 -1
  83. package/dist/core/db/schema.d.ts +213 -0
  84. package/dist/core/db/schema.d.ts.map +1 -1
  85. package/dist/core/db/schema.js +42 -0
  86. package/dist/core/db/schema.js.map +1 -1
  87. package/dist/emails/index.d.ts +2 -0
  88. package/dist/emails/index.d.ts.map +1 -1
  89. package/dist/emails/index.js +1 -0
  90. package/dist/emails/index.js.map +1 -1
  91. package/dist/emails/send/orders.d.ts +4 -0
  92. package/dist/emails/send/orders.d.ts.map +1 -1
  93. package/dist/emails/send/orders.js +1 -0
  94. package/dist/emails/send/orders.js.map +1 -1
  95. package/dist/emails/sender.d.ts.map +1 -1
  96. package/dist/emails/sender.js +30 -5
  97. package/dist/emails/sender.js.map +1 -1
  98. package/dist/emails/templates/order-confirmation.d.ts +9 -0
  99. package/dist/emails/templates/order-confirmation.d.ts.map +1 -1
  100. package/dist/emails/templates/order-confirmation.js +19 -8
  101. package/dist/emails/templates/order-confirmation.js.map +1 -1
  102. package/dist/emails/transport-smtp.d.ts +58 -0
  103. package/dist/emails/transport-smtp.d.ts.map +1 -0
  104. package/dist/emails/transport-smtp.js +97 -0
  105. package/dist/emails/transport-smtp.js.map +1 -0
  106. package/dist/emails/transport.d.ts +77 -0
  107. package/dist/emails/transport.d.ts.map +1 -0
  108. package/dist/emails/transport.js +154 -0
  109. package/dist/emails/transport.js.map +1 -0
  110. package/dist/emails/types.d.ts +5 -0
  111. package/dist/emails/types.d.ts.map +1 -1
  112. package/dist/products/api/products.d.ts.map +1 -1
  113. package/dist/products/api/products.js +18 -3
  114. package/dist/products/api/products.js.map +1 -1
  115. package/docs/changelog/epoch-09-catalog-tax.md +91 -0
  116. package/docs/changelog/epoch-10-email-transport.md +97 -0
  117. package/package.json +2 -1
  118. package/templates/store-template/.claude/skills/manage-products/SKILL.md +1 -1
  119. package/templates/store-template/app/account/orders/[id]/invoice/page.tsx +19 -4
  120. package/templates/store-template/app/api/admin/emails/sending/route.ts +9 -0
  121. package/templates/store-template/app/api/admin/integrations/brevo/backfill/route.ts +9 -0
  122. package/templates/store-template/app/api/admin/integrations/brevo/route.ts +9 -0
  123. package/templates/store-template/next.config.js +4 -1
  124. package/templates/store-template/package.json +2 -1
@@ -151,6 +151,11 @@ export interface OrderConfirmationData {
151
151
  shippingCost: string;
152
152
  /** Formatted tax (e.g., "$8.00") */
153
153
  tax: string;
154
+ /** Per-rate VAT ventilation (0.22.0), pre-formatted. Multi-rate orders only. */
155
+ taxBreakdown?: Array<{
156
+ rate: number;
157
+ amount: string;
158
+ }>;
154
159
  /** Formatted total (e.g., "$112.00") */
155
160
  total: string;
156
161
  shippingAddress: EmailAddress;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/emails/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/emails/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"products.d.ts","sourceRoot":"","sources":["../../../src/products/api/products.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,EACL,YAAY,EAIb,MAAM,uBAAuB,CAAA;AAQ9B,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAA;IAC9C,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAQD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,GAAG,CACvB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,CAAC,mBAAmB,GAAG,gBAAgB,CAAC,CAAC,CAqG/D"}
1
+ {"version":3,"file":"products.d.ts","sourceRoot":"","sources":["../../../src/products/api/products.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,EACL,YAAY,EAKb,MAAM,uBAAuB,CAAA;AAQ9B,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAA;IAC9C,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAQD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,GAAG,CACvB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,CAAC,mBAAmB,GAAG,gBAAgB,CAAC,CAAC,CAmH/D"}
@@ -11,7 +11,7 @@
11
11
  * ```
12
12
  */
13
13
  import { NextResponse } from 'next/server';
14
- import { findProducts, countProducts, findCategoryBySlug, } from '../../core/db/queries';
14
+ import { findProducts, countProducts, findCategoryBySlug, findCategoryDescendantIds, } from '../../core/db/queries';
15
15
  import { getRequestLocale } from '../../core/server/request-locale';
16
16
  import { localizeCatalogRows } from '../../core/i18n/catalog';
17
17
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -52,7 +52,7 @@ export async function GET(request) {
52
52
  // matched nothing and the link showed the full catalog. An unknown slug
53
53
  // returns an honest empty result instead.
54
54
  const categoryParam = searchParams.get('category') || undefined;
55
- let categoryId = categoryParam;
55
+ let resolvedCategoryId = categoryParam;
56
56
  if (categoryParam && !UUID_RE.test(categoryParam)) {
57
57
  const category = await findCategoryBySlug(categoryParam);
58
58
  if (!category) {
@@ -64,7 +64,22 @@ export async function GET(request) {
64
64
  hasMore: false,
65
65
  });
66
66
  }
67
- categoryId = category.id;
67
+ resolvedCategoryId = category.id;
68
+ }
69
+ // Tree-aware: a parent-category link includes its descendants' products
70
+ // (imported catalogs assign products to LEAF categories — PrestaShop-front
71
+ // behaviour). Leaf categories have no descendants → exact match, and a
72
+ // descendant-lookup failure degrades to exact match, never a 500.
73
+ let categoryId = resolvedCategoryId;
74
+ if (resolvedCategoryId) {
75
+ try {
76
+ const descendants = await findCategoryDescendantIds(resolvedCategoryId);
77
+ if (descendants.length > 0)
78
+ categoryId = [resolvedCategoryId, ...descendants];
79
+ }
80
+ catch {
81
+ /* exact match fallback */
82
+ }
68
83
  }
69
84
  const onSaleParam = searchParams.get('onSale');
70
85
  const onSale = onSaleParam === '1' || onSaleParam === 'true' ? true : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"products.js","sourceRoot":"","sources":["../../../src/products/api/products.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAe,YAAY,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,kBAAkB,GAEnB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAmB7D,MAAM,OAAO,GAAG,iEAAiE,CAAA;AAEjF,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,OAAoB;IAEpB,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAA;QAEjD,mBAAmB;QACnB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC,CAAA;QACvE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,GAAG,EACH,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAC7D,CAAA;QACD,MAAM,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAA;QAEjC,aAAa;QACb,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAC1C,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAA;QAE1D,oDAAoD;QACpD,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAC9C,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAA;QAElE,oEAAoE;QACpE,sEAAsE;QACtE,wEAAwE;QACxE,0CAA0C;QAC1C,MAAM,aAAa,GAAG,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,SAAS,CAAA;QAC/D,IAAI,UAAU,GAAG,aAAa,CAAA;QAC9B,IAAI,aAAa,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;YAClD,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,aAAa,CAAC,CAAA;YACxD,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,YAAY,CAAC,IAAI,CAAC;oBACvB,IAAI,EAAE,EAAE;oBACR,KAAK,EAAE,CAAC;oBACR,IAAI;oBACJ,QAAQ,EAAE,KAAK;oBACf,OAAO,EAAE,KAAK;iBACf,CAAC,CAAA;YACJ,CAAC;YACD,UAAU,GAAG,QAAQ,CAAC,EAAE,CAAA;QAC1B,CAAC;QAED,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAC9C,MAAM,MAAM,GAAG,WAAW,KAAK,GAAG,IAAI,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;QAE/E,sBAAsB;QACtB,MAAM,OAAO,GAAwB;YACnC,UAAU;YACV,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,SAAS;YAC/C,MAAM;YACN,IAAI;YACJ,MAAM;YACN,KAAK;YACL,MAAM;SACP,CAAA;QAED,8BAA8B;QAC9B,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC1C,YAAY,CAAC,OAAO,CAAC;YACrB,aAAa,CAAC;gBACZ,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC;SACH,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC,MAAM,GAAG,KAAK,CAAA;QAEhD,uEAAuE;QACvE,gEAAgE;QAChE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC7E,MAAM,SAAS,GAAG,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,aAAa,CAAC,CAAA;QAE7E,OAAO,YAAY,CAAC,IAAI,CAAC;YACvB,IAAI,EAAE,SAAS;YACf,KAAK;YACL,IAAI;YACJ,QAAQ,EAAE,KAAK;YACf,OAAO;SACR,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAA;QAE7C,yCAAyC;QACzC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YAC1E,OAAO,YAAY,CAAC,IAAI,CACtB;gBACE,KAAK,EAAE,kEAAkE;gBACzE,IAAI,EAAE,gBAAgB;aACvB,EACD,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB,CAAA;QACH,CAAC;QAED,OAAO,YAAY,CAAC,IAAI,CACtB;YACE,KAAK,EAAE,0BAA0B;YACjC,IAAI,EAAE,gBAAgB;SACvB,EACD,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB,CAAA;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF,SAAS,WAAW,CAClB,KAAoB;IAEpB,OAAO,CACL,KAAK,KAAK,QAAQ;QAClB,KAAK,KAAK,WAAW;QACrB,KAAK,KAAK,YAAY;QACtB,KAAK,KAAK,MAAM,CACjB,CAAA;AACH,CAAC;AAED,SAAS,aAAa,CACpB,KAAoB;IAEpB,OAAO,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,UAAU,CAAA;AACxE,CAAC"}
1
+ {"version":3,"file":"products.js","sourceRoot":"","sources":["../../../src/products/api/products.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ # E9 Catalog & tax — 0.22.0..0.22.0
2
+
3
+ ## What landed
4
+ Two catalog-commerce behaviors every PrestaShop-migrated store needs: the
5
+ public category filter is now TREE-AWARE (a parent-category link includes its
6
+ descendant categories' products — imported catalogs assign products to leaf
7
+ categories), and TAX CLASSES bring per-product VAT rates (French 5.5%/20%
8
+ food split): products carry a `tax_class`, tax zones carry per-class rates,
9
+ and every money surface (quote, Stripe session, orders, emails, invoice,
10
+ admin) computes and renders the per-rate VAT ventilation ("dont TVA par
11
+ taux") French invoices legally require.
12
+
13
+ ## SDK-internal (free)
14
+ - `findProducts`/`countProducts` accept `categoryId: string | string[]`
15
+ (IN-match). New `findCategoryDescendantIds(id)` (recursive CTE) and
16
+ `findTaxClassesByProductIds(ids)`.
17
+ - `resolveTax` accepts optional `lines` — per-line computation grouped by
18
+ rate, order discount allocated pro-rata (largest-remainder, sums exact),
19
+ shipping taxed at the zone's base rate. Returns `taxBreakdown` +
20
+ `taxClassRates`. Without `lines`, or on a zone with no `class_rates`, the
21
+ original lump formula runs — cent-identical to 0.21.x.
22
+ - `buildQuote` carries `taxBreakdown`/`taxClassRates` on the Quote; the
23
+ Stripe session divides each line by ITS OWN rate in tax-inclusive mode and
24
+ stamps `rovelaTaxBreakdown` metadata; both order writers persist
25
+ `orders.tax_breakdown`.
26
+ - Admin: TaxSettings zone editor gains per-class rate rows; ProductForm
27
+ gains a Tax class field (datalist fed from the zones' class names);
28
+ tax-zones API accepts `classRates`; products API accepts `taxClass`.
29
+
30
+ ## Template contract
31
+ - `app/account/orders/[id]/invoice/page.tsx` — the totals block renders one
32
+ `TVA {rate}%` row per `order.taxBreakdown` entry when the order carries a
33
+ multi-rate ventilation, else the single flat tax row (stock shape: gated
34
+ branch on `order.taxBreakdown?.length > 1`). Stores with a customized
35
+ invoice keep their layout and add the same branch.
36
+
37
+ ## Behavior contracts
38
+ - **Public `/api/products?category=` is tree-aware.** A parent category id or
39
+ slug now returns its own products PLUS every descendant category's. Stores
40
+ whose nav deliberately relied on parent links showing ONLY directly-assigned
41
+ products (rare; usually a bug they worked around) will see more products.
42
+ Admin product filters are UNCHANGED (exact match).
43
+ - **`OrderSummary` accepts `taxBreakdown`** and renders per-rate rows when
44
+ more than one rate is present; `CheckoutFlow` computes it from the estimate
45
+ response. Single-rate stores render byte-identically to 0.21.x.
46
+ - The pre-checkout shipping estimate (`/api/checkout/shipping`) accepts an
47
+ optional `productId` per item and returns `tax.breakdown`. Clients that
48
+ omit `productId` get the previous base-rate estimate (totals unchanged in
49
+ tax-inclusive stores).
50
+
51
+ ## Custom-code hazards
52
+ - `grep -rn "resolveTax(" app lib components` — custom callers keep working
53
+ (the `lines` param is optional; omitted = old math). If a custom checkout
54
+ displays tax recomputed from `taxRate` alone, it cannot reproduce a
55
+ multi-rate cart: read `tax.breakdown`/`quote.taxBreakdown` when present
56
+ (see CheckoutFlow's per-group recompute for the reference implementation).
57
+ - `grep -rn "taxRate" app components` — any custom "TVA (20%)" label stays
58
+ correct for single-rate stores; multi-rate stores should render the
59
+ breakdown rows instead.
60
+ - `grep -rn "category=" app components lib` — store-authored nav links to
61
+ PARENT categories now include leaf products (this is almost always the
62
+ desired fix, not a regression).
63
+
64
+ ## DB
65
+ - `products.tax_class varchar(50)` NULL — self-heals via
66
+ `ensureCatalogTranslationsSchema` (every catalog chokepoint).
67
+ - `tax_zones.class_rates jsonb NOT NULL DEFAULT '{}'` — self-heals via
68
+ `ensureVisibilityColumns`.
69
+ - `orders.tax_breakdown jsonb` NULL — self-heals via
70
+ `ensurePaymentMethodsSchema`.
71
+ - All three are additive with behavior-preserving defaults: no class rates
72
+ configured = 0.21.x math to the cent. Pre-applying is optional.
73
+
74
+ ## New surfaces
75
+ - None. (TaxSettings/ProductForm gains are inside existing admin pages; no
76
+ new routes to mount.)
77
+
78
+ ## Verify
79
+ 1. `/products?category=<parent slug>` lists products assigned to child
80
+ categories; the admin Products page filtered to the same parent does NOT.
81
+ 2. Settings → Tax: add a class rate (e.g. `tva-5-5` = 5.5) on the active
82
+ zone; assign the class to one product (Product form → Pricing → Tax
83
+ class).
84
+ 3. Cart with one classed + one unclassed product → checkout review shows two
85
+ `TVA x%` rows summing to the receipt tax; totals unchanged
86
+ (tax-inclusive).
87
+ 4. Place a test order → `orders.tax_breakdown` populated; invoice page and
88
+ order-confirmation email render the ventilation; admin order detail shows
89
+ per-rate rows.
90
+ 5. A store that configures NO class rates: quote totals and every tax line
91
+ render exactly as before the update.
@@ -0,0 +1,97 @@
1
+ # E10 Email sending & Brevo — 0.23.0..0.23.0
2
+
3
+ ## What landed
4
+ Transactional-email delivery became merchant-configurable. Every store email
5
+ (order confirmations, account emails, custom emails) already funnels through
6
+ the SDK's one `sendEmail()` chokepoint; it now resolves a per-store
7
+ TRANSPORT: `'platform'` (default — the pre-0.23 Resend path, byte-identical
8
+ for the whole fleet), `'brevo'` (the store's connected Brevo account over
9
+ its HTTP API — same API key as the marketing integration, no SMTP key
10
+ needed), or `'smtp'` (the merchant's own server). The Brevo integration
11
+ also gained a live status echo and a one-click, resumable HISTORY IMPORT
12
+ that replaces per-store backfill scripts.
13
+
14
+ ## SDK-internal (free via pin bump)
15
+ - `emails/transport.ts` — transport resolution + the two senders. **FAIL-SAFE
16
+ DELIVERY RULE**: a non-platform transport failure falls back to the
17
+ platform Resend path and logs loudly; a merchant's SMTP typo can never eat
18
+ an order confirmation. Misconfiguration surfaces at SAVE time instead
19
+ (real SMTP `verify()` handshake; Brevo verified-sender check).
20
+ - New `store_settings` columns (drizzle + `ensureStoreSettingsSchema` +
21
+ parent-branch ALTER at ship time): `email_transport`,
22
+ `email_from_address`, `email_from_name`, `smtp_host`, `smtp_port`,
23
+ `smtp_secure`, `smtp_user`, `smtp_password` (SERVER-ONLY secret — stripped
24
+ from the admin settings GET like `colissimo_password`; write-only, blank
25
+ keeps the stored value).
26
+ - `nodemailer` (pinned to the 7.x line — next-auth 4.x declares
27
+ `peerOptional nodemailer@^7` and npm refuses to hoist a different major)
28
+ became BOTH an SDK dependency and a TEMPLATE dependency (root-hoisted,
29
+ deterministic location). It loads through a BUNDLER-IGNORED dynamic
30
+ import (`webpackIgnore` + `turbopackIgnore`, isolated in
31
+ `emails/transport-smtp.ts`) — the emails graph is client-reachable, so a
32
+ static import breaks `next build`; the ignored import is native
33
+ server-runtime resolution, no path guessing.
34
+ - `EmailSendingPanel` (Sending card on /admin/emails) + `EmailsManager`
35
+ mounts it; the "Send a test" button exercises the REAL saved transport.
36
+ - Integrations registry entries gained `details` bullets (what each
37
+ integration actually does, rendered in the configure modal — all 10
38
+ entries authored).
39
+ - Brevo configure modal extras: live "Connected as x@y · plan" echo,
40
+ verified-sender status, the "send transactional emails through Brevo"
41
+ toggle (writes the same `email_transport` column as the Sending panel —
42
+ the two surfaces can never disagree), and the history import UI
43
+ (progress bar, resumable, include-orders switch defaulted OFF when
44
+ Brevo's eCommerce module already holds orders — the double-count guard).
45
+
46
+ ## Template contract
47
+ - `app/api/admin/emails/sending/route.ts` (NEW) — re-export
48
+ `getEmailSending as GET, putEmailSending as PUT`. Without it the Sending
49
+ panel shows a load error and the Brevo toggle cannot save.
50
+ - `app/api/admin/integrations/brevo/route.ts` (NEW) — `getBrevoStatus as
51
+ GET`; `app/api/admin/integrations/brevo/backfill/route.ts` (NEW) —
52
+ `postBrevoBackfill as POST`. Without them the Brevo modal's extras show
53
+ an error state (credentials editing keeps working).
54
+ - **Component-dependency note (the E4 precedent)**: two per-store
55
+ requirements for the Custom-SMTP option — `package.json` gains
56
+ `"nodemailer": "7.0.13"` (MUST stay on 7.x: next-auth's peerOptional
57
+ range; a 8/9 pin makes npm nest it where the runtime can't resolve it)
58
+ and `next.config.js` gains
59
+ `outputFileTracingIncludes: ['./node_modules/nodemailer/**']` (an ignored
60
+ import is invisible to Vercel's tracer). A store updating the SDK WITHOUT
61
+ these loses only the Custom-SMTP option at runtime (platform + Brevo
62
+ transports are unaffected — Brevo is plain fetch), with a loud
63
+ `[Email] nodemailer not loadable` log.
64
+
65
+ ## Behavior contracts
66
+ - `sendEmail()` behavior is UNCHANGED while `email_transport` is NULL /
67
+ 'platform' — the entire existing fleet keeps its exact sending path.
68
+ - The Brevo history import is idempotent + resumable: contacts upsert by
69
+ email (`updateEnabled` — no duplicates, existing attributes/lists/consent
70
+ untouched, NO listIds ever sent), orders push with `historical: true`
71
+ (populates dashboards, NEVER fires an automation), chunked per request
72
+ (serverless-safe; the modal loops on the returned cursor).
73
+ - Per-store backfill scripts are RETIRED: the connect-brevo card + the
74
+ credentials contract now forbid writing one-off sync scripts into the
75
+ repo — history imports live in the admin.
76
+
77
+ ## Custom-code hazards (audit greps for CC)
78
+ - Grep `scripts/` for hand-written Brevo/marketing backfill or sync scripts
79
+ (e.g. EasyElec's `scripts/brevo-backfill.mjs`) — superseded by
80
+ Integrations → Brevo → "Import history"; delete them.
81
+ - Grep for direct `getResend()` / `resend.emails.send` calls in store code —
82
+ they bypass the transport layer; route them through `sendEmail()` from
83
+ `@rovela-ai/sdk/emails`.
84
+
85
+ ## MERCHANT-DATA HAZARD
86
+ None — no existing data changes meaning. The default transport is the
87
+ existing behavior; Brevo/SMTP are opt-in.
88
+
89
+ ## Verify
90
+ - /admin/emails shows the Sending card; saving Custom SMTP with a wrong
91
+ host is REJECTED at save time with the handshake error.
92
+ - With Brevo connected: the integration modal shows "Connected as …", the
93
+ transactional toggle flips `email_transport`, and "Send a test" delivers
94
+ through Brevo (check the Brevo → Transactional log).
95
+ - The history import runs to 100% with a progress bar, is resumable after
96
+ an interruption, and fires zero automations (historical flag).
97
+ - A store with `email_transport` unset sends exactly as before.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rovela-ai/sdk",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "description": "Rovela SDK - Pre-built e-commerce components for AI-powered store generation",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -320,6 +320,7 @@
320
320
  "lucide-react": "0.555.0",
321
321
  "nanoid": "5.1.6",
322
322
  "next-auth": "4.24.13",
323
+ "nodemailer": "7.0.13",
323
324
  "react-colorful": "^5.6.1",
324
325
  "recharts": "3.7.0",
325
326
  "resend": "6.9.1",
@@ -27,7 +27,7 @@ Usage: `nextjs_call` with `port="3000"` and `toolName="execute_sql"`
27
27
 
28
28
  | Table | Key Columns |
29
29
  |-------|-------------|
30
- | `products` | id, name, slug, price, status (`draft`/`active`/`archived`), categoryId, hasVariants, images (JSONB string[]), videos (JSONB string[]), metafields (JSONB key/label/value/type), translations (JSONB per-locale name/description) |
30
+ | `products` | id, name, slug, price, status (`draft`/`active`/`archived`), categoryId, hasVariants, images (JSONB string[]), videos (JSONB string[]), metafields (JSONB key/label/value/type), translations (JSONB per-locale name/description), taxClass (0.22.0 — names a rate in tax_zones.class_rates; NULL = zone base rate) |
31
31
  | `product_variants` | id, productId (CASCADE), sku, name, price, inventory, attributes (JSONB), image, video |
32
32
  | `categories` | id, name, slug, parentId (self-ref), order, translations (JSONB) |
33
33
  | `orders` | id, customerId, email, status, total, currency (ISO snapshot — display orders in THIS currency), refundAmount, returnReason, shippingAddress (JSONB) |
@@ -42,6 +42,8 @@ interface InvoiceOrder {
42
42
  total: number
43
43
  subtotal: number
44
44
  tax: number
45
+ /** Per-rate VAT ventilation (0.22.0) — cents; null/absent = flat tax line. */
46
+ taxBreakdown?: Array<{ rate: number; baseCents: number; taxCents: number }> | null
45
47
  shipping: number
46
48
  discountAmount?: number | string
47
49
  discountCode?: string | null
@@ -245,10 +247,23 @@ function InvoiceContent({ orderId }: { orderId: string }) {
245
247
  <span>{t('common.shipping')}</span>
246
248
  <span>{order.shipping > 0 ? formatPrice(order.shipping, orderCurrency) : t('common.free')}</span>
247
249
  </div>
248
- <div className="flex justify-between text-muted-foreground">
249
- <span>{t('common.tax')}</span>
250
- <span>{formatPrice(order.tax, orderCurrency)}</span>
251
- </div>
250
+ {order.taxBreakdown && order.taxBreakdown.length > 1 ? (
251
+ // Per-rate VAT ventilation (0.22.0) — the legally required French
252
+ // invoice breakdown ("dont TVA par taux").
253
+ order.taxBreakdown.map((entry) => (
254
+ <div key={entry.rate} className="flex justify-between text-muted-foreground">
255
+ <span>
256
+ {t('common.tax')} {entry.rate}%
257
+ </span>
258
+ <span>{formatPrice(entry.taxCents / 100, orderCurrency)}</span>
259
+ </div>
260
+ ))
261
+ ) : (
262
+ <div className="flex justify-between text-muted-foreground">
263
+ <span>{t('common.tax')}</span>
264
+ <span>{formatPrice(order.tax, orderCurrency)}</span>
265
+ </div>
266
+ )}
252
267
  <div className="flex justify-between border-t pt-2 text-base font-semibold text-foreground">
253
268
  <span>{t('common.total')}</span>
254
269
  <span>{formatPrice(order.total, orderCurrency)}</span>
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Email Sending Configuration Route
3
+ *
4
+ * GET /api/admin/emails/sending - Current transactional-email transport
5
+ * PUT /api/admin/emails/sending - Save it (SMTP handshake / Brevo verified-
6
+ * sender check run BEFORE persisting)
7
+ */
8
+
9
+ export { getEmailSending as GET, putEmailSending as PUT } from '@rovela-ai/sdk/admin/api'
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Brevo History Import Route
3
+ *
4
+ * POST /api/admin/integrations/brevo/backfill - One chunk of the resumable
5
+ * history import (contacts upsert, then orders with historical:true so no
6
+ * automation fires). The integrations modal loops on the returned cursor.
7
+ */
8
+
9
+ export { postBrevoBackfill as POST } from '@rovela-ai/sdk/admin/api'
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Brevo Integration Status Route
3
+ *
4
+ * GET /api/admin/integrations/brevo - Live Brevo status for the
5
+ * integrations modal (account identity, sender verification, whether the
6
+ * eCommerce module already holds orders, current email transport).
7
+ */
8
+
9
+ export { getBrevoStatus as GET } from '@rovela-ai/sdk/admin/api'
@@ -50,7 +50,10 @@ const nextConfig = {
50
50
  // the SDK's core/config get the file, and every other function (checkout,
51
51
  // webhooks, auth, admin emails) silently falls back to default styling.
52
52
  outputFileTracingIncludes: {
53
- '/**': ['./.rovela/blueprint.json'],
53
+ // nodemailer is loaded via a bundler-invisible require (the emails graph
54
+ // is client-reachable, a static import breaks the build) so the tracer
55
+ // can't see it — force-include it or the SMTP transport 500s on Vercel.
56
+ '/**': ['./.rovela/blueprint.json', './node_modules/nodemailer/**'],
54
57
  },
55
58
 
56
59
  // Image domains for Unsplash, CDNs, and R2 storage
@@ -9,13 +9,14 @@
9
9
  "lint": "eslint ."
10
10
  },
11
11
  "dependencies": {
12
- "@rovela-ai/sdk": "0.21.0",
12
+ "@rovela-ai/sdk": "0.23.0",
13
13
  "@tailwindcss/forms": "0.5.11",
14
14
  "@tailwindcss/typography": "0.5.19",
15
15
  "autoprefixer": "10.4.24",
16
16
  "lucide-react": "0.555.0",
17
17
  "next": "16.2.10",
18
18
  "next-auth": "4.24.13",
19
+ "nodemailer": "7.0.13",
19
20
  "postcss": "8.5.6",
20
21
  "react": "19.2.4",
21
22
  "react-dom": "19.2.4",