kybernus 2.1.0 → 2.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 (175) hide show
  1. package/node_modules/{@isaacs/balanced-match → balanced-match}/README.md +7 -10
  2. package/node_modules/{@isaacs/balanced-match → balanced-match}/package.json +5 -16
  3. package/node_modules/{@isaacs/brace-expansion → brace-expansion}/README.md +2 -5
  4. package/node_modules/{@isaacs/brace-expansion → brace-expansion}/dist/commonjs/index.js +1 -1
  5. package/node_modules/{@isaacs/brace-expansion → brace-expansion}/dist/commonjs/index.js.map +1 -1
  6. package/node_modules/{@isaacs/brace-expansion → brace-expansion}/dist/esm/index.js +1 -1
  7. package/node_modules/{@isaacs/brace-expansion → brace-expansion}/dist/esm/index.js.map +1 -1
  8. package/node_modules/{@isaacs/brace-expansion → brace-expansion}/package.json +9 -5
  9. package/node_modules/glob/dist/commonjs/glob.d.ts +8 -0
  10. package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
  11. package/node_modules/glob/dist/commonjs/glob.js +2 -1
  12. package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
  13. package/node_modules/glob/dist/commonjs/index.min.js +4 -0
  14. package/node_modules/glob/dist/commonjs/index.min.js.map +7 -0
  15. package/node_modules/glob/dist/commonjs/pattern.d.ts +3 -0
  16. package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
  17. package/node_modules/glob/dist/commonjs/pattern.js +4 -0
  18. package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
  19. package/node_modules/glob/dist/esm/glob.d.ts +8 -0
  20. package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
  21. package/node_modules/glob/dist/esm/glob.js +2 -1
  22. package/node_modules/glob/dist/esm/glob.js.map +1 -1
  23. package/node_modules/glob/dist/esm/index.min.js +4 -0
  24. package/node_modules/glob/dist/esm/index.min.js.map +7 -0
  25. package/node_modules/glob/dist/esm/pattern.d.ts +3 -0
  26. package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
  27. package/node_modules/glob/dist/esm/pattern.js +4 -0
  28. package/node_modules/glob/dist/esm/pattern.js.map +1 -1
  29. package/node_modules/glob/package.json +30 -10
  30. package/node_modules/lru-cache/package.json +7 -7
  31. package/node_modules/minimatch/README.md +3 -1
  32. package/node_modules/minimatch/dist/commonjs/ast.d.ts.map +1 -1
  33. package/node_modules/minimatch/dist/commonjs/ast.js +37 -27
  34. package/node_modules/minimatch/dist/commonjs/ast.js.map +1 -1
  35. package/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +1 -1
  36. package/node_modules/minimatch/dist/commonjs/brace-expressions.js +2 -4
  37. package/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +1 -1
  38. package/node_modules/minimatch/dist/commonjs/escape.js +4 -4
  39. package/node_modules/minimatch/dist/commonjs/escape.js.map +1 -1
  40. package/node_modules/minimatch/dist/commonjs/index.d.ts +50 -0
  41. package/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -1
  42. package/node_modules/minimatch/dist/commonjs/index.js +37 -31
  43. package/node_modules/minimatch/dist/commonjs/index.js.map +1 -1
  44. package/node_modules/minimatch/dist/commonjs/unescape.js +4 -4
  45. package/node_modules/minimatch/dist/commonjs/unescape.js.map +1 -1
  46. package/node_modules/minimatch/dist/esm/ast.d.ts.map +1 -1
  47. package/node_modules/minimatch/dist/esm/ast.js +37 -27
  48. package/node_modules/minimatch/dist/esm/ast.js.map +1 -1
  49. package/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +1 -1
  50. package/node_modules/minimatch/dist/esm/brace-expressions.js +2 -4
  51. package/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
  52. package/node_modules/minimatch/dist/esm/escape.js +4 -4
  53. package/node_modules/minimatch/dist/esm/escape.js.map +1 -1
  54. package/node_modules/minimatch/dist/esm/index.d.ts +50 -0
  55. package/node_modules/minimatch/dist/esm/index.d.ts.map +1 -1
  56. package/node_modules/minimatch/dist/esm/index.js +37 -31
  57. package/node_modules/minimatch/dist/esm/index.js.map +1 -1
  58. package/node_modules/minimatch/dist/esm/unescape.js +4 -4
  59. package/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
  60. package/node_modules/minimatch/package.json +3 -3
  61. package/node_modules/minipass/LICENSE.md +55 -0
  62. package/node_modules/minipass/dist/commonjs/index.d.ts +12 -16
  63. package/node_modules/minipass/dist/commonjs/index.d.ts.map +1 -1
  64. package/node_modules/minipass/dist/commonjs/index.js +13 -3
  65. package/node_modules/minipass/dist/commonjs/index.js.map +1 -1
  66. package/node_modules/minipass/dist/esm/index.d.ts +12 -16
  67. package/node_modules/minipass/dist/esm/index.d.ts.map +1 -1
  68. package/node_modules/minipass/dist/esm/index.js +3 -1
  69. package/node_modules/minipass/dist/esm/index.js.map +1 -1
  70. package/node_modules/minipass/package.json +9 -14
  71. package/node_modules/rimraf/README.md +29 -0
  72. package/node_modules/rimraf/dist/commonjs/fs.d.ts +9 -8
  73. package/node_modules/rimraf/dist/commonjs/fs.d.ts.map +1 -1
  74. package/node_modules/rimraf/dist/commonjs/index.d.ts.map +1 -1
  75. package/node_modules/rimraf/dist/commonjs/index.js +9 -3
  76. package/node_modules/rimraf/dist/commonjs/index.js.map +1 -1
  77. package/node_modules/rimraf/dist/commonjs/opt-arg.d.ts.map +1 -1
  78. package/node_modules/rimraf/dist/commonjs/opt-arg.js +2 -1
  79. package/node_modules/rimraf/dist/commonjs/opt-arg.js.map +1 -1
  80. package/node_modules/rimraf/dist/commonjs/path-arg.d.ts.map +1 -1
  81. package/node_modules/rimraf/dist/commonjs/path-arg.js +2 -1
  82. package/node_modules/rimraf/dist/commonjs/path-arg.js.map +1 -1
  83. package/node_modules/rimraf/dist/commonjs/readdir-or-error.d.ts +2 -2
  84. package/node_modules/rimraf/dist/commonjs/readdir-or-error.d.ts.map +1 -1
  85. package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.d.ts.map +1 -1
  86. package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.js.map +1 -1
  87. package/node_modules/rimraf/dist/commonjs/rimraf-posix.d.ts.map +1 -1
  88. package/node_modules/rimraf/dist/commonjs/rimraf-posix.js +1 -2
  89. package/node_modules/rimraf/dist/commonjs/rimraf-posix.js.map +1 -1
  90. package/node_modules/rimraf/dist/commonjs/rimraf-windows.d.ts.map +1 -1
  91. package/node_modules/rimraf/dist/commonjs/rimraf-windows.js.map +1 -1
  92. package/node_modules/rimraf/dist/esm/bin.mjs.map +1 -1
  93. package/node_modules/rimraf/dist/esm/fs.d.ts +9 -8
  94. package/node_modules/rimraf/dist/esm/fs.d.ts.map +1 -1
  95. package/node_modules/rimraf/dist/esm/index.d.ts.map +1 -1
  96. package/node_modules/rimraf/dist/esm/index.js +10 -4
  97. package/node_modules/rimraf/dist/esm/index.js.map +1 -1
  98. package/node_modules/rimraf/dist/esm/opt-arg.d.ts.map +1 -1
  99. package/node_modules/rimraf/dist/esm/opt-arg.js +2 -1
  100. package/node_modules/rimraf/dist/esm/opt-arg.js.map +1 -1
  101. package/node_modules/rimraf/dist/esm/path-arg.d.ts.map +1 -1
  102. package/node_modules/rimraf/dist/esm/path-arg.js +2 -1
  103. package/node_modules/rimraf/dist/esm/path-arg.js.map +1 -1
  104. package/node_modules/rimraf/dist/esm/readdir-or-error.d.ts +2 -2
  105. package/node_modules/rimraf/dist/esm/readdir-or-error.d.ts.map +1 -1
  106. package/node_modules/rimraf/dist/esm/rimraf-move-remove.d.ts.map +1 -1
  107. package/node_modules/rimraf/dist/esm/rimraf-move-remove.js +1 -1
  108. package/node_modules/rimraf/dist/esm/rimraf-move-remove.js.map +1 -1
  109. package/node_modules/rimraf/dist/esm/rimraf-posix.d.ts.map +1 -1
  110. package/node_modules/rimraf/dist/esm/rimraf-posix.js +1 -2
  111. package/node_modules/rimraf/dist/esm/rimraf-posix.js.map +1 -1
  112. package/node_modules/rimraf/dist/esm/rimraf-windows.d.ts.map +1 -1
  113. package/node_modules/rimraf/dist/esm/rimraf-windows.js +1 -1
  114. package/node_modules/rimraf/dist/esm/rimraf-windows.js.map +1 -1
  115. package/node_modules/rimraf/package.json +4 -19
  116. package/package.json +2 -2
  117. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/AuthController.java.hbs +38 -42
  118. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/ItemController.java.hbs +42 -0
  119. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/PaymentsController.java.hbs +65 -22
  120. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/model/Item.java.hbs +38 -0
  121. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/model/User.java.hbs +41 -0
  122. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/repository/ItemRepository.java.hbs +9 -0
  123. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/repository/UserRepository.java.hbs +13 -0
  124. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/service/AuthService.java.hbs +62 -0
  125. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/service/StripeService.java.hbs +18 -18
  126. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/{{projectNamePascalCase}}Application.java.hbs +2 -0
  127. package/templates/nestjs/mvc/package.json.hbs +6 -2
  128. package/templates/nestjs/mvc/prisma/schema.prisma.hbs +31 -0
  129. package/templates/nestjs/mvc/src/app.module.ts.hbs +3 -1
  130. package/templates/nestjs/mvc/src/auth/auth.service.ts.hbs +34 -31
  131. package/templates/nestjs/mvc/src/payments/payments.service.ts.hbs +26 -6
  132. package/templates/nestjs/mvc/src/prisma/prisma.module.ts.hbs +9 -0
  133. package/templates/nestjs/mvc/src/prisma/prisma.service.ts.hbs +15 -0
  134. package/templates/nestjs/mvc/src/services/items.service.ts.hbs +33 -20
  135. package/templates/nextjs/mvc/package.json.hbs +1 -0
  136. package/templates/nextjs/mvc/prisma/schema.prisma.hbs +60 -6
  137. package/templates/nextjs/mvc/src/app/api/webhook/route.ts.hbs +23 -18
  138. package/templates/nodejs-express/mvc/package.json.hbs +8 -4
  139. package/templates/nodejs-express/mvc/prisma/schema.prisma.hbs +31 -0
  140. package/templates/nodejs-express/mvc/src/config/database.ts.hbs +2 -9
  141. package/templates/nodejs-express/mvc/src/controllers/auth.controller.ts.hbs +40 -58
  142. package/templates/nodejs-express/mvc/src/controllers/items.controller.ts.hbs +29 -0
  143. package/templates/nodejs-express/mvc/src/models/README.md.hbs +10 -0
  144. package/templates/nodejs-express/mvc/src/prisma/client.ts.hbs +3 -0
  145. package/templates/nodejs-express/mvc/src/services/auth.service.ts.hbs +71 -0
  146. package/templates/nodejs-express/mvc/src/services/stripe.service.ts.hbs +35 -25
  147. package/templates/python-fastapi/mvc/app/controllers/auth.py.hbs +25 -16
  148. package/templates/python-fastapi/mvc/app/controllers/items.py.hbs +9 -7
  149. package/templates/python-fastapi/mvc/app/controllers/payments.py.hbs +42 -15
  150. package/templates/python-fastapi/mvc/app/database.py.hbs +17 -0
  151. package/templates/python-fastapi/mvc/app/main.py.hbs +4 -0
  152. package/templates/python-fastapi/mvc/app/models/item.py.hbs +11 -8
  153. package/templates/python-fastapi/mvc/app/models/user.py.hbs +15 -0
  154. package/templates/python-fastapi/mvc/app/repositories/item_repository.py.hbs +15 -0
  155. package/templates/python-fastapi/mvc/app/repositories/user_repository.py.hbs +15 -0
  156. package/templates/python-fastapi/mvc/app/services/item_service.py.hbs +17 -19
  157. package/node_modules/minipass/LICENSE +0 -15
  158. /package/node_modules/{@isaacs/balanced-match → balanced-match}/LICENSE.md +0 -0
  159. /package/node_modules/{@isaacs/balanced-match → balanced-match}/dist/commonjs/index.d.ts +0 -0
  160. /package/node_modules/{@isaacs/balanced-match → balanced-match}/dist/commonjs/index.d.ts.map +0 -0
  161. /package/node_modules/{@isaacs/balanced-match → balanced-match}/dist/commonjs/index.js +0 -0
  162. /package/node_modules/{@isaacs/balanced-match → balanced-match}/dist/commonjs/index.js.map +0 -0
  163. /package/node_modules/{@isaacs/balanced-match → balanced-match}/dist/commonjs/package.json +0 -0
  164. /package/node_modules/{@isaacs/balanced-match → balanced-match}/dist/esm/index.d.ts +0 -0
  165. /package/node_modules/{@isaacs/balanced-match → balanced-match}/dist/esm/index.d.ts.map +0 -0
  166. /package/node_modules/{@isaacs/balanced-match → balanced-match}/dist/esm/index.js +0 -0
  167. /package/node_modules/{@isaacs/balanced-match → balanced-match}/dist/esm/index.js.map +0 -0
  168. /package/node_modules/{@isaacs/balanced-match → balanced-match}/dist/esm/package.json +0 -0
  169. /package/node_modules/{@isaacs/brace-expansion → brace-expansion}/LICENSE +0 -0
  170. /package/node_modules/{@isaacs/brace-expansion → brace-expansion}/dist/commonjs/index.d.ts +0 -0
  171. /package/node_modules/{@isaacs/brace-expansion → brace-expansion}/dist/commonjs/index.d.ts.map +0 -0
  172. /package/node_modules/{@isaacs/brace-expansion → brace-expansion}/dist/commonjs/package.json +0 -0
  173. /package/node_modules/{@isaacs/brace-expansion → brace-expansion}/dist/esm/index.d.ts +0 -0
  174. /package/node_modules/{@isaacs/brace-expansion → brace-expansion}/dist/esm/index.d.ts.map +0 -0
  175. /package/node_modules/{@isaacs/brace-expansion → brace-expansion}/dist/esm/package.json +0 -0
@@ -1,5 +1,6 @@
1
1
  import { NextRequest, NextResponse } from "next/server";
2
2
  import Stripe from "stripe";
3
+ import { prisma } from "@/lib/prisma";
3
4
 
4
5
  const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
5
6
  apiVersion: "2025-12-15.clover",
@@ -16,35 +17,39 @@ export async function POST(request: NextRequest) {
16
17
  try {
17
18
  event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
18
19
  } catch (err: any) {
19
- console.error();
20
+ console.error("Webhook signature verification failed.", err.message);
20
21
  return NextResponse.json({ error: "Invalid signature" }, { status: 400 });
21
22
  }
22
23
 
23
24
  switch (event.type) {
24
25
  case "checkout.session.completed":
25
- const session = event.data.object as Stripe.Checkout.Session;
26
- // TODO: Fulfill the purchase
27
- console.log("Checkout completed:", session.id);
28
- break;
26
+ const session = event.data.object as Stripe.Checkout.Session;
27
+ console.log("Checkout completed:", session.id);
28
+ // Example: Update user's stripeCustomerId
29
+ // if (session.client_reference_id) {
30
+ // await prisma.user.update({
31
+ // where: { id: session.client_reference_id },
32
+ // data: { stripeCustomerId: session.customer as string }
33
+ // });
34
+ // }
35
+ break;
29
36
 
30
- case "customer.subscription.created":
31
37
  case "customer.subscription.updated":
32
- const subscription = event.data.object as Stripe.Subscription;
33
- // TODO: Update user subscription status in database
34
- console.log("Subscription updated:", subscription.id);
35
- break;
38
+ const subscription = event.data.object as Stripe.Subscription;
39
+ console.log("Subscription updated:", subscription.id);
40
+ // TODO: Update user subscription status in database
41
+ break;
36
42
 
37
43
  case "customer.subscription.deleted":
38
- const deletedSubscription = event.data.object as Stripe.Subscription;
39
- // TODO: Handle subscription cancellation
40
- console.log("Subscription deleted:", deletedSubscription.id);
41
- break;
44
+ const deletedSubscription = event.data.object as Stripe.Subscription;
45
+ console.log("Subscription deleted:", deletedSubscription.id);
46
+ // TODO: Handle subscription cancellation in database
47
+ break;
42
48
 
43
49
  case "invoice.payment_failed":
44
- const invoice = event.data.object as Stripe.Invoice;
45
- // TODO: Handle failed payment
46
- console.log("Payment failed:", invoice.id);
47
- break;
50
+ const invoice = event.data.object as Stripe.Invoice;
51
+ console.log("Payment failed:", invoice.id);
52
+ break;
48
53
  }
49
54
 
50
55
  return NextResponse.json({ received: true });
@@ -9,7 +9,9 @@
9
9
  "start": "node dist/index.js",
10
10
  "lint": "eslint src --ext .ts",
11
11
  "format": "prettier --write \"src/**/*.ts\"",
12
- "test": "jest"
12
+ "test": "jest",
13
+ "db:generate": "prisma generate",
14
+ "db:push": "prisma db push"
13
15
  },
14
16
  "keywords": [
15
17
  "express",
@@ -30,7 +32,8 @@
30
32
  "morgan": "^1.10.0",
31
33
  "jsonwebtoken": "^9.0.2",
32
34
  "bcryptjs": "^2.4.3",
33
- "stripe": "^14.14.0"
35
+ "stripe": "^14.14.0",
36
+ "@prisma/client": "^5.10.2"
34
37
  },
35
38
  "devDependencies": {
36
39
  "@types/express": "^4.17.21",
@@ -47,9 +50,10 @@
47
50
  "@typescript-eslint/parser": "^6.21.0",
48
51
  "prettier": "^3.2.5",
49
52
  "jest": "^29.7.0",
50
- "@types/jest": "^29.5.12"
53
+ "@types/jest": "^29.5.12",
54
+ "prisma": "^5.10.2"
51
55
  },
52
56
  "engines": {
53
57
  "node": ">=18.0.0"
54
58
  }
55
- }
59
+ }
@@ -0,0 +1,31 @@
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ }
4
+
5
+ datasource db {
6
+ provider = "postgresql"
7
+ url = env("DATABASE_URL")
8
+ }
9
+
10
+ model User {
11
+ id String @id @default(uuid())
12
+ email String @unique
13
+ name String?
14
+ password String
15
+ stripeCustomerId String? @map("stripe_customer_id")
16
+ createdAt DateTime @default(now()) @map("created_at")
17
+ updatedAt DateTime @updatedAt @map("updated_at")
18
+
19
+ @@map("users")
20
+ }
21
+
22
+ model Item {
23
+ id String @id @default(uuid())
24
+ name String
25
+ description String?
26
+ price Float?
27
+ createdAt DateTime @default(now()) @map("created_at")
28
+ updatedAt DateTime @updatedAt @map("updated_at")
29
+
30
+ @@map("items")
31
+ }
@@ -1,10 +1,3 @@
1
- /**
2
- * Database configuration
3
- *
4
- * Add your database connection logic here
5
- * Example with PostgreSQL / Prisma / TypeORM
6
- */
1
+ import { PrismaClient } from '@prisma/client';
7
2
 
8
- export const databaseConfig = {
9
- url: process.env.DATABASE_URL || 'postgresql://localhost:5432/{{snakeCase projectName}}',
10
- };
3
+ export const prisma = new PrismaClient();
@@ -1,55 +1,36 @@
1
1
  import { Router, Request, Response } from 'express';
2
- import jwt from 'jsonwebtoken';
3
- import bcrypt from 'bcryptjs';
2
+ import { authService } from '../services/auth.service';
4
3
  import { authMiddleware, AuthRequest } from '../middlewares/auth.middleware';
5
4
 
6
5
  const router = Router();
7
6
 
8
- // In-memory users store (replace with database in production)
9
- const users: { id: string; email: string; password: string }[] = [];
10
-
11
7
  /**
12
- * @route POST /api/auth/register
13
- * @desc Register a new user
14
- */
8
+ * @route POST /api/auth/register
9
+ * @desc Register a new user
10
+ */
15
11
  router.post('/register', async (req: Request, res: Response) => {
16
12
  try {
17
- const { email, password } = req.body;
13
+ const { email, name, password } = req.body;
18
14
 
19
15
  if (!email || !password) {
20
16
  return res.status(400).json({ error: 'Email and password are required' });
21
17
  }
22
18
 
23
- const existingUser = users.find(u => u.email === email);
24
- if (existingUser) {
25
- return res.status(400).json({ error: 'User already exists' });
19
+ const result = await authService.register(email, name, password);
20
+ res.status(201).json(result);
21
+ } catch (error: any) {
22
+ console.error('Registration error:', error);
23
+ if (error.message === 'User already exists') {
24
+ return res.status(400).json({ error: error.message });
26
25
  }
27
-
28
- const hashedPassword = await bcrypt.hash(password, 10);
29
- const user = {
30
- id: Date.now().toString(),
31
- email,
32
- password: hashedPassword,
33
- };
34
-
35
- users.push(user);
36
-
37
- const token = jwt.sign(
38
- { id: user.id, email: user.email },
39
- process.env.JWT_SECRET || 'your-secret-key',
40
- { expiresIn: '7d' }
41
- );
42
-
43
- res.status(201).json({ token, user: { id: user.id, email: user.email } });
44
- } catch (error) {
45
26
  res.status(500).json({ error: 'Internal server error' });
46
27
  }
47
28
  });
48
29
 
49
30
  /**
50
- * @route POST /api/auth/login
51
- * @desc Authenticate user and return token
52
- */
31
+ * @route POST /api/auth/login
32
+ * @desc Authenticate user and return token
33
+ */
53
34
  router.post('/login', async (req: Request, res: Response) => {
54
35
  try {
55
36
  const { email, password } = req.body;
@@ -58,34 +39,35 @@ router.post('/login', async (req: Request, res: Response) => {
58
39
  return res.status(400).json({ error: 'Email and password are required' });
59
40
  }
60
41
 
61
- const user = users.find(u => u.email === email);
62
- if (!user) {
63
- return res.status(401).json({ error: 'Invalid credentials' });
64
- }
65
-
66
- const isValidPassword = await bcrypt.compare(password, user.password);
67
- if (!isValidPassword) {
68
- return res.status(401).json({ error: 'Invalid credentials' });
69
- }
70
-
71
- const token = jwt.sign(
72
- { id: user.id, email: user.email },
73
- process.env.JWT_SECRET || 'your-secret-key',
74
- { expiresIn: '7d' }
75
- );
76
-
77
- res.json({ token, user: { id: user.id, email: user.email } });
78
- } catch (error) {
79
- res.status(500).json({ error: 'Internal server error' });
42
+ const result = await authService.login(email, password);
43
+ res.json(result);
44
+ } catch (error: any) {
45
+ console.error('Login error:', error);
46
+ if (error.message === 'Invalid credentials') {
47
+ return res.status(401).json({ error: error.message });
48
+ }
49
+ res.status(500).json({ error: 'Internal server error' });
80
50
  }
81
51
  });
82
52
 
83
53
  /**
84
- * @route GET /api/auth/me
85
- * @desc Get current user info
86
- */
87
- router.get('/me', authMiddleware, (req: AuthRequest, res: Response) => {
88
- res.json({ user: req.user });
54
+ * @route GET /api/auth/me
55
+ * @desc Get current user info
56
+ */
57
+ router.get('/me', authMiddleware, async (req: AuthRequest, res: Response) => {
58
+ try {
59
+ if (!req.user?.id) {
60
+ return res.status(401).json({ error: 'Unauthorized' });
61
+ }
62
+
63
+ const user = await authService.getMe(req.user.id);
64
+ res.json({ user });
65
+ } catch (error: any) {
66
+ if (error.message === 'User not found') {
67
+ return res.status(404).json({ error: error.message });
68
+ }
69
+ res.status(500).json({ error: 'Internal server error' });
70
+ }
89
71
  });
90
72
 
91
- export default router;
73
+ export default router;
@@ -0,0 +1,29 @@
1
+ import { Router, Request, Response } from 'express';
2
+ import { prisma } from '../prisma/client';
3
+
4
+ const router = Router();
5
+
6
+ // Basic CRUD for Items using the new structure
7
+
8
+ router.get('/', async (req: Request, res: Response) => {
9
+ try {
10
+ const items = await prisma.item.findMany();
11
+ res.json(items);
12
+ } catch (error) {
13
+ res.status(500).json({ error: 'Internal server error' });
14
+ }
15
+ });
16
+
17
+ router.post('/', async (req: Request, res: Response) => {
18
+ try {
19
+ const { name, description, price } = req.body;
20
+ const item = await prisma.item.create({
21
+ data: { name, description, price }
22
+ });
23
+ res.status(201).json(item);
24
+ } catch (error) {
25
+ res.status(500).json({ error: 'Internal server error' });
26
+ }
27
+ });
28
+
29
+ export default router;
@@ -0,0 +1,10 @@
1
+ # Models Directory
2
+
3
+ In an MVC application using Prisma, the true database models are defined centrally in `prisma/schema.prisma`.
4
+
5
+ This `models/` directory is typically used for:
6
+ 1. **Interfaces and Types**: TypeScript interfaces for data structures that don't directly map to the database (e.g., API response structures, complex DTOs).
7
+ 2. **Business Logic Models**: domain-driven models if your application requires a thicker model layer than what Prisma Client provides by default.
8
+ 3. **Mongoose/Sequelize**: If you were to swap Prisma out for an ODM like Mongoose or another ORM like Sequelize, those definitions would live here.
9
+
10
+ Since we are using Prisma, you can simply import types directly generated by Prisma Client (e.g., `import { User, Item } from '@prisma/client'`) where needed.
@@ -0,0 +1,3 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+
3
+ export const prisma = new PrismaClient();
@@ -0,0 +1,71 @@
1
+ import jwt from 'jsonwebtoken';
2
+ import bcrypt from 'bcryptjs';
3
+ import { prisma } from '../prisma/client';
4
+
5
+ export class AuthService {
6
+ async register(email: string, name: string, password: string) {
7
+ const existingUser = await prisma.user.findUnique({
8
+ where: { email }
9
+ });
10
+
11
+ if (existingUser) {
12
+ throw new Error('User already exists');
13
+ }
14
+
15
+ const hashedPassword = await bcrypt.hash(password, 10);
16
+
17
+ const user = await prisma.user.create({
18
+ data: {
19
+ email,
20
+ name,
21
+ password: hashedPassword
22
+ }
23
+ });
24
+
25
+ const token = jwt.sign(
26
+ { id: user.id, email: user.email },
27
+ process.env.JWT_SECRET || 'your-secret-key',
28
+ { expiresIn: '7d' }
29
+ );
30
+
31
+ return { token, user: { id: user.id, email: user.email, name: user.name } };
32
+ }
33
+
34
+ async login(email: string, password: string) {
35
+ const user = await prisma.user.findUnique({
36
+ where: { email }
37
+ });
38
+
39
+ if (!user) {
40
+ throw new Error('Invalid credentials');
41
+ }
42
+
43
+ const isValidPassword = await bcrypt.compare(password, user.password);
44
+ if (!isValidPassword) {
45
+ throw new Error('Invalid credentials');
46
+ }
47
+
48
+ const token = jwt.sign(
49
+ { id: user.id, email: user.email },
50
+ process.env.JWT_SECRET || 'your-secret-key',
51
+ { expiresIn: '7d' }
52
+ );
53
+
54
+ return { token, user: { id: user.id, email: user.email, name: user.name } };
55
+ }
56
+
57
+ async getMe(userId: string) {
58
+ const user = await prisma.user.findUnique({
59
+ where: { id: userId },
60
+ select: { id: true, email: true, name: true }
61
+ });
62
+
63
+ if (!user) {
64
+ throw new Error('User not found');
65
+ }
66
+
67
+ return user;
68
+ }
69
+ }
70
+
71
+ export const authService = new AuthService();
@@ -1,4 +1,5 @@
1
1
  import Stripe from 'stripe';
2
+ import { prisma } from '../config/database';
2
3
 
3
4
  const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || '', {
4
5
  apiVersion: '2024-12-18.acacia',
@@ -13,8 +14,8 @@ export interface CreateCheckoutSessionParams {
13
14
 
14
15
  export class StripeService {
15
16
  /**
16
- * Create a checkout session for subscription
17
- */
17
+ * Create a checkout session for subscription
18
+ */
18
19
  async createCheckoutSession(params: CreateCheckoutSessionParams) {
19
20
  const session = await stripe.checkout.sessions.create({
20
21
  mode: 'subscription',
@@ -34,8 +35,8 @@ export class StripeService {
34
35
  }
35
36
 
36
37
  /**
37
- * Create a customer portal session
38
- */
38
+ * Create a customer portal session
39
+ */
39
40
  async createPortalSession(customerId: string, returnUrl: string) {
40
41
  const session = await stripe.billingPortal.sessions.create({
41
42
  customer: customerId,
@@ -46,8 +47,8 @@ export class StripeService {
46
47
  }
47
48
 
48
49
  /**
49
- * Handle webhook event
50
- */
50
+ * Handle webhook event
51
+ */
51
52
  async handleWebhook(rawBody: Buffer, signature: string) {
52
53
  const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET || '';
53
54
 
@@ -59,36 +60,45 @@ export class StripeService {
59
60
 
60
61
  switch (event.type) {
61
62
  case 'checkout.session.completed':
62
- const session = event.data.object;
63
- // Handle successful subscription
64
- console.log('Checkout completed:', session.id);
65
- break;
63
+ {
64
+ const session = event.data.object as Stripe.Checkout.Session;
65
+ // Handle successful subscription
66
+ console.log('Checkout completed:', session.id);
67
+ // Match to user and update DB, e.g., using session.client_reference_id
68
+ }
69
+ break;
66
70
 
67
71
  case 'customer.subscription.updated':
68
- const subscription = event.data.object;
69
- // Handle subscription update
70
- console.log('Subscription updated:', subscription.id);
71
- break;
72
+ {
73
+ const subscription = event.data.object as Stripe.Subscription;
74
+ // Handle subscription update in DB
75
+ console.log('Subscription updated:', subscription.id);
76
+ }
77
+ break;
72
78
 
73
79
  case 'customer.subscription.deleted':
74
- const deletedSubscription = event.data.object;
75
- // Handle subscription cancellation
76
- console.log('Subscription deleted:', deletedSubscription.id);
77
- break;
80
+ {
81
+ const deletedSubscription = event.data.object as Stripe.Subscription;
82
+ // Handle subscription cancellation in DB
83
+ console.log('Subscription deleted:', deletedSubscription.id);
84
+ }
85
+ break;
78
86
 
79
87
  case 'invoice.payment_failed':
80
- const invoice = event.data.object;
81
- // Handle failed payment
82
- console.log('Payment failed:', invoice.id);
83
- break;
88
+ {
89
+ const invoice = event.data.object as Stripe.Invoice;
90
+ // Handle failed payment
91
+ console.log('Payment failed:', invoice.id);
92
+ }
93
+ break;
84
94
  }
85
95
 
86
96
  return { received: true };
87
97
  }
88
98
 
89
99
  /**
90
- * Create a Stripe customer
91
- */
100
+ * Create a Stripe customer
101
+ */
92
102
  async createCustomer(email: string, name?: string) {
93
103
  const customer = await stripe.customers.create({
94
104
  email,
@@ -99,4 +109,4 @@ export class StripeService {
99
109
  }
100
110
  }
101
111
 
102
- export const stripeService = new StripeService();
112
+ export const stripeService = new StripeService();
@@ -1,11 +1,13 @@
1
1
  from fastapi import APIRouter, HTTPException, Depends
2
+ from sqlalchemy.orm import Session
2
3
  from pydantic import BaseModel, EmailStr
3
4
  from app.middleware.security import hash_password, verify_password, create_access_token, get_current_user
5
+ from app.database import get_db
6
+ from app.models.user import User
7
+ from app.repositories.user_repository import UserRepository
4
8
 
5
9
  router = APIRouter()
6
-
7
- # In-memory user store (replace with database)
8
- users_db: dict = {}
10
+ user_repo = UserRepository()
9
11
 
10
12
  class UserRegister(BaseModel):
11
13
  email: EmailStr
@@ -21,26 +23,33 @@ class AuthResponse(BaseModel):
21
23
  user: dict
22
24
 
23
25
  @router.post("/register", response_model=AuthResponse)
24
- async def register(data: UserRegister):
25
- if data.email in users_db:
26
+ async def register(data: UserRegister, db: Session = Depends(get_db)):
27
+ existing_user = user_repo.get_by_email(db, data.email)
28
+ if existing_user:
26
29
  raise HTTPException(status_code=400, detail="User already exists")
27
30
 
28
31
  hashed = hash_password(data.password)
29
- user = {"id": str(len(users_db) + 1), "email": data.email, "name": data.name, "password": hashed}
30
- users_db[data.email] = user
32
+ new_user = User(email=data.email, name=data.name, password=hashed)
33
+
34
+ user = user_repo.create(db, new_user)
31
35
 
32
- token = create_access_token({"sub": user["id"], "email": user["email"]})
33
- return {"token": token, "user": {"id": user["id"], "email": user["email"], "name": user["name"]}}
36
+ token = create_access_token({"sub": user.id, "email": user.email})
37
+ return {"token": token, "user": {"id": user.id, "email": user.email, "name": user.name}}
34
38
 
35
39
  @router.post("/login", response_model=AuthResponse)
36
- async def login(data: UserLogin):
37
- user = users_db.get(data.email)
38
- if not user or not verify_password(data.password, user["password"]):
40
+ async def login(data: UserLogin, db: Session = Depends(get_db)):
41
+ user = user_repo.get_by_email(db, data.email)
42
+
43
+ if not user or not verify_password(data.password, user.password):
39
44
  raise HTTPException(status_code=401, detail="Invalid credentials")
40
45
 
41
- token = create_access_token({"sub": user["id"], "email": user["email"]})
42
- return {"token": token, "user": {"id": user["id"], "email": user["email"], "name": user["name"]}}
46
+ token = create_access_token({"sub": user.id, "email": user.email})
47
+ return {"token": token, "user": {"id": user.id, "email": user.email, "name": user.name}}
43
48
 
44
49
  @router.get("/me")
45
- async def get_me(current_user: dict = Depends(get_current_user)):
46
- return {"user": current_user}
50
+ async def get_me(current_user: dict = Depends(get_current_user), db: Session = Depends(get_db)):
51
+ user = user_repo.get_by_id(db, current_user["id"])
52
+ if not user:
53
+ raise HTTPException(status_code=404, detail="User not found")
54
+
55
+ return {"user": {"id": user.id, "email": user.email, "name": user.name}}
@@ -1,21 +1,23 @@
1
- from fastapi import APIRouter, HTTPException
1
+ from fastapi import APIRouter, HTTPException, Depends
2
+ from sqlalchemy.orm import Session
2
3
  from app.services.item_service import ItemService
3
4
  from app.schemas.item import ItemCreate, ItemResponse
5
+ from app.database import get_db
4
6
 
5
7
  router = APIRouter()
6
8
  service = ItemService()
7
9
 
8
10
  @router.get("/", response_model=list[ItemResponse])
9
- async def list_items():
10
- return service.list_items()
11
+ async def list_items(db: Session = Depends(get_db)):
12
+ return service.list_items(db)
11
13
 
12
14
  @router.post("/", response_model=ItemResponse, status_code=201)
13
- async def create_item(item: ItemCreate):
14
- return service.create_item(item)
15
+ async def create_item(item: ItemCreate, db: Session = Depends(get_db)):
16
+ return service.create_item(item, db)
15
17
 
16
18
  @router.get("/{item_id}", response_model=ItemResponse)
17
- async def get_item(item_id: str):
18
- item = service.get_item(item_id)
19
+ async def get_item(item_id: str, db: Session = Depends(get_db)):
20
+ item = service.get_item(item_id, db)
19
21
  if not item:
20
22
  raise HTTPException(status_code=404, detail="Item not found")
21
23
  return item