create-nextblock 0.12.8 → 0.12.11

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 (293) hide show
  1. package/docker-template/.dockerignore +23 -23
  2. package/docker-template/.env.docker.example +69 -69
  3. package/docker-template/docker/db/init/99-jwt.sql +6 -6
  4. package/docker-template/docker/db/init/99-roles.sql +25 -25
  5. package/docker-template/docker/kong/kong.yml +112 -112
  6. package/docker-template/scripts/docker-setup.mjs +310 -310
  7. package/libs/db/tsconfig.lib.json +3 -3
  8. package/libs/editor/tsconfig.lib.json +3 -3
  9. package/libs/ui/tsconfig.lib.json +3 -3
  10. package/libs/utils/tsconfig.json +3 -3
  11. package/package.json +1 -1
  12. package/project.json +19 -19
  13. package/templates/nextblock-template/.browserslistrc +11 -11
  14. package/templates/nextblock-template/.dockerignore +23 -23
  15. package/templates/nextblock-template/README.md +34 -34
  16. package/templates/nextblock-template/app/(auth-pages)/layout.tsx +9 -9
  17. package/templates/nextblock-template/app/(auth-pages)/post-sign-in/page.tsx +27 -27
  18. package/templates/nextblock-template/app/(auth-pages)/sign-up/SignUpForm.tsx +141 -141
  19. package/templates/nextblock-template/app/(auth-pages)/sign-up/page.tsx +46 -46
  20. package/templates/nextblock-template/app/(auth-pages)/two-factor/actions.ts +91 -91
  21. package/templates/nextblock-template/app/(auth-pages)/two-factor/components/TwoFactorForm.tsx +123 -123
  22. package/templates/nextblock-template/app/(auth-pages)/two-factor/page.tsx +51 -51
  23. package/templates/nextblock-template/app/ToasterProvider.tsx +17 -17
  24. package/templates/nextblock-template/app/[slug]/pageClientActions.ts +7 -7
  25. package/templates/nextblock-template/app/actions/consent.ts +57 -57
  26. package/templates/nextblock-template/app/actions/interactions.test.ts +301 -301
  27. package/templates/nextblock-template/app/actions/interactions.ts +373 -373
  28. package/templates/nextblock-template/app/actions/postActions.ts +146 -146
  29. package/templates/nextblock-template/app/actions/twoFactorEmail.ts +22 -22
  30. package/templates/nextblock-template/app/api/ai/cortex/build-widget/route.ts +153 -153
  31. package/templates/nextblock-template/app/api/ai/generate-blocks/route.ts +96 -96
  32. package/templates/nextblock-template/app/api/ai/global-agent/route.ts +964 -964
  33. package/templates/nextblock-template/app/api/brand/email-logo/route.ts +48 -48
  34. package/templates/nextblock-template/app/api/cms/check-updates/route.ts +44 -44
  35. package/templates/nextblock-template/app/api/cms/full-backup/export/route.ts +33 -33
  36. package/templates/nextblock-template/app/api/cms/full-backup/restore/route.ts +63 -63
  37. package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +3490 -3490
  38. package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +5597 -5597
  39. package/templates/nextblock-template/app/api/cron/sync-currencies/route.ts +39 -39
  40. package/templates/nextblock-template/app/api/custom-blocks/db-relations/route.ts +92 -92
  41. package/templates/nextblock-template/app/api/custom-blocks/editor-definitions/route.ts +43 -43
  42. package/templates/nextblock-template/app/api/media/library/route.ts +69 -69
  43. package/templates/nextblock-template/app/api/media/r2-presigned/route.ts +53 -53
  44. package/templates/nextblock-template/app/api/media/record/route.ts +160 -160
  45. package/templates/nextblock-template/app/api/search/route.ts +43 -43
  46. package/templates/nextblock-template/app/article/[slug]/PostClientContent.tsx +441 -441
  47. package/templates/nextblock-template/app/auth/callback/route.ts +31 -31
  48. package/templates/nextblock-template/app/cart/page.tsx +7 -7
  49. package/templates/nextblock-template/app/cms/blocks/components/CustomBlockEditorPreview.tsx +160 -160
  50. package/templates/nextblock-template/app/cms/blocks/components/MediaLibraryModal.tsx +149 -149
  51. package/templates/nextblock-template/app/cms/blocks/editors/DynamicCustomBlockEditor.tsx +167 -167
  52. package/templates/nextblock-template/app/cms/blocks/editors/ImageBlockEditor.tsx +29 -29
  53. package/templates/nextblock-template/app/cms/blocks/editors/TextBlockEditor.tsx +90 -90
  54. package/templates/nextblock-template/app/cms/components/ConnectGitHubButton.tsx +122 -122
  55. package/templates/nextblock-template/app/cms/components/CortexAiPageContext.tsx +58 -58
  56. package/templates/nextblock-template/app/cms/components/FeatureImageField.tsx +244 -244
  57. package/templates/nextblock-template/app/cms/components/FeedbackModal.tsx +36 -36
  58. package/templates/nextblock-template/app/cms/components/SystemAlertsBanner.tsx +112 -112
  59. package/templates/nextblock-template/app/cms/components/TwoFactorReminderBanner.tsx +45 -45
  60. package/templates/nextblock-template/app/cms/components/github-connect-actions.ts +102 -102
  61. package/templates/nextblock-template/app/cms/components/system-alerts-actions.ts +31 -31
  62. package/templates/nextblock-template/app/cms/custom-blocks/[id]/edit/page.tsx +66 -66
  63. package/templates/nextblock-template/app/cms/custom-blocks/actions.ts +519 -519
  64. package/templates/nextblock-template/app/cms/custom-blocks/components/BlockComposer.tsx +1522 -1522
  65. package/templates/nextblock-template/app/cms/custom-blocks/components/BlocksLibraryTransferControls.tsx +256 -256
  66. package/templates/nextblock-template/app/cms/custom-blocks/components/DBRelationSelect.tsx +384 -384
  67. package/templates/nextblock-template/app/cms/custom-blocks/components/ImageR2Picker.tsx +221 -221
  68. package/templates/nextblock-template/app/cms/custom-blocks/new/page.tsx +12 -12
  69. package/templates/nextblock-template/app/cms/custom-blocks/page.tsx +438 -438
  70. package/templates/nextblock-template/app/cms/dashboard/actions.ts +228 -228
  71. package/templates/nextblock-template/app/cms/dashboard/components/DashboardOnboarding.tsx +130 -130
  72. package/templates/nextblock-template/app/cms/import-export/ContentTransferControls.tsx +431 -391
  73. package/templates/nextblock-template/app/cms/import-export/actions.ts +226 -226
  74. package/templates/nextblock-template/app/cms/interactions/InteractionsModerationClient.tsx +408 -408
  75. package/templates/nextblock-template/app/cms/interactions/page.tsx +51 -51
  76. package/templates/nextblock-template/app/cms/layout.tsx +73 -73
  77. package/templates/nextblock-template/app/cms/media/components/FolderNavigator.tsx +273 -273
  78. package/templates/nextblock-template/app/cms/media/components/FolderTree.tsx +122 -122
  79. package/templates/nextblock-template/app/cms/media/components/MediaEditForm.tsx +26 -26
  80. package/templates/nextblock-template/app/cms/media/components/MediaGridClient.tsx +69 -69
  81. package/templates/nextblock-template/app/cms/media/components/MediaPickerDialog.tsx +149 -149
  82. package/templates/nextblock-template/app/cms/media/components/MediaUploadForm.tsx +101 -101
  83. package/templates/nextblock-template/app/cms/navigation/components/NavigationMenuDnd.tsx +3 -3
  84. package/templates/nextblock-template/app/cms/pages/page.tsx +18 -17
  85. package/templates/nextblock-template/app/cms/posts/page.tsx +19 -18
  86. package/templates/nextblock-template/app/cms/products/attributes/page.tsx +12 -12
  87. package/templates/nextblock-template/app/cms/products/categories/page.tsx +12 -12
  88. package/templates/nextblock-template/app/cms/products/inventory/page.tsx +13 -13
  89. package/templates/nextblock-template/app/cms/products/new/page.tsx +135 -135
  90. package/templates/nextblock-template/app/cms/products/page.tsx +39 -27
  91. package/templates/nextblock-template/app/cms/products/productFormData.ts +133 -133
  92. package/templates/nextblock-template/app/cms/products/settings/page.tsx +5 -5
  93. package/templates/nextblock-template/app/cms/promotions/PromotionsWorkspace.tsx +456 -456
  94. package/templates/nextblock-template/app/cms/promotions/actions.ts +115 -115
  95. package/templates/nextblock-template/app/cms/promotions/page.tsx +31 -31
  96. package/templates/nextblock-template/app/cms/revisions/service.ts +19 -19
  97. package/templates/nextblock-template/app/cms/revisions/utils.ts +132 -132
  98. package/templates/nextblock-template/app/cms/settings/backup-restore/BackupRestoreWorkspace.tsx +1004 -1004
  99. package/templates/nextblock-template/app/cms/settings/backup-restore/page.tsx +29 -29
  100. package/templates/nextblock-template/app/cms/settings/bot-protection/actions.ts +93 -93
  101. package/templates/nextblock-template/app/cms/settings/bot-protection/components/BotProtectionForm.tsx +129 -129
  102. package/templates/nextblock-template/app/cms/settings/bot-protection/page.tsx +24 -24
  103. package/templates/nextblock-template/app/cms/settings/cortex-ai/SandboxCortexAiSettingsClient.tsx +497 -497
  104. package/templates/nextblock-template/app/cms/settings/cortex-ai/StoredCortexAiSettingsClient.tsx +410 -410
  105. package/templates/nextblock-template/app/cms/settings/cortex-ai/actions.ts +246 -246
  106. package/templates/nextblock-template/app/cms/settings/cortex-ai/page.tsx +80 -80
  107. package/templates/nextblock-template/app/cms/settings/currencies/actions.ts +331 -331
  108. package/templates/nextblock-template/app/cms/settings/currencies/page.tsx +494 -494
  109. package/templates/nextblock-template/app/cms/settings/email/actions.ts +64 -64
  110. package/templates/nextblock-template/app/cms/settings/email/components/EmailForm.tsx +181 -181
  111. package/templates/nextblock-template/app/cms/settings/email/page.tsx +28 -28
  112. package/templates/nextblock-template/app/cms/settings/extra-translations/ExtraTranslationsWorkspace.tsx +767 -767
  113. package/templates/nextblock-template/app/cms/settings/extra-translations/page.tsx +93 -93
  114. package/templates/nextblock-template/app/cms/settings/google-analytics/actions.ts +60 -60
  115. package/templates/nextblock-template/app/cms/settings/google-analytics/components/GoogleAnalyticsForm.tsx +129 -129
  116. package/templates/nextblock-template/app/cms/settings/google-analytics/page.tsx +26 -26
  117. package/templates/nextblock-template/app/cms/settings/languages/actions.ts +16 -16
  118. package/templates/nextblock-template/app/cms/settings/logos/[id]/edit/page.tsx +7 -7
  119. package/templates/nextblock-template/app/cms/settings/logos/components/BrandingSettingsForm.tsx +339 -339
  120. package/templates/nextblock-template/app/cms/settings/logos/components/DeleteLogoButton.tsx +21 -21
  121. package/templates/nextblock-template/app/cms/settings/logos/components/LogoForm.tsx +20 -20
  122. package/templates/nextblock-template/app/cms/settings/logos/components/SetActiveLogoButton.tsx +42 -42
  123. package/templates/nextblock-template/app/cms/settings/logos/components/SiteSeoSettingsForm.tsx +133 -133
  124. package/templates/nextblock-template/app/cms/settings/logos/new/page.tsx +8 -8
  125. package/templates/nextblock-template/app/cms/settings/packages/package-card.tsx +122 -122
  126. package/templates/nextblock-template/app/cms/settings/privacy/actions.ts +52 -52
  127. package/templates/nextblock-template/app/cms/settings/privacy/components/PrivacyForm.tsx +148 -148
  128. package/templates/nextblock-template/app/cms/settings/privacy/page.tsx +27 -27
  129. package/templates/nextblock-template/app/cms/settings/registration/actions.ts +44 -44
  130. package/templates/nextblock-template/app/cms/settings/registration/components/RegistrationForm.tsx +65 -65
  131. package/templates/nextblock-template/app/cms/settings/registration/page.tsx +27 -27
  132. package/templates/nextblock-template/app/cms/settings/security/actions.ts +284 -284
  133. package/templates/nextblock-template/app/cms/settings/security/components/SecurityPanel.tsx +522 -522
  134. package/templates/nextblock-template/app/cms/settings/security/page.tsx +33 -33
  135. package/templates/nextblock-template/app/cms/settings/taxes/page.tsx +21 -21
  136. package/templates/nextblock-template/app/cms/shipping/page.tsx +20 -20
  137. package/templates/nextblock-template/app/cms/users/actions.ts +222 -222
  138. package/templates/nextblock-template/app/cms/users/components/DeleteUserButton.tsx +12 -12
  139. package/templates/nextblock-template/app/cms/users/components/UserForm.tsx +44 -44
  140. package/templates/nextblock-template/app/lib/site-settings.ts +105 -105
  141. package/templates/nextblock-template/app/lib/sitemap-utils.ts +253 -253
  142. package/templates/nextblock-template/app/profile/ProfileAccountSidebar.tsx +73 -73
  143. package/templates/nextblock-template/app/profile/ProfilePageHeader.tsx +16 -16
  144. package/templates/nextblock-template/app/profile/ProfilePageMissingState.tsx +9 -9
  145. package/templates/nextblock-template/app/profile/account-data.ts +37 -37
  146. package/templates/nextblock-template/app/profile/account-links.ts +22 -22
  147. package/templates/nextblock-template/app/profile/account-types.ts +11 -11
  148. package/templates/nextblock-template/app/profile/orders/CustomerOrdersPageClient.tsx +124 -124
  149. package/templates/nextblock-template/app/profile/orders/[id]/CustomerOrderDetailPageClient.tsx +79 -79
  150. package/templates/nextblock-template/app/profile/orders/[id]/page.tsx +32 -32
  151. package/templates/nextblock-template/app/profile/orders/page.tsx +19 -19
  152. package/templates/nextblock-template/app/profile/page.tsx +42 -42
  153. package/templates/nextblock-template/app/profile/password/PasswordSettingsPageClient.tsx +128 -128
  154. package/templates/nextblock-template/app/profile/password/actions.ts +59 -59
  155. package/templates/nextblock-template/app/profile/password/page.tsx +27 -27
  156. package/templates/nextblock-template/app/setup/SetupWizard.tsx +678 -678
  157. package/templates/nextblock-template/app/setup/layout.tsx +13 -13
  158. package/templates/nextblock-template/app/setup/page.tsx +111 -111
  159. package/templates/nextblock-template/app/sitemap.ts +130 -130
  160. package/templates/nextblock-template/components/CartDrawerLoader.tsx +7 -7
  161. package/templates/nextblock-template/components/DeferredCartDrawer.tsx +23 -23
  162. package/templates/nextblock-template/components/DeferredGoogleAnalytics.tsx +70 -70
  163. package/templates/nextblock-template/components/DeferredGoogleTagManager.tsx +70 -70
  164. package/templates/nextblock-template/components/DeferredSpeedInsights.tsx +69 -69
  165. package/templates/nextblock-template/components/FeatureImageHero.tsx +47 -47
  166. package/templates/nextblock-template/components/FooterNavigation.tsx +32 -32
  167. package/templates/nextblock-template/components/GitHubLoginButton.tsx +15 -15
  168. package/templates/nextblock-template/components/HtmlScriptExecutor.tsx +47 -47
  169. package/templates/nextblock-template/components/LanguageSwitcher.tsx +2 -2
  170. package/templates/nextblock-template/components/PostCommentsSection.tsx +369 -369
  171. package/templates/nextblock-template/components/ProductReviewsSection.tsx +419 -419
  172. package/templates/nextblock-template/components/PublicEnvBootstrap.tsx +30 -30
  173. package/templates/nextblock-template/components/ResponsiveNav.tsx +14 -14
  174. package/templates/nextblock-template/components/auth/AuthBotProtection.tsx +182 -182
  175. package/templates/nextblock-template/components/blocks/PostCardSkeleton.tsx +12 -12
  176. package/templates/nextblock-template/components/blocks/PostsGridBlock.tsx +12 -12
  177. package/templates/nextblock-template/components/blocks/ecommerceRendererLoaders.ts +23 -23
  178. package/templates/nextblock-template/components/blocks/renderers/FormBlockRenderer.tsx +249 -249
  179. package/templates/nextblock-template/components/blocks/types.ts +7 -7
  180. package/templates/nextblock-template/components/env-var-warning.tsx +3 -3
  181. package/templates/nextblock-template/components/form-message.tsx +32 -32
  182. package/templates/nextblock-template/components/privacy/ConsentBanner.tsx +170 -170
  183. package/templates/nextblock-template/components/privacy/ConsentGatedAnalytics.tsx +70 -70
  184. package/templates/nextblock-template/components/renderers/CachedDynamicLayoutEngine.tsx +28 -28
  185. package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.test.tsx +166 -166
  186. package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.tsx +464 -464
  187. package/templates/nextblock-template/components/submit-button.tsx +23 -23
  188. package/templates/nextblock-template/components/theme-switcher.tsx +8 -8
  189. package/templates/nextblock-template/components/visual-editing/DeferredVisualEditing.tsx +21 -21
  190. package/templates/nextblock-template/context/AuthContext.tsx +23 -23
  191. package/templates/nextblock-template/context/LanguageContext.tsx +16 -16
  192. package/templates/nextblock-template/context/language-rest-client.ts +32 -32
  193. package/templates/nextblock-template/docker/db/init/99-jwt.sql +6 -6
  194. package/templates/nextblock-template/docker/db/init/99-roles.sql +25 -25
  195. package/templates/nextblock-template/docker/kong/kong.yml +112 -112
  196. package/templates/nextblock-template/docs/01-PROJECT-OVERVIEW.md +94 -94
  197. package/templates/nextblock-template/docs/02-ECOMMERCE-CAPABILITIES.md +364 -364
  198. package/templates/nextblock-template/docs/03-CMS-AND-EDITOR.md +202 -202
  199. package/templates/nextblock-template/docs/04-DATABASE-AND-AUTH.md +246 -246
  200. package/templates/nextblock-template/docs/06-CLI-AND-SCAFFOLDING.md +176 -176
  201. package/templates/nextblock-template/docs/07-BLOCK-SDK-AND-EXTENSIBILITY.md +146 -146
  202. package/templates/nextblock-template/docs/08-NEXTBLOCK-CORTEX-AI-ARCHITECTURE.md +1319 -1319
  203. package/templates/nextblock-template/docs/10-CUSTOM-BLOCKS.md +222 -222
  204. package/templates/nextblock-template/docs/11-SELF-HOSTED-DOCKER.md +173 -173
  205. package/templates/nextblock-template/docs/12-VERCEL-DEPLOYMENT.md +170 -170
  206. package/templates/nextblock-template/docs/13-STAYING-UP-TO-DATE.md +151 -151
  207. package/templates/nextblock-template/docs/README.md +39 -39
  208. package/templates/nextblock-template/docs/TECHNICAL_SPECIFICATION.md +12505 -12505
  209. package/templates/nextblock-template/hooks/use-hotkeys.ts +21 -21
  210. package/templates/nextblock-template/hooks/useGlobalSearch.ts +101 -101
  211. package/templates/nextblock-template/index.d.ts +7 -7
  212. package/templates/nextblock-template/lib/app-secrets.ts +39 -39
  213. package/templates/nextblock-template/lib/auth/cookies.ts +47 -47
  214. package/templates/nextblock-template/lib/auth/crypto.ts +45 -45
  215. package/templates/nextblock-template/lib/auth/trustedDevices.ts +92 -92
  216. package/templates/nextblock-template/lib/auth/twoFactor.ts +208 -208
  217. package/templates/nextblock-template/lib/auth-redirects.ts +46 -46
  218. package/templates/nextblock-template/lib/blocks/README.md +13 -13
  219. package/templates/nextblock-template/lib/blocks/blockRegistry.ts +6 -6
  220. package/templates/nextblock-template/lib/blocks/blockTypes.ts +18 -18
  221. package/templates/nextblock-template/lib/botProtection/verify.ts +134 -134
  222. package/templates/nextblock-template/lib/cms-transfer/csv.test.ts +100 -77
  223. package/templates/nextblock-template/lib/cms-transfer/csv.ts +403 -399
  224. package/templates/nextblock-template/lib/cms-transfer/server.ts +2243 -2243
  225. package/templates/nextblock-template/lib/cms-transfer/types.ts +145 -145
  226. package/templates/nextblock-template/lib/config/email-settings.ts +217 -217
  227. package/templates/nextblock-template/lib/custom-block-definitions.ts +87 -87
  228. package/templates/nextblock-template/lib/custom-block-r2-upload-shared.ts +178 -178
  229. package/templates/nextblock-template/lib/custom-block-r2-upload.test.ts +140 -140
  230. package/templates/nextblock-template/lib/custom-block-r2-upload.ts +88 -88
  231. package/templates/nextblock-template/lib/custom-block-relation-registry.ts +256 -256
  232. package/templates/nextblock-template/lib/custom-block-relations.test.ts +227 -227
  233. package/templates/nextblock-template/lib/custom-block-relations.ts +279 -279
  234. package/templates/nextblock-template/lib/custom-block-safelist.ts +14 -14
  235. package/templates/nextblock-template/lib/editor/dynamic-extension-core.test.ts +172 -172
  236. package/templates/nextblock-template/lib/editor/dynamic-extension-core.ts +213 -213
  237. package/templates/nextblock-template/lib/editor/dynamic-extension-loader.ts +22 -22
  238. package/templates/nextblock-template/lib/editor/dynamic-extensions.tsx +193 -193
  239. package/templates/nextblock-template/lib/email/branding-format.test.ts +133 -133
  240. package/templates/nextblock-template/lib/email/branding-format.ts +123 -123
  241. package/templates/nextblock-template/lib/email/branding.ts +76 -76
  242. package/templates/nextblock-template/lib/full-backup/manifest.test.ts +121 -121
  243. package/templates/nextblock-template/lib/full-backup/manifest.ts +206 -206
  244. package/templates/nextblock-template/lib/full-backup/server.ts +743 -743
  245. package/templates/nextblock-template/lib/logos/active-logo.ts +53 -53
  246. package/templates/nextblock-template/lib/media/resolveMediaUrl.ts +54 -54
  247. package/templates/nextblock-template/lib/onboarding/actions.ts +31 -31
  248. package/templates/nextblock-template/lib/onboarding/status.ts +222 -222
  249. package/templates/nextblock-template/lib/posts/readTime.ts +60 -60
  250. package/templates/nextblock-template/lib/privacy/consent-client.ts +57 -57
  251. package/templates/nextblock-template/lib/privacy/contact-emails.ts +64 -64
  252. package/templates/nextblock-template/lib/privacy/settings.ts +115 -115
  253. package/templates/nextblock-template/lib/privacy/types.ts +69 -69
  254. package/templates/nextblock-template/lib/promotions/server.test.ts +74 -74
  255. package/templates/nextblock-template/lib/promotions/server.ts +741 -741
  256. package/templates/nextblock-template/lib/resolve-block-relations.test.ts +142 -142
  257. package/templates/nextblock-template/lib/resolve-block-relations.ts +255 -255
  258. package/templates/nextblock-template/lib/search/server.ts +585 -585
  259. package/templates/nextblock-template/lib/search/types.ts +27 -27
  260. package/templates/nextblock-template/lib/setup/actions.ts +460 -460
  261. package/templates/nextblock-template/lib/setup/env-status.ts +125 -125
  262. package/templates/nextblock-template/lib/setup/env-write.ts +111 -111
  263. package/templates/nextblock-template/lib/setup/migrations-bundle.ts +37 -37
  264. package/templates/nextblock-template/lib/setup/provisioning.ts +59 -59
  265. package/templates/nextblock-template/lib/setup/schema-apply.ts +408 -408
  266. package/templates/nextblock-template/lib/setup/system-config.ts +105 -105
  267. package/templates/nextblock-template/lib/setup/types.ts +18 -18
  268. package/templates/nextblock-template/lib/site-url.ts +48 -48
  269. package/templates/nextblock-template/lib/storage/provider.ts +66 -66
  270. package/templates/nextblock-template/lib/storage/supabase-storage.ts +103 -103
  271. package/templates/nextblock-template/lib/updates/check-upstream.ts +441 -441
  272. package/templates/nextblock-template/lib/updates/github-device.ts +206 -206
  273. package/templates/nextblock-template/lib/updates/repo-identity.ts +56 -56
  274. package/templates/nextblock-template/next.config.js +6 -0
  275. package/templates/nextblock-template/package.json +1 -1
  276. package/templates/nextblock-template/postcss.config.js +6 -6
  277. package/templates/nextblock-template/scripts/backup.js +115 -115
  278. package/templates/nextblock-template/scripts/docker-setup.mjs +310 -310
  279. package/templates/nextblock-template/scripts/restore.js +385 -385
  280. package/templates/nextblock-template/scripts/verify-cortex-ai-build-widget.tsx +98 -98
  281. package/templates/nextblock-template/scripts/verify-cortex-ai-generate-blocks.ts +62 -62
  282. package/templates/nextblock-template/scripts/verify-cortex-ai-global-tools.ts +537 -537
  283. package/templates/nextblock-template/scripts/verify-cortex-ai-routing.ts +58 -58
  284. package/templates/nextblock-template/scripts/verify-custom-block-definitions.ts +188 -188
  285. package/templates/nextblock-template/scripts/verify-dynamic-custom-block-extensions.ts +123 -123
  286. package/templates/nextblock-template/scripts/verify-dynamic-layout-engine.tsx +133 -133
  287. package/templates/nextblock-template/scripts/verify-milestone-2-custom-blocks.ts +65 -65
  288. package/templates/nextblock-template/tailwind.config.js +25 -25
  289. package/templates/nextblock-template/tools/build-migrate.mjs +209 -209
  290. package/templates/nextblock-template/tools/configure-supabase-auth.js +282 -282
  291. package/templates/nextblock-template/types/jsdom.d.ts +6 -6
  292. package/tsconfig.base.json +3 -3
  293. package/templates/nextblock-template/tsconfig.tsbuildinfo +0 -1
@@ -1,364 +1,364 @@
1
- # 02 Ecommerce Capabilities
2
-
3
- ## Scope and Source of Truth
4
-
5
- The commerce feature set is implemented across:
6
-
7
- - `libs/ecommerce/src/lib/*`
8
- - `libs/db/src/supabase/migrations/00000000000003` through `00000000000006`
9
- - `apps/nextblock/app/api/checkout/route.ts`
10
- - `apps/nextblock/app/api/webhooks/*`
11
- - `apps/nextblock/app/cms/products`, `orders`, `shipping`, `payments`, and
12
- `settings/taxes`
13
-
14
- In workspace code, the developer-facing import paths are:
15
-
16
- - `@nextblock-cms/ecommerce`
17
- - `@nextblock-cms/ecommerce/server`
18
- - `@nextblock-cms/ecommerce/actions`
19
-
20
- One packaging discrepancy exists today: `libs/ecommerce/package.json` is still
21
- named `@nextblock-cms/ecom`, while the workspace and CLI activation flow expose
22
- the package through the `@nextblock-cms/ecommerce` alias.
23
-
24
- ## Commerce Data Model
25
-
26
- The commerce schema spans:
27
-
28
- - Catalog: `products`, `product_media`, `product_attributes`,
29
- `product_attribute_terms`, `product_variants`,
30
- `variant_attribute_mapping`, `categories`, `product_categories`
31
- (categories and their translations were added by migrations
32
- `00000000000019` and `00000000000020`)
33
- - Inventory and licensing: `inventory_items`, `package_activations`,
34
- `freemius_plans`, `freemius_pricing`
35
- - Checkout and fulfillment: `orders`, `order_items`, `shipping_zones`,
36
- `shipping_zone_locations`, `shipping_zone_methods`, `tax_rates`,
37
- `currencies`
38
-
39
- `products` can be physical or digital. The current provider selection logic
40
- resolves:
41
-
42
- - physical -> Stripe
43
- - digital -> Freemius
44
-
45
- Mixed-provider carts are rejected by `app/api/checkout/route.ts`.
46
-
47
- ## Multi-Currency
48
-
49
- The multi-currency implementation is real and fairly deep.
50
-
51
- ### Store currencies
52
-
53
- `currencies` stores:
54
-
55
- - ISO code and symbol
56
- - exchange rate relative to the current store default
57
- - default and active flags
58
- - rounding mode, rounding increment, and optional charm ending
59
- - automatic FX refresh flag
60
- - automatic product price sync flag
61
- - last exchange-rate source and refresh timestamp
62
-
63
- Supported rounding modes in code are:
64
-
65
- - `none`
66
- - `nearest`
67
- - `up`
68
- - `down`
69
- - `charm`
70
-
71
- ### Product and variant pricing
72
-
73
- Products and variants support:
74
-
75
- - legacy single-currency `price` and `sale_price`
76
- - multi-currency `prices` and `sale_prices`
77
-
78
- The pricing helpers resolve amounts by:
79
-
80
- 1. looking for an explicit amount in the selected currency
81
- 2. falling back to the base price
82
- 3. converting from the default currency when store-managed auto-sync pricing is
83
- enabled
84
-
85
- The CMS product editor respects that distinction. Store-managed currencies can
86
- be displayed in forms, but their saved overrides are stripped before
87
- persisting.
88
-
89
- ### Scheduled sales, price changes, and promotions
90
-
91
- Products and variants carry a scheduled-pricing layer (migration
92
- `00000000000025_add_sale_schedule_columns.sql`):
93
-
94
- - `sale_start_at` / `sale_end_at` — the time window during which `sale_price` /
95
- `sale_prices` apply. Both null = always-on (back-compat with static sales).
96
- - `scheduled_price` / `scheduled_prices` / `scheduled_price_at` — a pending,
97
- permanent regular-price change applied once `scheduled_price_at` passes
98
- (bulk/Stripe-oriented; Freemius regular prices are owned by Freemius).
99
- - `product_freemius_sale_coupons` — maps a product to an auto-generated,
100
- time-bounded Freemius coupon so a scheduled Freemius sale is actually enforced
101
- at Freemius-hosted checkout (Freemius enforces the coupon's start/end dates).
102
-
103
- **Enforcement is read-time, not cron-driven.** The helpers in
104
- `libs/ecommerce/src/lib/currency.ts` decide what applies *now*:
105
-
106
- - `isSaleWindowActive({ saleStartAt, saleEndAt, now })`
107
- - `resolveEffectivePriceForCurrency({ ..., saleStartAt, saleEndAt, scheduledPrice*, now })`
108
- — wraps `resolvePriceForCurrency`, gating the sale by its window and swapping in
109
- a due scheduled price. A sale outside its window resolves to `sale_price: null`.
110
-
111
- Every place that computes a payable or displayed amount goes through the
112
- window-aware helper: checkout providers (`providers/stripe.ts`,
113
- `providers/freemius.ts`), cart/tax/coupon math, and storefront components
114
- (`ProductCard`, `FeaturedProduct`, `ProductDetailsLayout`, UCP). The CMS edit
115
- form exposes the window per-product and per-variant (`SaleScheduleFields`); the
116
- bulk **Promotions** admin (`/cms/promotions`, `apps/nextblock/lib/promotions/`)
117
- imports/exports sales and price changes via CSV.
118
-
119
- > **Gotchas for future agents (these caused real revert/display bugs):**
120
- >
121
- > 1. **`generateVariantDrafts` (`variation-utils.ts`) must carry over every
122
- > per-variant field**, including `sale_start_at`/`sale_end_at`. It re-runs on
123
- > editor mount/attribute change; an omitted field resets to null and is then
124
- > autosaved away ("dates revert after publish").
125
- > 2. **Storefront block mappers must pass the window through** on *both* the
126
- > product and each variant — `ProductGridBlock`, `FeaturedProductBlock`,
127
- > `app/product/[slug]/page.tsx`. If the window is dropped, `isSaleWindowActive`
128
- > sees both bounds null and treats the sale as always-on, so an inactive sale
129
- > price shows (e.g. a "$25 – $32" range before the sale starts).
130
- > 3. **`getVariantEffectivePriceRange` is window-aware** — pass
131
- > `sale_start_at`/`sale_end_at` per variant or it ignores the schedule.
132
- > 4. **Persisting on save/publish does not rely on the RPC.** Products are
133
- > written via `upsert_product_with_variants`, but some databases run a stale
134
- > copy of that function. `persistProductSaleSchedule` (`product-actions.ts`)
135
- > writes the window columns with a direct `update` right after the RPC (same
136
- > pattern as `persistProductTaxability`), matching variants by SKU.
137
- > 5. **Autosave must not `reset()` the form or revalidate the edit route.** The
138
- > edit-form autosave (`ProductForm.tsx`) uses a serialized-snapshot guard to
139
- > avoid a render loop; `updateProductAction` writes only the draft (no
140
- > `revalidatePath`). Re-rendering mid-edit resets native datetime inputs.
141
-
142
- ### FX sync and rebasing
143
-
144
- `libs/ecommerce/src/lib/currency-sync.ts` implements two separate operations:
145
-
146
- - `syncStoreCurrencyRates()`: pulls fresh FX rates from `https://api.frankfurter.dev`
147
- unless `FX_API_BASE_URL` overrides the provider.
148
- - `rebaseStoreCurrencyExchangeRates()`: when an admin changes the default
149
- currency, every stored rate is rebased so the new default becomes `1`.
150
-
151
- The app exposes both through:
152
-
153
- - CMS currency settings actions in
154
- `apps/nextblock/app/cms/settings/currencies/actions.ts`
155
- - `GET /api/cron/sync-currencies`, guarded by `CRON_SECRET`
156
-
157
- ## Tax Calculation
158
-
159
- Tax behavior is driven by the `ecommerce_inventory_settings` site setting,
160
- loaded through `getEcommerceInventorySettings()`.
161
-
162
- The current settings shape is:
163
-
164
- - `trackQuantities`
165
- - `enableTaxes`
166
- - `taxCalculationMode`
167
-
168
- Supported tax modes are:
169
-
170
- - `manual`
171
- - `automatic`
172
-
173
- ### Manual mode
174
-
175
- Manual mode uses `tax_rates` rows keyed by country and optional state/province.
176
- Multiple rows can exist for the same jurisdiction, so stacked taxes such as GST
177
- plus PST are supported.
178
-
179
- During checkout:
180
-
181
- - only taxable products are included
182
- - the destination is normalized from shipping or billing data
183
- - matching `tax_rates` are loaded
184
- - tax lines are calculated and stored in `orders.tax_details`
185
-
186
- ### Automatic mode
187
-
188
- Automatic mode defers final tax calculation to Stripe Tax.
189
-
190
- In this mode:
191
-
192
- - checkout still records a tax intent in `orders.tax_details`
193
- - the Stripe provider marks product and shipping tax codes on line items
194
- - the webhook resync step replaces provisional tax data with finalized Stripe
195
- checkout data
196
-
197
- ## Shipping Zones and Rate Resolution
198
-
199
- Shipping is backed by:
200
-
201
- - `shipping_zones`
202
- - `shipping_zone_locations`
203
- - `shipping_zone_methods`
204
-
205
- Each method stores:
206
-
207
- - base amount and currency
208
- - localized names
209
- - per-currency amount maps and threshold maps
210
- - `currency_pricing_mode` of `auto` or `manual`
211
-
212
- ### Current resolver behavior
213
-
214
- `libs/ecommerce/src/lib/shipping/resolver.ts` currently:
215
-
216
- 1. loads active currencies
217
- 2. queries zone locations by destination country
218
- 3. prefers a state match when one exists
219
- 4. otherwise prefers a country-wide match
220
- 5. otherwise falls back to the first zone by `priority_order`
221
- 6. filters methods by the cart total and minimum threshold
222
- 7. converts method prices into the shopper currency
223
- 8. returns only the cheapest valid method
224
-
225
- Important implementation detail: `shipping_zone_locations.postal_code` exists in
226
- schema, but the current resolver does not yet use postal code matching during
227
- runtime resolution.
228
-
229
- The storefront calls this through
230
- `libs/ecommerce/src/lib/server-actions/shipping-actions.ts`.
231
-
232
- ## Stripe Integration
233
-
234
- Stripe is the current payment flow for physical products.
235
-
236
- ### Checkout flow
237
-
238
- `app/api/checkout/route.ts`:
239
-
240
- - verifies the ecommerce package is active
241
- - rejects carts without provider-aware items
242
- - rejects mixed-provider carts
243
- - requires a billing address
244
- - resolves the provider through `getPaymentProvider()`
245
-
246
- `StripeProvider.createCheckoutSession()` then:
247
-
248
- - loads currencies and store settings
249
- - validates products and variants against the database
250
- - validates inventory before session creation when quantity tracking is enabled
251
- - resolves shipping cost from the selected shipping method
252
- - calculates tax in manual or automatic mode
253
- - upserts a Stripe customer when an email is available
254
- - inserts a pending `orders` row plus `order_items`
255
- - stores currency, subtotal, shipping, tax, and exchange-rate data
256
- - creates the Stripe Checkout Session and stores `stripe_session_id`
257
-
258
- ### Webhook flow
259
-
260
- `app/api/webhooks/stripe/route.ts` passes the raw body to
261
- `handleStripeWebhook()`.
262
-
263
- On `checkout.session.completed`, the sync layer:
264
-
265
- - reloads the session with tax breakdown details
266
- - finds the existing order
267
- - stores payment intent, customer details, and finalized totals
268
- - normalizes tax details from Stripe
269
- - updates saved customer addresses
270
- - assigns invoice metadata
271
- - applies inventory deduction
272
-
273
- ## Freemius Licensing and Product Sync
274
-
275
- Freemius currently handles digital-product checkout and product synchronization.
276
-
277
- ### Checkout behavior
278
-
279
- `FreemiusProvider.createCheckoutSession()`:
280
-
281
- - only allows one item per checkout
282
- - loads the product from Supabase
283
- - requires `freemius_product_id` and `freemius_plan_id`
284
- - resolves pricing in the chosen currency
285
- - inserts a pending order and order item
286
- - optionally syncs default addresses and profile fields for the current user
287
- - builds a Freemius checkout URL, including sandbox parameters when enabled
288
-
289
- Supported credential sources include:
290
-
291
- - product-scoped JSON map
292
- - single-product sandbox overrides
293
- - single-product env vars
294
- - legacy shared env vars
295
-
296
- ### Product sync
297
-
298
- `syncFreemiusProductsToSupabase()` and `syncSingleFreemiusProduct()`:
299
-
300
- - call the Freemius API with signed requests
301
- - fetch plugins, plans, and pricing
302
- - upsert digital products into `products`
303
- - upsert related `freemius_plans` and `freemius_pricing`
304
-
305
- These flows are surfaced in the CMS product actions and the sandbox reset route.
306
-
307
- ### Current webhook limitation
308
-
309
- `app/api/webhooks/freemius/route.ts` currently verifies the webhook signature
310
- and acknowledges selected event types, but it does not yet reconcile license or
311
- order state back into the local database.
312
-
313
- ## Inventory Management and Fulfillment
314
-
315
- Inventory behavior is controlled by `trackQuantities`.
316
-
317
- When tracking is enabled:
318
-
319
- - checkout validates requested quantity against `inventory_items`
320
- - if a SKU is not yet cached there, product or variant stock fields are used as
321
- fallback
322
- - a paid order triggers `apply_order_inventory_deduction()`
323
-
324
- The deduction flow is resilient:
325
-
326
- - first it calls the database RPC `apply_order_inventory_deduction`
327
- - if that fails, it falls back to a direct SQL reconciliation path using
328
- `POSTGRES_URL` or `DATABASE_URL`
329
-
330
- Order statuses currently supported in code are:
331
-
332
- - `pending`
333
- - `paid`
334
- - `shipped`
335
- - `cancelled`
336
- - `refunded`
337
-
338
- Manual CMS order status changes also trigger invoice assignment and inventory
339
- deduction when an order is moved to `paid`.
340
-
341
- ## Invoice and Order Presentation
342
-
343
- The order/invoice layer includes:
344
-
345
- - stable invoice numbering through database functions
346
- - `invoice_settings` in `site_settings`
347
- - printable invoice presentation data via `invoice-server.ts`
348
- - UI components such as `InvoiceDocument` and `InvoiceViewerShell`
349
- - customer order history and invoice access through `customer-orders.ts`
350
-
351
- ## CMS Commerce Surfaces
352
-
353
- The active ecommerce CMS surface includes:
354
-
355
- - product list, create, edit, media, attribute, and variation management
356
- - inventory management
357
- - orders list and detail management
358
- - shipping zones and shipping rate management
359
- - payment-provider enablement
360
- - tax settings and manual tax-rate management
361
- - currency settings under `/cms/settings/currencies`
362
-
363
- The CMS shell only exposes these store sections when the ecommerce package is
364
- reported as active.
1
+ # 02 Ecommerce Capabilities
2
+
3
+ ## Scope and Source of Truth
4
+
5
+ The commerce feature set is implemented across:
6
+
7
+ - `libs/ecommerce/src/lib/*`
8
+ - `libs/db/src/supabase/migrations/00000000000003` through `00000000000006`
9
+ - `apps/nextblock/app/api/checkout/route.ts`
10
+ - `apps/nextblock/app/api/webhooks/*`
11
+ - `apps/nextblock/app/cms/products`, `orders`, `shipping`, `payments`, and
12
+ `settings/taxes`
13
+
14
+ In workspace code, the developer-facing import paths are:
15
+
16
+ - `@nextblock-cms/ecommerce`
17
+ - `@nextblock-cms/ecommerce/server`
18
+ - `@nextblock-cms/ecommerce/actions`
19
+
20
+ One packaging discrepancy exists today: `libs/ecommerce/package.json` is still
21
+ named `@nextblock-cms/ecom`, while the workspace and CLI activation flow expose
22
+ the package through the `@nextblock-cms/ecommerce` alias.
23
+
24
+ ## Commerce Data Model
25
+
26
+ The commerce schema spans:
27
+
28
+ - Catalog: `products`, `product_media`, `product_attributes`,
29
+ `product_attribute_terms`, `product_variants`,
30
+ `variant_attribute_mapping`, `categories`, `product_categories`
31
+ (categories and their translations were added by migrations
32
+ `00000000000019` and `00000000000020`)
33
+ - Inventory and licensing: `inventory_items`, `package_activations`,
34
+ `freemius_plans`, `freemius_pricing`
35
+ - Checkout and fulfillment: `orders`, `order_items`, `shipping_zones`,
36
+ `shipping_zone_locations`, `shipping_zone_methods`, `tax_rates`,
37
+ `currencies`
38
+
39
+ `products` can be physical or digital. The current provider selection logic
40
+ resolves:
41
+
42
+ - physical -> Stripe
43
+ - digital -> Freemius
44
+
45
+ Mixed-provider carts are rejected by `app/api/checkout/route.ts`.
46
+
47
+ ## Multi-Currency
48
+
49
+ The multi-currency implementation is real and fairly deep.
50
+
51
+ ### Store currencies
52
+
53
+ `currencies` stores:
54
+
55
+ - ISO code and symbol
56
+ - exchange rate relative to the current store default
57
+ - default and active flags
58
+ - rounding mode, rounding increment, and optional charm ending
59
+ - automatic FX refresh flag
60
+ - automatic product price sync flag
61
+ - last exchange-rate source and refresh timestamp
62
+
63
+ Supported rounding modes in code are:
64
+
65
+ - `none`
66
+ - `nearest`
67
+ - `up`
68
+ - `down`
69
+ - `charm`
70
+
71
+ ### Product and variant pricing
72
+
73
+ Products and variants support:
74
+
75
+ - legacy single-currency `price` and `sale_price`
76
+ - multi-currency `prices` and `sale_prices`
77
+
78
+ The pricing helpers resolve amounts by:
79
+
80
+ 1. looking for an explicit amount in the selected currency
81
+ 2. falling back to the base price
82
+ 3. converting from the default currency when store-managed auto-sync pricing is
83
+ enabled
84
+
85
+ The CMS product editor respects that distinction. Store-managed currencies can
86
+ be displayed in forms, but their saved overrides are stripped before
87
+ persisting.
88
+
89
+ ### Scheduled sales, price changes, and promotions
90
+
91
+ Products and variants carry a scheduled-pricing layer (migration
92
+ `00000000000025_add_sale_schedule_columns.sql`):
93
+
94
+ - `sale_start_at` / `sale_end_at` — the time window during which `sale_price` /
95
+ `sale_prices` apply. Both null = always-on (back-compat with static sales).
96
+ - `scheduled_price` / `scheduled_prices` / `scheduled_price_at` — a pending,
97
+ permanent regular-price change applied once `scheduled_price_at` passes
98
+ (bulk/Stripe-oriented; Freemius regular prices are owned by Freemius).
99
+ - `product_freemius_sale_coupons` — maps a product to an auto-generated,
100
+ time-bounded Freemius coupon so a scheduled Freemius sale is actually enforced
101
+ at Freemius-hosted checkout (Freemius enforces the coupon's start/end dates).
102
+
103
+ **Enforcement is read-time, not cron-driven.** The helpers in
104
+ `libs/ecommerce/src/lib/currency.ts` decide what applies *now*:
105
+
106
+ - `isSaleWindowActive({ saleStartAt, saleEndAt, now })`
107
+ - `resolveEffectivePriceForCurrency({ ..., saleStartAt, saleEndAt, scheduledPrice*, now })`
108
+ — wraps `resolvePriceForCurrency`, gating the sale by its window and swapping in
109
+ a due scheduled price. A sale outside its window resolves to `sale_price: null`.
110
+
111
+ Every place that computes a payable or displayed amount goes through the
112
+ window-aware helper: checkout providers (`providers/stripe.ts`,
113
+ `providers/freemius.ts`), cart/tax/coupon math, and storefront components
114
+ (`ProductCard`, `FeaturedProduct`, `ProductDetailsLayout`, UCP). The CMS edit
115
+ form exposes the window per-product and per-variant (`SaleScheduleFields`); the
116
+ bulk **Promotions** admin (`/cms/promotions`, `apps/nextblock/lib/promotions/`)
117
+ imports/exports sales and price changes via CSV.
118
+
119
+ > **Gotchas for future agents (these caused real revert/display bugs):**
120
+ >
121
+ > 1. **`generateVariantDrafts` (`variation-utils.ts`) must carry over every
122
+ > per-variant field**, including `sale_start_at`/`sale_end_at`. It re-runs on
123
+ > editor mount/attribute change; an omitted field resets to null and is then
124
+ > autosaved away ("dates revert after publish").
125
+ > 2. **Storefront block mappers must pass the window through** on *both* the
126
+ > product and each variant — `ProductGridBlock`, `FeaturedProductBlock`,
127
+ > `app/product/[slug]/page.tsx`. If the window is dropped, `isSaleWindowActive`
128
+ > sees both bounds null and treats the sale as always-on, so an inactive sale
129
+ > price shows (e.g. a "$25 – $32" range before the sale starts).
130
+ > 3. **`getVariantEffectivePriceRange` is window-aware** — pass
131
+ > `sale_start_at`/`sale_end_at` per variant or it ignores the schedule.
132
+ > 4. **Persisting on save/publish does not rely on the RPC.** Products are
133
+ > written via `upsert_product_with_variants`, but some databases run a stale
134
+ > copy of that function. `persistProductSaleSchedule` (`product-actions.ts`)
135
+ > writes the window columns with a direct `update` right after the RPC (same
136
+ > pattern as `persistProductTaxability`), matching variants by SKU.
137
+ > 5. **Autosave must not `reset()` the form or revalidate the edit route.** The
138
+ > edit-form autosave (`ProductForm.tsx`) uses a serialized-snapshot guard to
139
+ > avoid a render loop; `updateProductAction` writes only the draft (no
140
+ > `revalidatePath`). Re-rendering mid-edit resets native datetime inputs.
141
+
142
+ ### FX sync and rebasing
143
+
144
+ `libs/ecommerce/src/lib/currency-sync.ts` implements two separate operations:
145
+
146
+ - `syncStoreCurrencyRates()`: pulls fresh FX rates from `https://api.frankfurter.dev`
147
+ unless `FX_API_BASE_URL` overrides the provider.
148
+ - `rebaseStoreCurrencyExchangeRates()`: when an admin changes the default
149
+ currency, every stored rate is rebased so the new default becomes `1`.
150
+
151
+ The app exposes both through:
152
+
153
+ - CMS currency settings actions in
154
+ `apps/nextblock/app/cms/settings/currencies/actions.ts`
155
+ - `GET /api/cron/sync-currencies`, guarded by `CRON_SECRET`
156
+
157
+ ## Tax Calculation
158
+
159
+ Tax behavior is driven by the `ecommerce_inventory_settings` site setting,
160
+ loaded through `getEcommerceInventorySettings()`.
161
+
162
+ The current settings shape is:
163
+
164
+ - `trackQuantities`
165
+ - `enableTaxes`
166
+ - `taxCalculationMode`
167
+
168
+ Supported tax modes are:
169
+
170
+ - `manual`
171
+ - `automatic`
172
+
173
+ ### Manual mode
174
+
175
+ Manual mode uses `tax_rates` rows keyed by country and optional state/province.
176
+ Multiple rows can exist for the same jurisdiction, so stacked taxes such as GST
177
+ plus PST are supported.
178
+
179
+ During checkout:
180
+
181
+ - only taxable products are included
182
+ - the destination is normalized from shipping or billing data
183
+ - matching `tax_rates` are loaded
184
+ - tax lines are calculated and stored in `orders.tax_details`
185
+
186
+ ### Automatic mode
187
+
188
+ Automatic mode defers final tax calculation to Stripe Tax.
189
+
190
+ In this mode:
191
+
192
+ - checkout still records a tax intent in `orders.tax_details`
193
+ - the Stripe provider marks product and shipping tax codes on line items
194
+ - the webhook resync step replaces provisional tax data with finalized Stripe
195
+ checkout data
196
+
197
+ ## Shipping Zones and Rate Resolution
198
+
199
+ Shipping is backed by:
200
+
201
+ - `shipping_zones`
202
+ - `shipping_zone_locations`
203
+ - `shipping_zone_methods`
204
+
205
+ Each method stores:
206
+
207
+ - base amount and currency
208
+ - localized names
209
+ - per-currency amount maps and threshold maps
210
+ - `currency_pricing_mode` of `auto` or `manual`
211
+
212
+ ### Current resolver behavior
213
+
214
+ `libs/ecommerce/src/lib/shipping/resolver.ts` currently:
215
+
216
+ 1. loads active currencies
217
+ 2. queries zone locations by destination country
218
+ 3. prefers a state match when one exists
219
+ 4. otherwise prefers a country-wide match
220
+ 5. otherwise falls back to the first zone by `priority_order`
221
+ 6. filters methods by the cart total and minimum threshold
222
+ 7. converts method prices into the shopper currency
223
+ 8. returns only the cheapest valid method
224
+
225
+ Important implementation detail: `shipping_zone_locations.postal_code` exists in
226
+ schema, but the current resolver does not yet use postal code matching during
227
+ runtime resolution.
228
+
229
+ The storefront calls this through
230
+ `libs/ecommerce/src/lib/server-actions/shipping-actions.ts`.
231
+
232
+ ## Stripe Integration
233
+
234
+ Stripe is the current payment flow for physical products.
235
+
236
+ ### Checkout flow
237
+
238
+ `app/api/checkout/route.ts`:
239
+
240
+ - verifies the ecommerce package is active
241
+ - rejects carts without provider-aware items
242
+ - rejects mixed-provider carts
243
+ - requires a billing address
244
+ - resolves the provider through `getPaymentProvider()`
245
+
246
+ `StripeProvider.createCheckoutSession()` then:
247
+
248
+ - loads currencies and store settings
249
+ - validates products and variants against the database
250
+ - validates inventory before session creation when quantity tracking is enabled
251
+ - resolves shipping cost from the selected shipping method
252
+ - calculates tax in manual or automatic mode
253
+ - upserts a Stripe customer when an email is available
254
+ - inserts a pending `orders` row plus `order_items`
255
+ - stores currency, subtotal, shipping, tax, and exchange-rate data
256
+ - creates the Stripe Checkout Session and stores `stripe_session_id`
257
+
258
+ ### Webhook flow
259
+
260
+ `app/api/webhooks/stripe/route.ts` passes the raw body to
261
+ `handleStripeWebhook()`.
262
+
263
+ On `checkout.session.completed`, the sync layer:
264
+
265
+ - reloads the session with tax breakdown details
266
+ - finds the existing order
267
+ - stores payment intent, customer details, and finalized totals
268
+ - normalizes tax details from Stripe
269
+ - updates saved customer addresses
270
+ - assigns invoice metadata
271
+ - applies inventory deduction
272
+
273
+ ## Freemius Licensing and Product Sync
274
+
275
+ Freemius currently handles digital-product checkout and product synchronization.
276
+
277
+ ### Checkout behavior
278
+
279
+ `FreemiusProvider.createCheckoutSession()`:
280
+
281
+ - only allows one item per checkout
282
+ - loads the product from Supabase
283
+ - requires `freemius_product_id` and `freemius_plan_id`
284
+ - resolves pricing in the chosen currency
285
+ - inserts a pending order and order item
286
+ - optionally syncs default addresses and profile fields for the current user
287
+ - builds a Freemius checkout URL, including sandbox parameters when enabled
288
+
289
+ Supported credential sources include:
290
+
291
+ - product-scoped JSON map
292
+ - single-product sandbox overrides
293
+ - single-product env vars
294
+ - legacy shared env vars
295
+
296
+ ### Product sync
297
+
298
+ `syncFreemiusProductsToSupabase()` and `syncSingleFreemiusProduct()`:
299
+
300
+ - call the Freemius API with signed requests
301
+ - fetch plugins, plans, and pricing
302
+ - upsert digital products into `products`
303
+ - upsert related `freemius_plans` and `freemius_pricing`
304
+
305
+ These flows are surfaced in the CMS product actions and the sandbox reset route.
306
+
307
+ ### Current webhook limitation
308
+
309
+ `app/api/webhooks/freemius/route.ts` currently verifies the webhook signature
310
+ and acknowledges selected event types, but it does not yet reconcile license or
311
+ order state back into the local database.
312
+
313
+ ## Inventory Management and Fulfillment
314
+
315
+ Inventory behavior is controlled by `trackQuantities`.
316
+
317
+ When tracking is enabled:
318
+
319
+ - checkout validates requested quantity against `inventory_items`
320
+ - if a SKU is not yet cached there, product or variant stock fields are used as
321
+ fallback
322
+ - a paid order triggers `apply_order_inventory_deduction()`
323
+
324
+ The deduction flow is resilient:
325
+
326
+ - first it calls the database RPC `apply_order_inventory_deduction`
327
+ - if that fails, it falls back to a direct SQL reconciliation path using
328
+ `POSTGRES_URL` or `DATABASE_URL`
329
+
330
+ Order statuses currently supported in code are:
331
+
332
+ - `pending`
333
+ - `paid`
334
+ - `shipped`
335
+ - `cancelled`
336
+ - `refunded`
337
+
338
+ Manual CMS order status changes also trigger invoice assignment and inventory
339
+ deduction when an order is moved to `paid`.
340
+
341
+ ## Invoice and Order Presentation
342
+
343
+ The order/invoice layer includes:
344
+
345
+ - stable invoice numbering through database functions
346
+ - `invoice_settings` in `site_settings`
347
+ - printable invoice presentation data via `invoice-server.ts`
348
+ - UI components such as `InvoiceDocument` and `InvoiceViewerShell`
349
+ - customer order history and invoice access through `customer-orders.ts`
350
+
351
+ ## CMS Commerce Surfaces
352
+
353
+ The active ecommerce CMS surface includes:
354
+
355
+ - product list, create, edit, media, attribute, and variation management
356
+ - inventory management
357
+ - orders list and detail management
358
+ - shipping zones and shipping rate management
359
+ - payment-provider enablement
360
+ - tax settings and manual tax-rate management
361
+ - currency settings under `/cms/settings/currencies`
362
+
363
+ The CMS shell only exposes these store sections when the ecommerce package is
364
+ reported as active.