kybernus 2.1.1 → 2.2.1

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 (93) hide show
  1. package/package.json +2 -2
  2. package/templates/java-spring/clean/infra/main.tf.hbs +42 -18
  3. package/templates/java-spring/clean/infra/modules/ecs/main.tf.hbs +217 -6
  4. package/templates/java-spring/clean/infra/modules/rds/main.tf.hbs +15 -15
  5. package/templates/java-spring/clean/infra/modules/vpc/main.tf.hbs +170 -30
  6. package/templates/java-spring/hexagonal/infra/main.tf.hbs +42 -18
  7. package/templates/java-spring/hexagonal/infra/modules/ecs/main.tf.hbs +217 -6
  8. package/templates/java-spring/hexagonal/infra/modules/rds/main.tf.hbs +15 -15
  9. package/templates/java-spring/hexagonal/infra/modules/vpc/main.tf.hbs +170 -30
  10. package/templates/java-spring/mvc/infra/main.tf.hbs +42 -18
  11. package/templates/java-spring/mvc/infra/modules/ecs/main.tf.hbs +217 -6
  12. package/templates/java-spring/mvc/infra/modules/rds/main.tf.hbs +15 -15
  13. package/templates/java-spring/mvc/infra/modules/vpc/main.tf.hbs +170 -30
  14. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/AuthController.java.hbs +38 -42
  15. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/ItemController.java.hbs +42 -0
  16. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/PaymentsController.java.hbs +65 -22
  17. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/model/Item.java.hbs +38 -0
  18. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/model/User.java.hbs +41 -0
  19. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/repository/ItemRepository.java.hbs +9 -0
  20. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/repository/UserRepository.java.hbs +13 -0
  21. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/service/AuthService.java.hbs +62 -0
  22. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/service/StripeService.java.hbs +18 -18
  23. package/templates/java-spring/mvc/src/main/java/{{packagePath}}/{{projectNamePascalCase}}Application.java.hbs +2 -0
  24. package/templates/nestjs/clean/infra/main.tf.hbs +42 -18
  25. package/templates/nestjs/clean/infra/modules/ecs/main.tf.hbs +217 -6
  26. package/templates/nestjs/clean/infra/modules/rds/main.tf.hbs +15 -15
  27. package/templates/nestjs/clean/infra/modules/vpc/main.tf.hbs +170 -30
  28. package/templates/nestjs/hexagonal/infra/main.tf.hbs +42 -18
  29. package/templates/nestjs/hexagonal/infra/modules/ecs/main.tf.hbs +217 -6
  30. package/templates/nestjs/hexagonal/infra/modules/rds/main.tf.hbs +15 -15
  31. package/templates/nestjs/hexagonal/infra/modules/vpc/main.tf.hbs +170 -30
  32. package/templates/nestjs/mvc/infra/main.tf.hbs +42 -18
  33. package/templates/nestjs/mvc/infra/modules/ecs/main.tf.hbs +217 -6
  34. package/templates/nestjs/mvc/infra/modules/rds/main.tf.hbs +15 -15
  35. package/templates/nestjs/mvc/infra/modules/vpc/main.tf.hbs +170 -30
  36. package/templates/nestjs/mvc/package.json.hbs +6 -2
  37. package/templates/nestjs/mvc/prisma/schema.prisma.hbs +31 -0
  38. package/templates/nestjs/mvc/src/app.module.ts.hbs +3 -1
  39. package/templates/nestjs/mvc/src/auth/auth.service.ts.hbs +34 -31
  40. package/templates/nestjs/mvc/src/payments/payments.service.ts.hbs +26 -6
  41. package/templates/nestjs/mvc/src/prisma/prisma.module.ts.hbs +9 -0
  42. package/templates/nestjs/mvc/src/prisma/prisma.service.ts.hbs +15 -0
  43. package/templates/nestjs/mvc/src/services/items.service.ts.hbs +33 -20
  44. package/templates/nextjs/mvc/infra/main.tf.hbs +42 -18
  45. package/templates/nextjs/mvc/infra/modules/ecs/main.tf.hbs +217 -6
  46. package/templates/nextjs/mvc/infra/modules/rds/main.tf.hbs +15 -15
  47. package/templates/nextjs/mvc/infra/modules/vpc/main.tf.hbs +170 -30
  48. package/templates/nextjs/mvc/package.json.hbs +1 -0
  49. package/templates/nextjs/mvc/prisma/schema.prisma.hbs +60 -6
  50. package/templates/nextjs/mvc/src/app/api/webhook/route.ts.hbs +23 -18
  51. package/templates/nodejs-express/clean/infra/main.tf.hbs +42 -18
  52. package/templates/nodejs-express/clean/infra/modules/ecs/main.tf.hbs +217 -6
  53. package/templates/nodejs-express/clean/infra/modules/rds/main.tf.hbs +15 -15
  54. package/templates/nodejs-express/clean/infra/modules/vpc/main.tf.hbs +170 -30
  55. package/templates/nodejs-express/hexagonal/infra/main.tf.hbs +42 -18
  56. package/templates/nodejs-express/hexagonal/infra/modules/ecs/main.tf.hbs +217 -6
  57. package/templates/nodejs-express/hexagonal/infra/modules/rds/main.tf.hbs +15 -15
  58. package/templates/nodejs-express/hexagonal/infra/modules/vpc/main.tf.hbs +170 -30
  59. package/templates/nodejs-express/mvc/infra/main.tf.hbs +42 -18
  60. package/templates/nodejs-express/mvc/infra/modules/ecs/main.tf.hbs +217 -6
  61. package/templates/nodejs-express/mvc/infra/modules/rds/main.tf.hbs +15 -15
  62. package/templates/nodejs-express/mvc/infra/modules/vpc/main.tf.hbs +170 -30
  63. package/templates/nodejs-express/mvc/package.json.hbs +8 -4
  64. package/templates/nodejs-express/mvc/prisma/schema.prisma.hbs +31 -0
  65. package/templates/nodejs-express/mvc/src/config/database.ts.hbs +2 -9
  66. package/templates/nodejs-express/mvc/src/controllers/auth.controller.ts.hbs +40 -58
  67. package/templates/nodejs-express/mvc/src/controllers/items.controller.ts.hbs +29 -0
  68. package/templates/nodejs-express/mvc/src/models/README.md.hbs +10 -0
  69. package/templates/nodejs-express/mvc/src/prisma/client.ts.hbs +3 -0
  70. package/templates/nodejs-express/mvc/src/services/auth.service.ts.hbs +71 -0
  71. package/templates/nodejs-express/mvc/src/services/stripe.service.ts.hbs +35 -25
  72. package/templates/python-fastapi/clean/infra/main.tf.hbs +42 -18
  73. package/templates/python-fastapi/clean/infra/modules/ecs/main.tf.hbs +217 -6
  74. package/templates/python-fastapi/clean/infra/modules/rds/main.tf.hbs +15 -15
  75. package/templates/python-fastapi/clean/infra/modules/vpc/main.tf.hbs +170 -30
  76. package/templates/python-fastapi/hexagonal/infra/main.tf.hbs +42 -18
  77. package/templates/python-fastapi/hexagonal/infra/modules/ecs/main.tf.hbs +217 -6
  78. package/templates/python-fastapi/hexagonal/infra/modules/rds/main.tf.hbs +15 -15
  79. package/templates/python-fastapi/hexagonal/infra/modules/vpc/main.tf.hbs +170 -30
  80. package/templates/python-fastapi/mvc/app/controllers/auth.py.hbs +25 -16
  81. package/templates/python-fastapi/mvc/app/controllers/items.py.hbs +9 -7
  82. package/templates/python-fastapi/mvc/app/controllers/payments.py.hbs +42 -15
  83. package/templates/python-fastapi/mvc/app/database.py.hbs +17 -0
  84. package/templates/python-fastapi/mvc/app/main.py.hbs +4 -0
  85. package/templates/python-fastapi/mvc/app/models/item.py.hbs +11 -8
  86. package/templates/python-fastapi/mvc/app/models/user.py.hbs +15 -0
  87. package/templates/python-fastapi/mvc/app/repositories/item_repository.py.hbs +15 -0
  88. package/templates/python-fastapi/mvc/app/repositories/user_repository.py.hbs +15 -0
  89. package/templates/python-fastapi/mvc/app/services/item_service.py.hbs +17 -19
  90. package/templates/python-fastapi/mvc/infra/main.tf.hbs +42 -18
  91. package/templates/python-fastapi/mvc/infra/modules/ecs/main.tf.hbs +217 -6
  92. package/templates/python-fastapi/mvc/infra/modules/rds/main.tf.hbs +15 -15
  93. package/templates/python-fastapi/mvc/infra/modules/vpc/main.tf.hbs +170 -30
@@ -10,81 +10,213 @@ variable "environment" {
10
10
 
11
11
  # VPC
12
12
  resource "aws_vpc" "main" {
13
- cidr_block = "10.0.0.0/16"
13
+ cidr_block = "10.0.0.0/16"
14
14
  enable_dns_hostnames = true
15
- enable_dns_support = true
15
+ enable_dns_support = true
16
16
 
17
17
  tags = {
18
- Name = "${var.app_name}-${var.environment}-vpc"
18
+ Name = "${var.app_name}-${var.environment}-vpc"
19
19
  Environment = var.environment
20
20
  }
21
21
  }
22
22
 
23
+ # Internet Gateway
24
+ resource "aws_internet_gateway" "main" {
25
+ vpc_id = aws_vpc.main.id
26
+
27
+ tags = {
28
+ Name = "${var.app_name}-${var.environment}-igw"
29
+ Environment = var.environment
30
+ }
31
+ }
32
+
33
+ # Data source for AZs
34
+ data "aws_availability_zones" "available" {
35
+ state = "available"
36
+ }
37
+
23
38
  # Public Subnets
24
39
  resource "aws_subnet" "public" {
25
- count = 2
40
+ count = 2
41
+ vpc_id = aws_vpc.main.id
42
+ cidr_block = "10.0.${count.index + 1}.0/24"
43
+ availability_zone = data.aws_availability_zones.available.names[count.index]
44
+ map_public_ip_on_launch = true
45
+
46
+ tags = {
47
+ Name = "${var.app_name}-${var.environment}-public-${count.index + 1}"
48
+ Environment = var.environment
49
+ }
50
+ }
51
+
52
+ # Route Table for Public Subnets
53
+ resource "aws_route_table" "public" {
26
54
  vpc_id = aws_vpc.main.id
27
- cidr_block = "10.0.${count.index + 1}.0/24"
28
- availability_zone = data.aws_availability_zones.available.names[count.index]
29
55
 
30
- map_public_ip_on_launch = true
56
+ route {
57
+ cidr_block = "0.0.0.0/0"
58
+ gateway_id = aws_internet_gateway.main.id
59
+ }
60
+
61
+ tags = {
62
+ Name = "${var.app_name}-${var.environment}-public-rt"
63
+ Environment = var.environment
64
+ }
65
+ }
66
+
67
+ # Association for Public Subnets
68
+ resource "aws_route_table_association" "public" {
69
+ count = 2
70
+ subnet_id = aws_subnet.public[count.index].id
71
+ route_table_id = aws_route_table.public.id
72
+ }
73
+
74
+ # Elastic IP for NAT Gateway
75
+ resource "aws_eip" "nat" {
76
+ count = 1
77
+ domain = "vpc"
31
78
 
32
79
  tags = {
33
- Name = "${var.app_name}-${var.environment}-public-${count.index + 1}"
80
+ Name = "${var.app_name}-${var.environment}-nat-eip"
81
+ Environment = var.environment
82
+ }
83
+ }
84
+
85
+ # NAT Gateway (single NAT for cost savings, can change to 1 per AZ for production if needed)
86
+ resource "aws_nat_gateway" "main" {
87
+ count = 1
88
+ allocation_id = aws_eip.nat[0].id
89
+ subnet_id = aws_subnet.public[0].id
90
+
91
+ depends_on = [aws_internet_gateway.main]
92
+
93
+ tags = {
94
+ Name = "${var.app_name}-${var.environment}-nat"
34
95
  Environment = var.environment
35
96
  }
36
97
  }
37
98
 
38
99
  # Private Subnets
39
100
  resource "aws_subnet" "private" {
40
- count = 2
41
- vpc_id = aws_vpc.main.id
42
- cidr_block = "10.0.${count.index + 10}.0/24"
101
+ count = 2
102
+ vpc_id = aws_vpc.main.id
103
+ cidr_block = "10.0.${count.index + 10}.0/24"
43
104
  availability_zone = data.aws_availability_zones.available.names[count.index]
44
105
 
45
106
  tags = {
46
- Name = "${var.app_name}-${var.environment}-private-${count.index + 1}"
107
+ Name = "${var.app_name}-${var.environment}-private-${count.index + 1}"
47
108
  Environment = var.environment
48
109
  }
49
110
  }
50
111
 
51
- # Internet Gateway
52
- resource "aws_internet_gateway" "main" {
112
+ # Route Table for Private Subnets
113
+ resource "aws_route_table" "private" {
53
114
  vpc_id = aws_vpc.main.id
54
115
 
116
+ route {
117
+ cidr_block = "0.0.0.0/0"
118
+ nat_gateway_id = aws_nat_gateway.main[0].id
119
+ }
120
+
55
121
  tags = {
56
- Name = "${var.app_name}-${var.environment}-igw"
122
+ Name = "${var.app_name}-${var.environment}-private-rt"
57
123
  Environment = var.environment
58
124
  }
59
125
  }
60
126
 
61
- # Data source for AZs
62
- data "aws_availability_zones" "available" {
63
- state = "available"
127
+ # Association for Private Subnets
128
+ resource "aws_route_table_association" "private" {
129
+ count = 2
130
+ subnet_id = aws_subnet.private[count.index].id
131
+ route_table_id = aws_route_table.private.id
132
+ }
133
+
134
+ # Security Group for Load Balancer (ALB)
135
+ resource "aws_security_group" "alb" {
136
+ name = "${var.app_name}-${var.environment}-alb-sg"
137
+ description = "Security group for ALB"
138
+ vpc_id = aws_vpc.main.id
139
+
140
+ ingress {
141
+ from_port = 80
142
+ to_port = 80
143
+ protocol = "tcp"
144
+ cidr_blocks = ["0.0.0.0/0"]
145
+ description = "Allow HTTP from anywhere"
146
+ }
147
+
148
+ ingress {
149
+ from_port = 443
150
+ to_port = 443
151
+ protocol = "tcp"
152
+ cidr_blocks = ["0.0.0.0/0"]
153
+ description = "Allow HTTPS from anywhere"
154
+ }
155
+
156
+ egress {
157
+ from_port = 0
158
+ to_port = 0
159
+ protocol = "-1"
160
+ cidr_blocks = ["0.0.0.0/0"]
161
+ }
162
+
163
+ tags = {
164
+ Name = "${var.app_name}-${var.environment}-alb-sg"
165
+ Environment = var.environment
166
+ }
64
167
  }
65
168
 
66
- # Security Group for DB
169
+ # Security Group for ECS Tasks
170
+ resource "aws_security_group" "ecs_tasks" {
171
+ name = "${var.app_name}-${var.environment}-ecs-tasks-sg"
172
+ description = "Security group for ECS tasks"
173
+ vpc_id = aws_vpc.main.id
174
+
175
+ ingress {
176
+ from_port = 0
177
+ to_port = 0
178
+ protocol = "-1"
179
+ security_groups = [aws_security_group.alb.id]
180
+ description = "Allow all traffic from ALB"
181
+ }
182
+
183
+ egress {
184
+ from_port = 0
185
+ to_port = 0
186
+ protocol = "-1"
187
+ cidr_blocks = ["0.0.0.0/0"]
188
+ description = "Allow all outbound traffic"
189
+ }
190
+
191
+ tags = {
192
+ Name = "${var.app_name}-${var.environment}-ecs-tasks-sg"
193
+ Environment = var.environment
194
+ }
195
+ }
196
+
197
+ # Security Group for Database (RDS)
67
198
  resource "aws_security_group" "db" {
68
- name = "${var.app_name}-${var.environment}-db-sg"
199
+ name = "${var.app_name}-${var.environment}-db-sg"
69
200
  description = "Security group for database"
70
- vpc_id = aws_vpc.main.id
201
+ vpc_id = aws_vpc.main.id
71
202
 
72
203
  ingress {
73
- from_port = 5432
74
- to_port = 5432
75
- protocol = "tcp"
76
- cidr_blocks = ["10.0.0.0/16"]
204
+ from_port = 5432
205
+ to_port = 5432
206
+ protocol = "tcp"
207
+ security_groups = [aws_security_group.ecs_tasks.id]
208
+ description = "Allow PostgreSQL access from ECS tasks"
77
209
  }
78
210
 
79
211
  egress {
80
- from_port = 0
81
- to_port = 0
82
- protocol = "-1"
212
+ from_port = 0
213
+ to_port = 0
214
+ protocol = "-1"
83
215
  cidr_blocks = ["0.0.0.0/0"]
84
216
  }
85
217
 
86
218
  tags = {
87
- Name = "${var.app_name}-${var.environment}-db-sg"
219
+ Name = "${var.app_name}-${var.environment}-db-sg"
88
220
  Environment = var.environment
89
221
  }
90
222
  }
@@ -104,4 +236,12 @@ output "private_subnet_ids" {
104
236
 
105
237
  output "db_security_group_id" {
106
238
  value = aws_security_group.db.id
107
- }
239
+ }
240
+
241
+ output "alb_security_group_id" {
242
+ value = aws_security_group.alb.id
243
+ }
244
+
245
+ output "ecs_tasks_security_group_id" {
246
+ value = aws_security_group.ecs_tasks.id
247
+ }
@@ -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();