kybernus 3.0.1 → 3.2.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 (392) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/commands/ecommerce.d.ts +3 -0
  3. package/dist/cli/commands/ecommerce.d.ts.map +1 -0
  4. package/dist/cli/commands/ecommerce.js +164 -0
  5. package/dist/cli/commands/ecommerce.js.map +1 -0
  6. package/dist/index.js +2 -0
  7. package/dist/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/templates/ecommerce/.env.example +10 -0
  10. package/templates/ecommerce/.github/workflows/ci.yml +102 -0
  11. package/templates/ecommerce/.github/workflows/deploy.yml +31 -0
  12. package/templates/ecommerce/.prettierrc +9 -0
  13. package/templates/ecommerce/Dockerfile +54 -0
  14. package/templates/ecommerce/README.md +295 -0
  15. package/templates/ecommerce/apps/api/.env.example +59 -0
  16. package/templates/ecommerce/apps/api/jest.config.ts +50 -0
  17. package/templates/ecommerce/apps/api/jest.integration.config.ts +45 -0
  18. package/templates/ecommerce/apps/api/package.json +59 -0
  19. package/templates/ecommerce/apps/api/prisma/migrations/20260306000137_init/migration.sql +184 -0
  20. package/templates/ecommerce/apps/api/prisma/migrations/migration_lock.toml +3 -0
  21. package/templates/ecommerce/apps/api/prisma/schema.prisma +181 -0
  22. package/templates/ecommerce/apps/api/prisma/seed.ts +159 -0
  23. package/templates/ecommerce/apps/api/src/__tests__/app.test.ts +39 -0
  24. package/templates/ecommerce/apps/api/src/__tests__/globalSetup.ts +34 -0
  25. package/templates/ecommerce/apps/api/src/__tests__/globalTeardown.ts +16 -0
  26. package/templates/ecommerce/apps/api/src/__tests__/setup.db.ts +18 -0
  27. package/templates/ecommerce/apps/api/src/__tests__/setup.env.ts +14 -0
  28. package/templates/ecommerce/apps/api/src/app.ts +133 -0
  29. package/templates/ecommerce/apps/api/src/application/admin/admin-user.service.ts +24 -0
  30. package/templates/ecommerce/apps/api/src/application/admin/dashboard.service.ts +102 -0
  31. package/templates/ecommerce/apps/api/src/application/auth/auth.service.ts +185 -0
  32. package/templates/ecommerce/apps/api/src/application/cart/cart.service.ts +151 -0
  33. package/templates/ecommerce/apps/api/src/application/cart/coupon.service.ts +51 -0
  34. package/templates/ecommerce/apps/api/src/application/catalog/catalog.service.ts +168 -0
  35. package/templates/ecommerce/apps/api/src/application/checkout/checkout.service.ts +114 -0
  36. package/templates/ecommerce/apps/api/src/application/orders/order.service.ts +93 -0
  37. package/templates/ecommerce/apps/api/src/application/ports/email.port.ts +3 -0
  38. package/templates/ecommerce/apps/api/src/application/ports/payment.port.ts +24 -0
  39. package/templates/ecommerce/apps/api/src/application/ports/shipping.port.ts +9 -0
  40. package/templates/ecommerce/apps/api/src/application/ports/storage.port.ts +3 -0
  41. package/templates/ecommerce/apps/api/src/application/ports/token-blacklist.port.ts +4 -0
  42. package/templates/ecommerce/apps/api/src/application/ports/token.port.ts +18 -0
  43. package/templates/ecommerce/apps/api/src/application/profile/profile.service.ts +76 -0
  44. package/templates/ecommerce/apps/api/src/domain/auth/user.entity.ts +109 -0
  45. package/templates/ecommerce/apps/api/src/domain/auth/user.repository.ts +11 -0
  46. package/templates/ecommerce/apps/api/src/domain/cart/cart.entity.ts +136 -0
  47. package/templates/ecommerce/apps/api/src/domain/cart/cart.repository.ts +8 -0
  48. package/templates/ecommerce/apps/api/src/domain/cart/coupon.entity.ts +58 -0
  49. package/templates/ecommerce/apps/api/src/domain/cart/coupon.repository.ts +10 -0
  50. package/templates/ecommerce/apps/api/src/domain/catalog/category.entity.ts +51 -0
  51. package/templates/ecommerce/apps/api/src/domain/catalog/category.repository.ts +10 -0
  52. package/templates/ecommerce/apps/api/src/domain/catalog/product.entity.ts +130 -0
  53. package/templates/ecommerce/apps/api/src/domain/catalog/product.repository.ts +28 -0
  54. package/templates/ecommerce/apps/api/src/domain/checkout/order.entity.ts +121 -0
  55. package/templates/ecommerce/apps/api/src/domain/checkout/order.repository.ts +11 -0
  56. package/templates/ecommerce/apps/api/src/domain/shared/AppError.ts +12 -0
  57. package/templates/ecommerce/apps/api/src/infrastructure/cache/redis.ts +16 -0
  58. package/templates/ecommerce/apps/api/src/infrastructure/config/registry/admin.registry.ts +13 -0
  59. package/templates/ecommerce/apps/api/src/infrastructure/config/registry/auth.registry.ts +34 -0
  60. package/templates/ecommerce/apps/api/src/infrastructure/config/registry/cart.registry.ts +49 -0
  61. package/templates/ecommerce/apps/api/src/infrastructure/config/registry/catalog.registry.ts +24 -0
  62. package/templates/ecommerce/apps/api/src/infrastructure/config/registry/checkout.registry.ts +47 -0
  63. package/templates/ecommerce/apps/api/src/infrastructure/config/registry/orders.registry.ts +6 -0
  64. package/templates/ecommerce/apps/api/src/infrastructure/config/registry/profile.registry.ts +4 -0
  65. package/templates/ecommerce/apps/api/src/infrastructure/persistence/in-memory/cart.memory.repository.ts +33 -0
  66. package/templates/ecommerce/apps/api/src/infrastructure/persistence/in-memory/category.memory.repository.ts +41 -0
  67. package/templates/ecommerce/apps/api/src/infrastructure/persistence/in-memory/coupon.memory.repository.ts +55 -0
  68. package/templates/ecommerce/apps/api/src/infrastructure/persistence/in-memory/order.memory.repository.ts +75 -0
  69. package/templates/ecommerce/apps/api/src/infrastructure/persistence/in-memory/product.memory.repository.ts +100 -0
  70. package/templates/ecommerce/apps/api/src/infrastructure/persistence/in-memory/user.memory.repository.ts +54 -0
  71. package/templates/ecommerce/apps/api/src/infrastructure/persistence/prisma/auth/user.prisma.repository.ts +83 -0
  72. package/templates/ecommerce/apps/api/src/infrastructure/persistence/prisma/catalog/category.prisma.repository.ts +69 -0
  73. package/templates/ecommerce/apps/api/src/infrastructure/persistence/prisma/catalog/product.prisma.repository.ts +185 -0
  74. package/templates/ecommerce/apps/api/src/infrastructure/persistence/prisma/checkout/order.prisma.repository.ts +149 -0
  75. package/templates/ecommerce/apps/api/src/infrastructure/persistence/prisma-client.ts +17 -0
  76. package/templates/ecommerce/apps/api/src/infrastructure/services/email/email.registry.ts +18 -0
  77. package/templates/ecommerce/apps/api/src/infrastructure/services/email/ethereal.email.service.ts +38 -0
  78. package/templates/ecommerce/apps/api/src/infrastructure/services/email/noop.email.service.ts +12 -0
  79. package/templates/ecommerce/apps/api/src/infrastructure/services/email/smtp.email.service.ts +36 -0
  80. package/templates/ecommerce/apps/api/src/infrastructure/services/payment/stripe-webhook.handler.ts +83 -0
  81. package/templates/ecommerce/apps/api/src/infrastructure/services/payment/stripe.adapter.ts +39 -0
  82. package/templates/ecommerce/apps/api/src/infrastructure/services/shipping/mock.shipping.service.ts +17 -0
  83. package/templates/ecommerce/apps/api/src/infrastructure/services/storage/in-memory.storage.service.ts +11 -0
  84. package/templates/ecommerce/apps/api/src/infrastructure/services/storage/local-disk.storage.service.ts +27 -0
  85. package/templates/ecommerce/apps/api/src/infrastructure/services/storage/s3.storage.service.ts +52 -0
  86. package/templates/ecommerce/apps/api/src/infrastructure/services/storage/storage.registry.ts +19 -0
  87. package/templates/ecommerce/apps/api/src/infrastructure/services/token/redis.token.blacklist.ts +23 -0
  88. package/templates/ecommerce/apps/api/src/infrastructure/services/token/token.blacklist.ts +30 -0
  89. package/templates/ecommerce/apps/api/src/infrastructure/services/token/token.service.ts +136 -0
  90. package/templates/ecommerce/apps/api/src/modules/admin/__tests__/admin.routes.integration.test.ts +250 -0
  91. package/templates/ecommerce/apps/api/src/modules/admin/admin.controller.ts +116 -0
  92. package/templates/ecommerce/apps/api/src/modules/admin/admin.registry.ts +1 -0
  93. package/templates/ecommerce/apps/api/src/modules/admin/admin.routes.ts +21 -0
  94. package/templates/ecommerce/apps/api/src/modules/admin/admin.service.ts +1 -0
  95. package/templates/ecommerce/apps/api/src/modules/admin/admin.user.service.ts +1 -0
  96. package/templates/ecommerce/apps/api/src/modules/auth/__tests__/auth.logout.redis.test.ts +104 -0
  97. package/templates/ecommerce/apps/api/src/modules/auth/__tests__/auth.routes.integration.test.ts +211 -0
  98. package/templates/ecommerce/apps/api/src/modules/auth/__tests__/auth.service.unit.test.ts +260 -0
  99. package/templates/ecommerce/apps/api/src/modules/auth/__tests__/email.service.unit.test.ts +94 -0
  100. package/templates/ecommerce/apps/api/src/modules/auth/__tests__/token.blacklist.redis.test.ts +65 -0
  101. package/templates/ecommerce/apps/api/src/modules/auth/__tests__/user.entity.unit.test.ts +79 -0
  102. package/templates/ecommerce/apps/api/src/modules/auth/__tests__/user.prisma.repository.test.ts +138 -0
  103. package/templates/ecommerce/apps/api/src/modules/auth/auth.controller.ts +148 -0
  104. package/templates/ecommerce/apps/api/src/modules/auth/auth.registry.ts +1 -0
  105. package/templates/ecommerce/apps/api/src/modules/auth/auth.routes.ts +17 -0
  106. package/templates/ecommerce/apps/api/src/modules/auth/auth.service.ts +1 -0
  107. package/templates/ecommerce/apps/api/src/modules/auth/redis.token.blacklist.ts +1 -0
  108. package/templates/ecommerce/apps/api/src/modules/auth/token.blacklist.ts +2 -0
  109. package/templates/ecommerce/apps/api/src/modules/auth/token.service.ts +2 -0
  110. package/templates/ecommerce/apps/api/src/modules/auth/user.entity.ts +1 -0
  111. package/templates/ecommerce/apps/api/src/modules/auth/user.prisma.repository.ts +1 -0
  112. package/templates/ecommerce/apps/api/src/modules/auth/user.repository.ts +2 -0
  113. package/templates/ecommerce/apps/api/src/modules/cart/__tests__/cart.entity.unit.test.ts +144 -0
  114. package/templates/ecommerce/apps/api/src/modules/cart/__tests__/cart.routes.integration.test.ts +242 -0
  115. package/templates/ecommerce/apps/api/src/modules/cart/__tests__/cart.service.unit.test.ts +151 -0
  116. package/templates/ecommerce/apps/api/src/modules/cart/__tests__/coupon.admin.integration.test.ts +136 -0
  117. package/templates/ecommerce/apps/api/src/modules/cart/cart.controller.ts +94 -0
  118. package/templates/ecommerce/apps/api/src/modules/cart/cart.entity.ts +1 -0
  119. package/templates/ecommerce/apps/api/src/modules/cart/cart.registry.ts +1 -0
  120. package/templates/ecommerce/apps/api/src/modules/cart/cart.repository.ts +2 -0
  121. package/templates/ecommerce/apps/api/src/modules/cart/cart.routes.ts +17 -0
  122. package/templates/ecommerce/apps/api/src/modules/cart/cart.service.ts +1 -0
  123. package/templates/ecommerce/apps/api/src/modules/cart/coupon.entity.ts +1 -0
  124. package/templates/ecommerce/apps/api/src/modules/cart/coupon.repository.ts +2 -0
  125. package/templates/ecommerce/apps/api/src/modules/cart/coupon.service.ts +1 -0
  126. package/templates/ecommerce/apps/api/src/modules/cart/shipping.service.ts +2 -0
  127. package/templates/ecommerce/apps/api/src/modules/catalog/__tests__/catalog.routes.integration.test.ts +275 -0
  128. package/templates/ecommerce/apps/api/src/modules/catalog/__tests__/catalog.service.unit.test.ts +223 -0
  129. package/templates/ecommerce/apps/api/src/modules/catalog/__tests__/product.image.integration.test.ts +130 -0
  130. package/templates/ecommerce/apps/api/src/modules/catalog/__tests__/product.prisma.repository.test.ts +174 -0
  131. package/templates/ecommerce/apps/api/src/modules/catalog/catalog.controller.ts +176 -0
  132. package/templates/ecommerce/apps/api/src/modules/catalog/catalog.registry.ts +1 -0
  133. package/templates/ecommerce/apps/api/src/modules/catalog/catalog.routes.ts +38 -0
  134. package/templates/ecommerce/apps/api/src/modules/catalog/catalog.service.ts +1 -0
  135. package/templates/ecommerce/apps/api/src/modules/catalog/category.entity.ts +1 -0
  136. package/templates/ecommerce/apps/api/src/modules/catalog/category.prisma.repository.ts +1 -0
  137. package/templates/ecommerce/apps/api/src/modules/catalog/category.repository.ts +2 -0
  138. package/templates/ecommerce/apps/api/src/modules/catalog/product.entity.ts +1 -0
  139. package/templates/ecommerce/apps/api/src/modules/catalog/product.prisma.repository.ts +1 -0
  140. package/templates/ecommerce/apps/api/src/modules/catalog/product.repository.ts +2 -0
  141. package/templates/ecommerce/apps/api/src/modules/checkout/__tests__/checkout.routes.integration.test.ts +163 -0
  142. package/templates/ecommerce/apps/api/src/modules/checkout/__tests__/checkout.service.unit.test.ts +191 -0
  143. package/templates/ecommerce/apps/api/src/modules/checkout/__tests__/order.prisma.repository.test.ts +150 -0
  144. package/templates/ecommerce/apps/api/src/modules/checkout/checkout.controller.ts +59 -0
  145. package/templates/ecommerce/apps/api/src/modules/checkout/checkout.registry.ts +1 -0
  146. package/templates/ecommerce/apps/api/src/modules/checkout/checkout.routes.ts +18 -0
  147. package/templates/ecommerce/apps/api/src/modules/checkout/checkout.service.ts +1 -0
  148. package/templates/ecommerce/apps/api/src/modules/checkout/order.entity.ts +1 -0
  149. package/templates/ecommerce/apps/api/src/modules/checkout/order.prisma.repository.ts +1 -0
  150. package/templates/ecommerce/apps/api/src/modules/checkout/order.repository.ts +2 -0
  151. package/templates/ecommerce/apps/api/src/modules/checkout/tax.service.ts +9 -0
  152. package/templates/ecommerce/apps/api/src/modules/orders/__tests__/order.entity.unit.test.ts +68 -0
  153. package/templates/ecommerce/apps/api/src/modules/orders/__tests__/order.routes.integration.test.ts +254 -0
  154. package/templates/ecommerce/apps/api/src/modules/orders/__tests__/order.service.email.unit.test.ts +142 -0
  155. package/templates/ecommerce/apps/api/src/modules/orders/order.controller.ts +96 -0
  156. package/templates/ecommerce/apps/api/src/modules/orders/order.registry.ts +1 -0
  157. package/templates/ecommerce/apps/api/src/modules/orders/order.routes.ts +17 -0
  158. package/templates/ecommerce/apps/api/src/modules/orders/order.service.ts +1 -0
  159. package/templates/ecommerce/apps/api/src/modules/payment/__tests__/stripe-webhook.unit.test.ts +330 -0
  160. package/templates/ecommerce/apps/api/src/modules/payment/__tests__/stripe.adapter.unit.test.ts +84 -0
  161. package/templates/ecommerce/apps/api/src/modules/payment/adapters/stripe.adapter.ts +1 -0
  162. package/templates/ecommerce/apps/api/src/modules/payment/payment.port.ts +1 -0
  163. package/templates/ecommerce/apps/api/src/modules/payment/stripe-webhook.handler.ts +1 -0
  164. package/templates/ecommerce/apps/api/src/modules/profile/__tests__/profile.routes.integration.test.ts +180 -0
  165. package/templates/ecommerce/apps/api/src/modules/profile/__tests__/profile.service.unit.test.ts +187 -0
  166. package/templates/ecommerce/apps/api/src/modules/profile/profile.controller.ts +92 -0
  167. package/templates/ecommerce/apps/api/src/modules/profile/profile.registry.ts +1 -0
  168. package/templates/ecommerce/apps/api/src/modules/profile/profile.routes.ts +14 -0
  169. package/templates/ecommerce/apps/api/src/modules/profile/profile.service.ts +1 -0
  170. package/templates/ecommerce/apps/api/src/presentation/middlewares/authenticate.ts +37 -0
  171. package/templates/ecommerce/apps/api/src/presentation/middlewares/authorize.ts +23 -0
  172. package/templates/ecommerce/apps/api/src/presentation/middlewares/errorHandler.ts +48 -0
  173. package/templates/ecommerce/apps/api/src/presentation/modules/admin/admin.controller.ts +116 -0
  174. package/templates/ecommerce/apps/api/src/presentation/modules/admin/admin.routes.ts +21 -0
  175. package/templates/ecommerce/apps/api/src/presentation/modules/auth/auth.controller.ts +147 -0
  176. package/templates/ecommerce/apps/api/src/presentation/modules/auth/auth.routes.ts +17 -0
  177. package/templates/ecommerce/apps/api/src/presentation/modules/cart/cart.controller.ts +94 -0
  178. package/templates/ecommerce/apps/api/src/presentation/modules/cart/cart.routes.ts +17 -0
  179. package/templates/ecommerce/apps/api/src/presentation/modules/catalog/catalog.controller.ts +176 -0
  180. package/templates/ecommerce/apps/api/src/presentation/modules/catalog/catalog.routes.ts +38 -0
  181. package/templates/ecommerce/apps/api/src/presentation/modules/checkout/checkout.controller.ts +59 -0
  182. package/templates/ecommerce/apps/api/src/presentation/modules/checkout/checkout.routes.ts +18 -0
  183. package/templates/ecommerce/apps/api/src/presentation/modules/orders/order.controller.ts +96 -0
  184. package/templates/ecommerce/apps/api/src/presentation/modules/orders/order.routes.ts +17 -0
  185. package/templates/ecommerce/apps/api/src/presentation/modules/profile/profile.controller.ts +92 -0
  186. package/templates/ecommerce/apps/api/src/presentation/modules/profile/profile.routes.ts +14 -0
  187. package/templates/ecommerce/apps/api/src/presentation/validators/uuidParam.ts +20 -0
  188. package/templates/ecommerce/apps/api/src/server.ts +47 -0
  189. package/templates/ecommerce/apps/api/src/shared/__tests__/uuid.validation.test.ts +111 -0
  190. package/templates/ecommerce/apps/api/src/shared/errors/AppError.ts +1 -0
  191. package/templates/ecommerce/apps/api/src/shared/infra/email/EtherealEmailService.ts +1 -0
  192. package/templates/ecommerce/apps/api/src/shared/infra/email/IEmailService.ts +1 -0
  193. package/templates/ecommerce/apps/api/src/shared/infra/email/NoopEmailService.ts +1 -0
  194. package/templates/ecommerce/apps/api/src/shared/infra/email/SmtpEmailService.ts +1 -0
  195. package/templates/ecommerce/apps/api/src/shared/infra/email/__tests__/ethereal.email.integration.test.ts +32 -0
  196. package/templates/ecommerce/apps/api/src/shared/infra/email/email.registry.ts +1 -0
  197. package/templates/ecommerce/apps/api/src/shared/infra/prisma.ts +1 -0
  198. package/templates/ecommerce/apps/api/src/shared/infra/redis.ts +1 -0
  199. package/templates/ecommerce/apps/api/src/shared/infra/storage/IStorageService.ts +1 -0
  200. package/templates/ecommerce/apps/api/src/shared/infra/storage/InMemoryStorageService.ts +1 -0
  201. package/templates/ecommerce/apps/api/src/shared/infra/storage/LocalDiskStorageService.ts +1 -0
  202. package/templates/ecommerce/apps/api/src/shared/infra/storage/S3StorageService.ts +1 -0
  203. package/templates/ecommerce/apps/api/src/shared/infra/storage/__tests__/s3.storage.unit.test.ts +73 -0
  204. package/templates/ecommerce/apps/api/src/shared/infra/storage/storage.registry.ts +1 -0
  205. package/templates/ecommerce/apps/api/src/shared/middlewares/authenticate.ts +1 -0
  206. package/templates/ecommerce/apps/api/src/shared/middlewares/authorize.ts +1 -0
  207. package/templates/ecommerce/apps/api/src/shared/middlewares/errorHandler.ts +1 -0
  208. package/templates/ecommerce/apps/api/src/shared/validators/uuidParam.ts +1 -0
  209. package/templates/ecommerce/apps/api/tsconfig.json +15 -0
  210. package/templates/ecommerce/apps/web/.env.example +8 -0
  211. package/templates/ecommerce/apps/web/index.html +19 -0
  212. package/templates/ecommerce/apps/web/jest.config.ts +45 -0
  213. package/templates/ecommerce/apps/web/package.json +38 -0
  214. package/templates/ecommerce/apps/web/src/App.tsx +133 -0
  215. package/templates/ecommerce/apps/web/src/__mocks__/fileMock.ts +1 -0
  216. package/templates/ecommerce/apps/web/src/__mocks__/styleMock.ts +1 -0
  217. package/templates/ecommerce/apps/web/src/index.css +159 -0
  218. package/templates/ecommerce/apps/web/src/main.tsx +13 -0
  219. package/templates/ecommerce/apps/web/src/modules/admin/__tests__/CouponsAdminPage.test.tsx +134 -0
  220. package/templates/ecommerce/apps/web/src/modules/admin/__tests__/DashboardPage.test.tsx +65 -0
  221. package/templates/ecommerce/apps/web/src/modules/admin/__tests__/OrdersAdminPage.test.tsx +79 -0
  222. package/templates/ecommerce/apps/web/src/modules/admin/__tests__/ProductsAdminPage.test.tsx +84 -0
  223. package/templates/ecommerce/apps/web/src/modules/admin/__tests__/UsersAdminPage.test.tsx +85 -0
  224. package/templates/ecommerce/apps/web/src/modules/admin/pages/CouponsAdminPage.tsx +179 -0
  225. package/templates/ecommerce/apps/web/src/modules/admin/pages/DashboardPage.tsx +58 -0
  226. package/templates/ecommerce/apps/web/src/modules/admin/pages/OrdersAdminPage.tsx +178 -0
  227. package/templates/ecommerce/apps/web/src/modules/admin/pages/ProductsAdminPage.tsx +444 -0
  228. package/templates/ecommerce/apps/web/src/modules/admin/pages/UsersAdminPage.tsx +87 -0
  229. package/templates/ecommerce/apps/web/src/modules/auth/LoginForm.tsx +91 -0
  230. package/templates/ecommerce/apps/web/src/modules/auth/RegisterForm.tsx +109 -0
  231. package/templates/ecommerce/apps/web/src/modules/auth/__tests__/ForgotPasswordPage.test.tsx +42 -0
  232. package/templates/ecommerce/apps/web/src/modules/auth/__tests__/LoginForm.test.tsx +76 -0
  233. package/templates/ecommerce/apps/web/src/modules/auth/__tests__/RegisterForm.test.tsx +62 -0
  234. package/templates/ecommerce/apps/web/src/modules/auth/__tests__/ResetPasswordPage.test.tsx +66 -0
  235. package/templates/ecommerce/apps/web/src/modules/auth/pages/ForgotPasswordPage.tsx +100 -0
  236. package/templates/ecommerce/apps/web/src/modules/auth/pages/LoginPage.tsx +39 -0
  237. package/templates/ecommerce/apps/web/src/modules/auth/pages/RegisterPage.tsx +39 -0
  238. package/templates/ecommerce/apps/web/src/modules/auth/pages/ResetPasswordPage.tsx +110 -0
  239. package/templates/ecommerce/apps/web/src/modules/auth/useAuthStore.ts +141 -0
  240. package/templates/ecommerce/apps/web/src/modules/cart/__tests__/CartPage.test.tsx +111 -0
  241. package/templates/ecommerce/apps/web/src/modules/cart/pages/CartPage.tsx +313 -0
  242. package/templates/ecommerce/apps/web/src/modules/catalog/__tests__/ProductCard.test.tsx +59 -0
  243. package/templates/ecommerce/apps/web/src/modules/catalog/__tests__/ProductFilters.test.tsx +56 -0
  244. package/templates/ecommerce/apps/web/src/modules/catalog/components/ProductCard.tsx +78 -0
  245. package/templates/ecommerce/apps/web/src/modules/catalog/components/ProductFilters.tsx +104 -0
  246. package/templates/ecommerce/apps/web/src/modules/catalog/pages/ProductDetailPage.tsx +179 -0
  247. package/templates/ecommerce/apps/web/src/modules/catalog/pages/ProductListPage.tsx +100 -0
  248. package/templates/ecommerce/apps/web/src/modules/checkout/__tests__/CheckoutPage.test.tsx +159 -0
  249. package/templates/ecommerce/apps/web/src/modules/checkout/__tests__/StripePaymentForm.test.tsx +79 -0
  250. package/templates/ecommerce/apps/web/src/modules/checkout/components/StripePaymentForm.tsx +55 -0
  251. package/templates/ecommerce/apps/web/src/modules/checkout/hooks/useCheckout.ts +56 -0
  252. package/templates/ecommerce/apps/web/src/modules/checkout/pages/CheckoutPage.tsx +344 -0
  253. package/templates/ecommerce/apps/web/src/modules/checkout/pages/CheckoutSuccessPage.tsx +12 -0
  254. package/templates/ecommerce/apps/web/src/modules/legal/pages/PrivacyPolicyPage.tsx +207 -0
  255. package/templates/ecommerce/apps/web/src/modules/legal/pages/TermsOfServicePage.tsx +175 -0
  256. package/templates/ecommerce/apps/web/src/modules/orders/__tests__/OrderDetailPage.test.tsx +75 -0
  257. package/templates/ecommerce/apps/web/src/modules/orders/__tests__/OrderHistoryPage.test.tsx +87 -0
  258. package/templates/ecommerce/apps/web/src/modules/orders/pages/OrderDetailPage.tsx +73 -0
  259. package/templates/ecommerce/apps/web/src/modules/orders/pages/OrderHistoryPage.tsx +97 -0
  260. package/templates/ecommerce/apps/web/src/modules/profile/__tests__/ProfilePage.test.tsx +150 -0
  261. package/templates/ecommerce/apps/web/src/modules/profile/pages/ProfilePage.tsx +275 -0
  262. package/templates/ecommerce/apps/web/src/setupTests.ts +10 -0
  263. package/templates/ecommerce/apps/web/src/shared/components/CookieConsent.tsx +108 -0
  264. package/templates/ecommerce/apps/web/src/shared/components/ErrorBoundary.tsx +112 -0
  265. package/templates/ecommerce/apps/web/src/shared/components/Layout.tsx +143 -0
  266. package/templates/ecommerce/apps/web/src/shared/components/ProtectedRoute.tsx +21 -0
  267. package/templates/ecommerce/apps/web/src/shared/config/siteConfig.ts +57 -0
  268. package/templates/ecommerce/apps/web/src/shared/hooks/usePageTitle.ts +16 -0
  269. package/templates/ecommerce/apps/web/src/shared/lib/apiFetch.ts +16 -0
  270. package/templates/ecommerce/apps/web/src/shared/pages/NotFoundPage.tsx +42 -0
  271. package/templates/ecommerce/apps/web/src/shared/theme/ThemeProvider.tsx +45 -0
  272. package/templates/ecommerce/apps/web/src/shared/theme/__tests__/ThemeProvider.test.tsx +78 -0
  273. package/templates/ecommerce/apps/web/src/shared/theme/createTheme.ts +58 -0
  274. package/templates/ecommerce/apps/web/src/shared/theme/tokens.ts +81 -0
  275. package/templates/ecommerce/apps/web/src/vite-env.d.ts +1 -0
  276. package/templates/ecommerce/apps/web/tsconfig.jest.json +12 -0
  277. package/templates/ecommerce/apps/web/tsconfig.json +25 -0
  278. package/templates/ecommerce/apps/web/tsconfig.node.json +11 -0
  279. package/templates/ecommerce/apps/web/vite.config.ts +30 -0
  280. package/templates/ecommerce/docker-compose.yml +85 -0
  281. package/templates/ecommerce/package-lock.json +11255 -0
  282. package/templates/ecommerce/package.json +27 -0
  283. package/templates/ecommerce/packages/shared-types/package.json +13 -0
  284. package/templates/ecommerce/packages/shared-types/src/index.ts +3 -0
  285. package/templates/ecommerce/packages/shared-types/src/theme.ts +44 -0
  286. package/templates/ecommerce/packages/shared-types/tsconfig.json +11 -0
  287. package/templates/ecommerce/scripts/customize.sh +201 -0
  288. package/templates/ecommerce/tsconfig.json +14 -0
  289. package/templates/java-spring/clean/.gitignore.hbs +72 -0
  290. package/templates/java-spring/clean/docker-compose.yml.hbs +6 -3
  291. package/templates/java-spring/clean/src/main/java/{{packagePath}}/application/usecase/PaymentUseCase.java.hbs +21 -17
  292. package/templates/java-spring/clean/src/main/java/{{packagePath}}/infrastructure/persistence/entity/UserEntity.java.hbs +52 -0
  293. package/templates/java-spring/clean/src/main/java/{{packagePath}}/infrastructure/persistence/repository/JpaUserRepository.java.hbs +12 -0
  294. package/templates/java-spring/clean/src/main/java/{{packagePath}}/infrastructure/security/JwtAuthenticationFilter.java.hbs +64 -0
  295. package/templates/java-spring/clean/src/main/java/{{packagePath}}/infrastructure/security/SecurityConfig.java.hbs +36 -0
  296. package/templates/java-spring/clean/src/main/java/{{packagePath}}/infrastructure/stripe/StripeGateway.java.hbs +63 -0
  297. package/templates/java-spring/clean/src/main/resources/application.properties.hbs +6 -7
  298. package/templates/java-spring/hexagonal/.gitignore.hbs +72 -0
  299. package/templates/java-spring/hexagonal/docker-compose.yml.hbs +6 -3
  300. package/templates/java-spring/hexagonal/src/main/java/{{packagePath}}/adapters/outbound/security/JwtFilter.java.hbs +71 -0
  301. package/templates/java-spring/hexagonal/src/main/java/{{packagePath}}/adapters/outbound/security/SecurityConfig.java.hbs +35 -0
  302. package/templates/java-spring/hexagonal/src/main/java/{{packagePath}}/core/service/PaymentService.java.hbs +3 -3
  303. package/templates/java-spring/hexagonal/src/main/resources/application.properties.hbs +4 -4
  304. package/templates/java-spring/mvc/.gitignore.hbs +72 -0
  305. package/templates/java-spring/mvc/docker-compose.yml.hbs +6 -3
  306. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/config/SecurityConfig.java.hbs +13 -12
  307. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/AuthController.java.hbs +9 -8
  308. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/PaymentsController.java.hbs +5 -6
  309. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/service/StripeService.java.hbs +3 -3
  310. package/templates/java-spring/mvc/src/main/resources/application.yml.hbs +29 -26
  311. package/templates/nestjs/clean/.gitignore.hbs +42 -0
  312. package/templates/nestjs/clean/Dockerfile.hbs +6 -3
  313. package/templates/nestjs/clean/docker-compose.yml.hbs +1 -11
  314. package/templates/nestjs/clean/src/app.module.ts.hbs +2 -1
  315. package/templates/nestjs/clean/src/application/payment.service.ts.hbs +72 -72
  316. package/templates/nestjs/clean/src/domain/entities/user.entity.ts.hbs +2 -2
  317. package/templates/nestjs/clean/src/domain/repositories/user.repository.ts.hbs +2 -2
  318. package/templates/nestjs/clean/src/infrastructure/database/repositories/prisma.user.repository.ts.hbs +18 -18
  319. package/templates/nestjs/clean/src/infrastructure/http/health.controller.ts.hbs +9 -0
  320. package/templates/nestjs/clean/src/main.ts.hbs +1 -4
  321. package/templates/nestjs/clean/src/payment.module.ts.hbs +12 -12
  322. package/templates/nestjs/hexagonal/.gitignore.hbs +42 -0
  323. package/templates/nestjs/hexagonal/Dockerfile.hbs +6 -3
  324. package/templates/nestjs/hexagonal/docker-compose.yml.hbs +1 -11
  325. package/templates/nestjs/hexagonal/src/adapters/inbound/health.controller.ts.hbs +9 -0
  326. package/templates/nestjs/hexagonal/src/app.module.ts.hbs +2 -1
  327. package/templates/nestjs/hexagonal/src/core/domain/user.entity.ts.hbs +6 -6
  328. package/templates/nestjs/hexagonal/src/core/ports/ports.ts.hbs +4 -4
  329. package/templates/nestjs/hexagonal/src/main.ts.hbs +1 -4
  330. package/templates/nestjs/mvc/.gitignore.hbs +42 -0
  331. package/templates/nestjs/mvc/Dockerfile.hbs +6 -3
  332. package/templates/nestjs/mvc/docker-compose.yml.hbs +1 -11
  333. package/templates/nestjs/mvc/src/auth/auth.controller.ts.hbs +11 -1
  334. package/templates/nestjs/mvc/src/auth/auth.service.ts.hbs +3 -1
  335. package/templates/nestjs/mvc/src/controllers/health.controller.ts.hbs +6 -6
  336. package/templates/nestjs/mvc/src/main.ts.hbs +1 -4
  337. package/templates/nestjs/mvc/src/models/create-item.dto.ts.hbs +5 -2
  338. package/templates/nestjs/mvc/src/prisma/prisma.service.ts.hbs +1 -0
  339. package/templates/nextjs/mvc/.gitignore.hbs +42 -0
  340. package/templates/nextjs/mvc/Dockerfile.hbs +23 -8
  341. package/templates/nextjs/mvc/docker-compose.yml.hbs +1 -1
  342. package/templates/nodejs-express/clean/.gitignore.hbs +42 -0
  343. package/templates/nodejs-express/clean/Dockerfile.hbs +6 -1
  344. package/templates/nodejs-express/clean/docker-compose.yml.hbs +2 -2
  345. package/templates/nodejs-express/clean/package.json.hbs +69 -69
  346. package/templates/nodejs-express/clean/src/config.ts.hbs +11 -0
  347. package/templates/nodejs-express/clean/src/domain/entities/User.ts.hbs +46 -8
  348. package/templates/nodejs-express/hexagonal/.gitignore.hbs +42 -0
  349. package/templates/nodejs-express/hexagonal/Dockerfile.hbs +1 -1
  350. package/templates/nodejs-express/hexagonal/docker-compose.yml.hbs +2 -2
  351. package/templates/nodejs-express/hexagonal/package.json.hbs +69 -69
  352. package/templates/nodejs-express/hexagonal/src/adapters/inbound/http/PaymentController.ts.hbs +21 -38
  353. package/templates/nodejs-express/hexagonal/src/adapters/outbound/persistence/prisma.ts.hbs +2 -0
  354. package/templates/nodejs-express/hexagonal/src/config.ts.hbs +9 -0
  355. package/templates/nodejs-express/hexagonal/src/core/AuthService.ts.hbs +5 -5
  356. package/templates/nodejs-express/hexagonal/src/core/PaymentService.ts.hbs +7 -22
  357. package/templates/nodejs-express/hexagonal/src/core/domain/entities/User.ts.hbs +24 -4
  358. package/templates/nodejs-express/mvc/.gitignore.hbs +42 -0
  359. package/templates/nodejs-express/mvc/package.json.hbs +67 -67
  360. package/templates/python-fastapi/clean/.gitignore.hbs +76 -0
  361. package/templates/python-fastapi/clean/app/application/services/payment_service.py.hbs +3 -3
  362. package/templates/python-fastapi/clean/app/config.py.hbs +6 -7
  363. package/templates/python-fastapi/clean/app/domain/usecases/login_user.py.hbs +15 -0
  364. package/templates/python-fastapi/clean/app/infrastructure/http/auth_controller.py.hbs +40 -6
  365. package/templates/python-fastapi/clean/app/infrastructure/http/payment_controller.py.hbs +5 -4
  366. package/templates/python-fastapi/clean/app/infrastructure/security/jwt.py.hbs +23 -0
  367. package/templates/python-fastapi/clean/app/main.py.hbs +3 -0
  368. package/templates/python-fastapi/clean/docker-compose.yml.hbs +5 -12
  369. package/templates/python-fastapi/clean/requirements.txt.hbs +3 -0
  370. package/templates/python-fastapi/hexagonal/.gitignore.hbs +76 -0
  371. package/templates/python-fastapi/hexagonal/app/adapters/inbound/http_adapter.py.hbs +6 -9
  372. package/templates/python-fastapi/hexagonal/app/adapters/inbound/payment_http_adapter.py.hbs +4 -3
  373. package/templates/python-fastapi/hexagonal/app/adapters/outbound/stripe_adapter.py.hbs +30 -19
  374. package/templates/python-fastapi/hexagonal/app/config.py.hbs +14 -4
  375. package/templates/python-fastapi/hexagonal/app/core/domain/user.py.hbs +3 -1
  376. package/templates/python-fastapi/hexagonal/app/core/payment_service.py.hbs +28 -18
  377. package/templates/python-fastapi/hexagonal/app/core/ports/__init__.py.hbs +3 -0
  378. package/templates/python-fastapi/hexagonal/app/core/ports/user_repository.py.hbs +15 -0
  379. package/templates/python-fastapi/hexagonal/app/infrastructure/database/session.py.hbs +7 -0
  380. package/templates/python-fastapi/hexagonal/app/infrastructure/database/user_repository.py.hbs +53 -0
  381. package/templates/python-fastapi/hexagonal/app/infrastructure/security/__init__.py.hbs +0 -0
  382. package/templates/python-fastapi/hexagonal/app/infrastructure/security/adapters.py.hbs +23 -0
  383. package/templates/python-fastapi/hexagonal/app/infrastructure/security/jwt.py.hbs +23 -0
  384. package/templates/python-fastapi/hexagonal/docker-compose.yml.hbs +5 -12
  385. package/templates/python-fastapi/hexagonal/requirements.txt.hbs +4 -0
  386. package/templates/python-fastapi/mvc/.gitignore.hbs +76 -0
  387. package/templates/python-fastapi/mvc/app/controllers/payments.py.hbs +3 -17
  388. package/templates/python-fastapi/mvc/app/middleware/security.py.hbs +24 -3
  389. package/templates/python-fastapi/mvc/app/schemas/item.py.hbs +3 -1
  390. package/templates/python-fastapi/mvc/docker-compose.yml.hbs +5 -12
  391. package/templates/python-fastapi/mvc/requirements.txt.hbs +3 -1
  392. package/templates/nodejs-express/hexagonal/src/adapters/outbound/persistence/prisma.ts +0 -5
@@ -0,0 +1,63 @@
1
+ package {{packageName}}.infrastructure.stripe;
2
+
3
+ import com.stripe.model.Customer;
4
+ import com.stripe.model.Event;
5
+ import com.stripe.model.checkout.Session;
6
+ import com.stripe.param.CustomerCreateParams;
7
+ import com.stripe.param.checkout.SessionCreateParams;
8
+ import org.springframework.beans.factory.annotation.Value;
9
+ import org.springframework.stereotype.Service;
10
+
11
+ @Service
12
+ public class StripeGateway {
13
+
14
+ @Value("${stripe.secret-key:sk_test_dummy}")
15
+ private String secretKey;
16
+
17
+ @Value("${stripe.webhook-secret:whsec_dummy}")
18
+ private String webhookSecret;
19
+
20
+ @Value("${frontend.url:http://localhost:3000}")
21
+ private String frontendUrl;
22
+
23
+ @jakarta.annotation.PostConstruct
24
+ public void init() {
25
+ com.stripe.Stripe.apiKey = secretKey;
26
+ }
27
+
28
+ public Customer createCustomer(String email, String userId) throws Exception {
29
+ CustomerCreateParams params = CustomerCreateParams.builder()
30
+ .setEmail(email)
31
+ .putMetadata("userId", userId)
32
+ .build();
33
+ return Customer.create(params);
34
+ }
35
+
36
+ public Session createCheckoutSession(String customerId, String priceId, String userId) throws Exception {
37
+ SessionCreateParams params = SessionCreateParams.builder()
38
+ .setCustomer(customerId)
39
+ .setSuccessUrl(frontendUrl + "/success?session_id={CHECKOUT_SESSION_ID}")
40
+ .setCancelUrl(frontendUrl + "/cancel")
41
+ .addLineItem(SessionCreateParams.LineItem.builder()
42
+ .setPrice(priceId)
43
+ .setQuantity(1L)
44
+ .build())
45
+ .setMode(SessionCreateParams.Mode.SUBSCRIPTION)
46
+ .setClientReferenceId(userId)
47
+ .build();
48
+ return Session.create(params);
49
+ }
50
+
51
+ public com.stripe.model.billingportal.Session createPortalSession(String customerId) throws Exception {
52
+ com.stripe.param.billingportal.SessionCreateParams params =
53
+ com.stripe.param.billingportal.SessionCreateParams.builder()
54
+ .setCustomer(customerId)
55
+ .setReturnUrl(frontendUrl + "/account")
56
+ .build();
57
+ return com.stripe.model.billingportal.Session.create(params);
58
+ }
59
+
60
+ public Event constructWebhookEvent(String payload, String sigHeader) throws Exception {
61
+ return com.stripe.net.Webhook.constructEvent(payload, sigHeader, webhookSecret);
62
+ }
63
+ }
@@ -1,7 +1,7 @@
1
1
  spring.application.name={{projectNameKebabCase}}
2
2
 
3
3
  # Database Configuration
4
- spring.datasource.url=jdbc:postgresql://postgres:5432/{{projectNameKebabCase}}
4
+ spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:5432/{{projectNameKebabCase}}
5
5
  spring.datasource.username=postgres
6
6
  spring.datasource.password=postgres
7
7
  spring.datasource.driver-class-name=org.postgresql.Driver
@@ -12,14 +12,13 @@ spring.jpa.hibernate.ddl-auto=update
12
12
  spring.jpa.show-sql=true
13
13
  spring.jpa.properties.hibernate.format_sql=true
14
14
 
15
- # JWT
16
- application.security.jwt.secret-key={{jwtSecretKey}}
17
- application.security.jwt.expiration=86400000
18
- application.security.jwt.refresh-token.expiration=604800000
15
+ # JWT (property name matches SecurityAdapters.java @Value)
16
+ jwt.secret=${JWT_SECRET:{{jwtSecretKey}}}
17
+ jwt.expiration=86400000
19
18
 
20
19
  # Stripe
21
- stripe.secret-key=${STRIPE_SECRET_KEY}
22
- stripe.webhook-secret=${STRIPE_WEBHOOK_SECRET}
20
+ stripe.secret-key=${STRIPE_SECRET_KEY:sk_test_dummy}
21
+ stripe.webhook-secret=${STRIPE_WEBHOOK_SECRET:whsec_dummy}
23
22
 
24
23
  # Frontend URL (for Stripe redirect URLs)
25
24
  frontend.url=${FRONTEND_URL:http://localhost:3000}
@@ -0,0 +1,72 @@
1
+ # Compiled class files
2
+ *.class
3
+
4
+ # Log files
5
+ *.log
6
+
7
+ # Package files
8
+ *.jar
9
+ *.war
10
+ *.nar
11
+ *.ear
12
+ *.zip
13
+ *.tar.gz
14
+ *.rar
15
+
16
+ # Virtual machine crash logs
17
+ hs_err_pid*
18
+ replay_pid*
19
+
20
+ # Maven
21
+ target/
22
+ .mvn/wrapper/maven-wrapper.jar
23
+ !**/src/main/**/target/
24
+ !**/src/test/**/target/
25
+
26
+ # Gradle
27
+ .gradle
28
+ build/
29
+ !gradle/wrapper/gradle-wrapper.jar
30
+ !**/src/main/**/build/
31
+ !**/src/test/**/build/
32
+
33
+ # Spring Boot
34
+ spring-shell.log
35
+
36
+ # STS / Eclipse
37
+ .apt_generated
38
+ .classpath
39
+ .factorypath
40
+ .project
41
+ .settings
42
+ .springBeans
43
+ .sts4-cache
44
+
45
+ # IntelliJ IDEA
46
+ .idea/
47
+ *.iws
48
+ *.iml
49
+ *.ipr
50
+
51
+ # VS Code
52
+ .vscode/
53
+
54
+ # NetBeans
55
+ /nbproject/private/
56
+ /nbbuild/
57
+ /nbdist/
58
+ /.nb-gradle/
59
+
60
+ # Environment
61
+ .env
62
+ .env.local
63
+ .env.*.local
64
+ !.env.example
65
+ application-local.yml
66
+ application-local.properties
67
+ application-dev.yml
68
+ application-dev.properties
69
+
70
+ # OS
71
+ .DS_Store
72
+ Thumbs.db
@@ -1,7 +1,5 @@
1
- version: '3.8'
2
-
3
1
  services:
4
- postgres:
2
+ db:
5
3
  image: postgres:15-alpine
6
4
  container_name: {{projectNameKebabCase}}-db
7
5
  environment:
@@ -13,6 +11,11 @@ services:
13
11
  volumes:
14
12
  - postgres_data:/var/lib/postgresql/data
15
13
  restart: unless-stopped
14
+ healthcheck:
15
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
16
+ interval: 10s
17
+ timeout: 5s
18
+ retries: 5
16
19
 
17
20
  volumes:
18
21
  postgres_data:
@@ -0,0 +1,71 @@
1
+ package {{packageName}}.adapters.outbound.security;
2
+
3
+ import io.jsonwebtoken.Claims;
4
+ import io.jsonwebtoken.Jwts;
5
+ import io.jsonwebtoken.security.Keys;
6
+ import jakarta.servlet.FilterChain;
7
+ import jakarta.servlet.ServletException;
8
+ import jakarta.servlet.http.HttpServletRequest;
9
+ import jakarta.servlet.http.HttpServletResponse;
10
+ import org.springframework.beans.factory.annotation.Value;
11
+ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
12
+ import org.springframework.security.core.context.SecurityContextHolder;
13
+ import org.springframework.security.core.userdetails.User;
14
+ import org.springframework.security.core.userdetails.UserDetails;
15
+ import org.springframework.stereotype.Component;
16
+ import org.springframework.web.filter.OncePerRequestFilter;
17
+
18
+ import javax.crypto.SecretKey;
19
+ import java.io.IOException;
20
+ import java.nio.charset.StandardCharsets;
21
+ import java.util.Collections;
22
+
23
+ @Component
24
+ public class JwtFilter extends OncePerRequestFilter {
25
+
26
+ @Value("${application.security.jwt.secret-key}")
27
+ private String jwtSecret;
28
+
29
+ private SecretKey getSigningKey() {
30
+ return Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8));
31
+ }
32
+
33
+ @Override
34
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
35
+ throws ServletException, IOException {
36
+
37
+ final String authHeader = request.getHeader("Authorization");
38
+ if (authHeader == null || !authHeader.startsWith("Bearer ")) {
39
+ filterChain.doFilter(request, response);
40
+ return;
41
+ }
42
+
43
+ final String jwt = authHeader.substring(7);
44
+ try {
45
+ Claims claims = Jwts.parser()
46
+ .verifyWith(getSigningKey())
47
+ .build()
48
+ .parseSignedClaims(jwt)
49
+ .getPayload();
50
+
51
+ String userId = claims.getSubject();
52
+
53
+ if (userId != null && SecurityContextHolder.getContext().getAuthentication() == null) {
54
+ UserDetails userDetails = User.builder()
55
+ .username(userId)
56
+ .password("")
57
+ .authorities(Collections.emptyList())
58
+ .build();
59
+
60
+ UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
61
+ userDetails, null, userDetails.getAuthorities());
62
+
63
+ SecurityContextHolder.getContext().setAuthentication(authToken);
64
+ }
65
+ } catch (Exception e) {
66
+ // Token invalid or expired — continue without setting authentication
67
+ }
68
+
69
+ filterChain.doFilter(request, response);
70
+ }
71
+ }
@@ -0,0 +1,35 @@
1
+ package {{packageName}}.adapters.outbound.security;
2
+
3
+ import org.springframework.context.annotation.Bean;
4
+ import org.springframework.context.annotation.Configuration;
5
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
7
+ import org.springframework.security.config.http.SessionCreationPolicy;
8
+ import org.springframework.security.web.SecurityFilterChain;
9
+ import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
10
+
11
+ @Configuration
12
+ @EnableWebSecurity
13
+ public class SecurityConfig {
14
+
15
+ private final JwtFilter jwtFilter;
16
+
17
+ public SecurityConfig(JwtFilter jwtFilter) {
18
+ this.jwtFilter = jwtFilter;
19
+ }
20
+
21
+ @Bean
22
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
23
+ return http
24
+ .csrf(csrf -> csrf.disable())
25
+ .authorizeHttpRequests(auth -> auth
26
+ .requestMatchers("/api/auth/**").permitAll()
27
+ .requestMatchers("/api/payments/webhook").permitAll()
28
+ .requestMatchers("/actuator/**").permitAll()
29
+ .anyRequest().authenticated()
30
+ )
31
+ .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
32
+ .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
33
+ .build();
34
+ }
35
+ }
@@ -23,7 +23,7 @@ public class PaymentService {
23
23
  }
24
24
 
25
25
  public String createCheckoutSession(String userId, String priceId) throws Exception {
26
- User user = userRepository.findById(java.util.UUID.fromString(userId))
26
+ User user = userRepository.findById(userId)
27
27
  .orElseThrow(() -> new RuntimeException("User not found"));
28
28
 
29
29
  String customerId = user.getStripeCustomerId();
@@ -39,7 +39,7 @@ public class PaymentService {
39
39
  }
40
40
 
41
41
  public String createPortalSession(String userId) throws Exception {
42
- User user = userRepository.findById(java.util.UUID.fromString(userId))
42
+ User user = userRepository.findById(userId)
43
43
  .orElseThrow(() -> new RuntimeException("User not found"));
44
44
 
45
45
  if (user.getStripeCustomerId() == null) {
@@ -57,7 +57,7 @@ public class PaymentService {
57
57
  Session session = (Session) event.getDataObjectDeserializer().getObject().orElse(null);
58
58
  if (session != null && session.getClientReferenceId() != null) {
59
59
  String userId = session.getClientReferenceId();
60
- userRepository.findById(java.util.UUID.fromString(userId)).ifPresent(user -> {
60
+ userRepository.findById(userId).ifPresent(user -> {
61
61
  user.setStripeCustomerId(session.getCustomer());
62
62
  userRepository.save(user);
63
63
  });
@@ -1,7 +1,7 @@
1
1
  spring.application.name={{projectNameKebabCase}}
2
2
 
3
3
  # Database Configuration
4
- spring.datasource.url=jdbc:postgresql://postgres:5432/{{projectNameKebabCase}}
4
+ spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:5432/{{projectNameKebabCase}}
5
5
  spring.datasource.username=postgres
6
6
  spring.datasource.password=postgres
7
7
  spring.datasource.driver-class-name=org.postgresql.Driver
@@ -13,13 +13,13 @@ spring.jpa.show-sql=true
13
13
  spring.jpa.properties.hibernate.format_sql=true
14
14
 
15
15
  # JWT
16
- application.security.jwt.secret-key={{jwtSecretKey}}
16
+ application.security.jwt.secret-key=${JWT_SECRET:{{jwtSecretKey}}}
17
17
  application.security.jwt.expiration=86400000
18
18
  application.security.jwt.refresh-token.expiration=604800000
19
19
 
20
20
  # Stripe
21
- stripe.secret-key=${STRIPE_SECRET_KEY}
22
- stripe.webhook-secret=${STRIPE_WEBHOOK_SECRET}
21
+ stripe.secret-key=${STRIPE_SECRET_KEY:sk_test_dummy}
22
+ stripe.webhook-secret=${STRIPE_WEBHOOK_SECRET:whsec_dummy}
23
23
 
24
24
  # Frontend URL (for Stripe redirect URLs)
25
25
  frontend.url=${FRONTEND_URL:http://localhost:3000}
@@ -0,0 +1,72 @@
1
+ # Compiled class files
2
+ *.class
3
+
4
+ # Log files
5
+ *.log
6
+
7
+ # Package files
8
+ *.jar
9
+ *.war
10
+ *.nar
11
+ *.ear
12
+ *.zip
13
+ *.tar.gz
14
+ *.rar
15
+
16
+ # Virtual machine crash logs
17
+ hs_err_pid*
18
+ replay_pid*
19
+
20
+ # Maven
21
+ target/
22
+ .mvn/wrapper/maven-wrapper.jar
23
+ !**/src/main/**/target/
24
+ !**/src/test/**/target/
25
+
26
+ # Gradle
27
+ .gradle
28
+ build/
29
+ !gradle/wrapper/gradle-wrapper.jar
30
+ !**/src/main/**/build/
31
+ !**/src/test/**/build/
32
+
33
+ # Spring Boot
34
+ spring-shell.log
35
+
36
+ # STS / Eclipse
37
+ .apt_generated
38
+ .classpath
39
+ .factorypath
40
+ .project
41
+ .settings
42
+ .springBeans
43
+ .sts4-cache
44
+
45
+ # IntelliJ IDEA
46
+ .idea/
47
+ *.iws
48
+ *.iml
49
+ *.ipr
50
+
51
+ # VS Code
52
+ .vscode/
53
+
54
+ # NetBeans
55
+ /nbproject/private/
56
+ /nbbuild/
57
+ /nbdist/
58
+ /.nb-gradle/
59
+
60
+ # Environment
61
+ .env
62
+ .env.local
63
+ .env.*.local
64
+ !.env.example
65
+ application-local.yml
66
+ application-local.properties
67
+ application-dev.yml
68
+ application-dev.properties
69
+
70
+ # OS
71
+ .DS_Store
72
+ Thumbs.db
@@ -1,7 +1,5 @@
1
- version: '3.8'
2
-
3
1
  services:
4
- postgres:
2
+ db:
5
3
  image: postgres:15-alpine
6
4
  container_name: {{projectNameKebabCase}}-db
7
5
  environment:
@@ -13,6 +11,11 @@ services:
13
11
  volumes:
14
12
  - postgres_data:/var/lib/postgresql/data
15
13
  restart: unless-stopped
14
+ healthcheck:
15
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
16
+ interval: 10s
17
+ timeout: 5s
18
+ retries: 5
16
19
 
17
20
  volumes:
18
21
  postgres_data:
@@ -27,18 +27,19 @@ public class SecurityConfig {
27
27
  .csrf(csrf -> csrf.disable())
28
28
  .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
29
29
  .authorizeHttpRequests(auth -> auth
30
- .requestMatchers("/api/auth/**").permitAll()
31
- .requestMatchers("/api/payments/webhook").permitAll()
32
- .requestMatchers("/actuator/health").permitAll()
33
- .anyRequest().authenticated()
34
- )
35
- .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
30
+ .requestMatchers("/api/auth/**").permitAll()
31
+ .requestMatchers("/api/payments/webhook").permitAll()
32
+ .requestMatchers("/api/health").permitAll()
33
+ .requestMatchers("/actuator/health").permitAll()
34
+ .anyRequest().authenticated()
35
+ )
36
+ .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
36
37
 
37
- return http.build();
38
- }
38
+ return http.build();
39
+ }
39
40
 
40
- @Bean
41
- public PasswordEncoder passwordEncoder() {
42
- return new BCryptPasswordEncoder();
41
+ @Bean
42
+ public PasswordEncoder passwordEncoder() {
43
+ return new BCryptPasswordEncoder();
44
+ }
43
45
  }
44
- }
@@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.*;
10
10
  import org.springframework.security.core.context.SecurityContextHolder;
11
11
  import org.springframework.security.core.Authentication;
12
12
 
13
+ import java.util.HashMap;
13
14
  import java.util.Map;
14
15
 
15
16
  @RestController
@@ -48,17 +49,17 @@ public class AuthController {
48
49
  if (authentication == null || !authentication.isAuthenticated()) {
49
50
  return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
50
51
  }
51
-
52
+
52
53
  try {
53
- String userId = (String) authentication.getPrincipal(); // Assuming custom jwt filter sets principal to id
54
+ String userId = (String) authentication.getPrincipal();
54
55
  User user = authService.getMe(userId);
55
- return ResponseEntity.ok(Map.of(
56
- "id", user.getId(),
57
- "email", user.getEmail(),
58
- "name", user.getName()
59
- ));
56
+ // Use HashMap instead of Map.of() — tolerates null values (e.g. name may be null)
57
+ Map<String, Object> result = new HashMap<>();
58
+ result.put("id", user.getId());
59
+ result.put("email", user.getEmail());
60
+ result.put("name", user.getName());
61
+ return ResponseEntity.ok(result);
60
62
  } catch (Exception e) {
61
- // Keep original behavior if principal isn't id
62
63
  return ResponseEntity.ok(Map.of("message", "Authenticated"));
63
64
  }
64
65
  }
@@ -6,7 +6,6 @@ import org.slf4j.LoggerFactory;
6
6
  import org.springframework.http.HttpStatus;
7
7
  import org.springframework.http.ResponseEntity;
8
8
  import org.springframework.security.core.annotation.AuthenticationPrincipal;
9
- import org.springframework.security.core.userdetails.UserDetails;
10
9
  import org.springframework.web.bind.annotation.*;
11
10
 
12
11
  import java.util.Map;
@@ -29,16 +28,16 @@ public class PaymentsController {
29
28
  */
30
29
  @PostMapping("/checkout")
31
30
  public ResponseEntity<?> createCheckout(
32
- @AuthenticationPrincipal UserDetails userDetails,
31
+ @AuthenticationPrincipal String userId,
33
32
  @RequestBody Map<String, String> body) {
34
33
  try {
35
34
  String priceId = body.get("priceId");
36
35
  if (priceId == null || priceId.isEmpty()) {
37
36
  return ResponseEntity.badRequest().body(Map.of("error", "priceId is required"));
38
37
  }
39
- // userDetails.getUsername() returns the user ID (set in JWT filter)
38
+ // userId is set directly in SecurityContextHolder by JwtAuthenticationFilter
40
39
  com.stripe.model.checkout.Session session =
41
- stripeService.createCheckoutSession(userDetails.getUsername(), priceId);
40
+ stripeService.createCheckoutSession(userId, priceId);
42
41
  return ResponseEntity.ok(Map.of("url", session.getUrl()));
43
42
  } catch (Exception e) {
44
43
  logger.error("Error creating checkout session", e);
@@ -51,10 +50,10 @@ public class PaymentsController {
51
50
  * Requires authentication. Opens Stripe Billing Portal.
52
51
  */
53
52
  @PostMapping("/portal")
54
- public ResponseEntity<?> createPortal(@AuthenticationPrincipal UserDetails userDetails) {
53
+ public ResponseEntity<?> createPortal(@AuthenticationPrincipal String userId) {
55
54
  try {
56
55
  com.stripe.model.billingportal.Session session =
57
- stripeService.createPortalSession(userDetails.getUsername());
56
+ stripeService.createPortalSession(userId);
58
57
  return ResponseEntity.ok(Map.of("url", session.getUrl()));
59
58
  } catch (Exception e) {
60
59
  logger.error("Error creating portal session", e);
@@ -45,7 +45,7 @@ public class StripeService {
45
45
  * Retrieve or create a Stripe customer for the given user, then open a checkout session.
46
46
  */
47
47
  public Session createCheckoutSession(String userId, String priceId) throws StripeException {
48
- User user = userRepository.findById(java.util.UUID.fromString(userId))
48
+ User user = userRepository.findById(userId)
49
49
  .orElseThrow(() -> new RuntimeException("User not found"));
50
50
 
51
51
  String customerId = user.getStripeCustomerId();
@@ -81,7 +81,7 @@ public class StripeService {
81
81
  * Open the Stripe Billing Portal for the given customer.
82
82
  */
83
83
  public com.stripe.model.billingportal.Session createPortalSession(String userId) throws StripeException {
84
- User user = userRepository.findById(java.util.UUID.fromString(userId))
84
+ User user = userRepository.findById(userId)
85
85
  .orElseThrow(() -> new RuntimeException("User not found"));
86
86
 
87
87
  if (user.getStripeCustomerId() == null) {
@@ -113,7 +113,7 @@ public class StripeService {
113
113
  Session session = (Session) event.getDataObjectDeserializer().getObject().orElse(null);
114
114
  if (session != null && session.getClientReferenceId() != null) {
115
115
  String userId = session.getClientReferenceId();
116
- userRepository.findById(java.util.UUID.fromString(userId)).ifPresent(user -> {
116
+ userRepository.findById(userId).ifPresent(user -> {
117
117
  user.setStripeCustomerId(session.getCustomer());
118
118
  userRepository.save(user);
119
119
  });
@@ -1,32 +1,35 @@
1
1
  spring:
2
2
  application:
3
3
  name: {{projectNameKebabCase}}
4
-
5
- datasource:
6
- url: jdbc:postgresql://localhost:5432/{{projectNameSnakeCase}}
7
- username: postgres
8
- password: postgres
9
- driver-class-name: org.postgresql.Driver
10
-
11
- jpa:
12
- hibernate:
13
- ddl-auto: update
14
- show-sql: true
15
- properties:
16
- hibernate:
17
- format_sql: true
18
- dialect: org.hibernate.dialect.PostgreSQLDialect
4
+ datasource:
5
+ url: jdbc:postgresql://localhost:5432/{{projectNameSnakeCase}}
6
+ username: postgres
7
+ password: postgres
8
+ driver-class-name: org.postgresql.Driver
9
+ jpa:
10
+ hibernate:
11
+ ddl-auto: update
12
+ show-sql: true
13
+ properties:
14
+ hibernate:
15
+ format_sql: true
16
+ dialect: org.hibernate.dialect.PostgreSQLDialect
19
17
 
20
- # H2 Console (for development)
21
- h2:
22
- console:
23
- enabled: true
24
- path: /h2-console
18
+ server:
19
+ port: 8080
25
20
 
26
- server:
27
- port: 8080
21
+ logging:
22
+ level:
23
+ root: INFO
24
+ {{packageName}}: DEBUG
28
25
 
29
- logging:
30
- level:
31
- root: INFO
32
- {{packageName}}: DEBUG
26
+ jwt:
27
+ secret: ${JWT_SECRET:{{jwtSecretKey}}}
28
+ expiration: 604800000
29
+
30
+ stripe:
31
+ secret-key: ${STRIPE_SECRET_KEY:sk_test_dummy}
32
+ webhook-secret: ${STRIPE_WEBHOOK_SECRET:whsec_dummy}
33
+
34
+ frontend:
35
+ url: ${FRONTEND_URL:http://localhost:3000}