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.
- package/package.json +2 -2
- package/templates/java-spring/clean/infra/main.tf.hbs +42 -18
- package/templates/java-spring/clean/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/java-spring/clean/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/java-spring/clean/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/java-spring/hexagonal/infra/main.tf.hbs +42 -18
- package/templates/java-spring/hexagonal/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/java-spring/hexagonal/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/java-spring/hexagonal/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/java-spring/mvc/infra/main.tf.hbs +42 -18
- package/templates/java-spring/mvc/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/java-spring/mvc/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/java-spring/mvc/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/AuthController.java.hbs +38 -42
- package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/ItemController.java.hbs +42 -0
- package/templates/java-spring/mvc/src/main/java/{{packagePath}}/controller/PaymentsController.java.hbs +65 -22
- package/templates/java-spring/mvc/src/main/java/{{packagePath}}/model/Item.java.hbs +38 -0
- package/templates/java-spring/mvc/src/main/java/{{packagePath}}/model/User.java.hbs +41 -0
- package/templates/java-spring/mvc/src/main/java/{{packagePath}}/repository/ItemRepository.java.hbs +9 -0
- package/templates/java-spring/mvc/src/main/java/{{packagePath}}/repository/UserRepository.java.hbs +13 -0
- package/templates/java-spring/mvc/src/main/java/{{packagePath}}/service/AuthService.java.hbs +62 -0
- package/templates/java-spring/mvc/src/main/java/{{packagePath}}/service/StripeService.java.hbs +18 -18
- package/templates/java-spring/mvc/src/main/java/{{packagePath}}/{{projectNamePascalCase}}Application.java.hbs +2 -0
- package/templates/nestjs/clean/infra/main.tf.hbs +42 -18
- package/templates/nestjs/clean/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/nestjs/clean/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/nestjs/clean/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/nestjs/hexagonal/infra/main.tf.hbs +42 -18
- package/templates/nestjs/hexagonal/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/nestjs/hexagonal/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/nestjs/hexagonal/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/nestjs/mvc/infra/main.tf.hbs +42 -18
- package/templates/nestjs/mvc/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/nestjs/mvc/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/nestjs/mvc/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/nestjs/mvc/package.json.hbs +6 -2
- package/templates/nestjs/mvc/prisma/schema.prisma.hbs +31 -0
- package/templates/nestjs/mvc/src/app.module.ts.hbs +3 -1
- package/templates/nestjs/mvc/src/auth/auth.service.ts.hbs +34 -31
- package/templates/nestjs/mvc/src/payments/payments.service.ts.hbs +26 -6
- package/templates/nestjs/mvc/src/prisma/prisma.module.ts.hbs +9 -0
- package/templates/nestjs/mvc/src/prisma/prisma.service.ts.hbs +15 -0
- package/templates/nestjs/mvc/src/services/items.service.ts.hbs +33 -20
- package/templates/nextjs/mvc/infra/main.tf.hbs +42 -18
- package/templates/nextjs/mvc/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/nextjs/mvc/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/nextjs/mvc/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/nextjs/mvc/package.json.hbs +1 -0
- package/templates/nextjs/mvc/prisma/schema.prisma.hbs +60 -6
- package/templates/nextjs/mvc/src/app/api/webhook/route.ts.hbs +23 -18
- package/templates/nodejs-express/clean/infra/main.tf.hbs +42 -18
- package/templates/nodejs-express/clean/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/nodejs-express/clean/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/nodejs-express/clean/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/nodejs-express/hexagonal/infra/main.tf.hbs +42 -18
- package/templates/nodejs-express/hexagonal/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/nodejs-express/hexagonal/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/nodejs-express/hexagonal/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/nodejs-express/mvc/infra/main.tf.hbs +42 -18
- package/templates/nodejs-express/mvc/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/nodejs-express/mvc/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/nodejs-express/mvc/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/nodejs-express/mvc/package.json.hbs +8 -4
- package/templates/nodejs-express/mvc/prisma/schema.prisma.hbs +31 -0
- package/templates/nodejs-express/mvc/src/config/database.ts.hbs +2 -9
- package/templates/nodejs-express/mvc/src/controllers/auth.controller.ts.hbs +40 -58
- package/templates/nodejs-express/mvc/src/controllers/items.controller.ts.hbs +29 -0
- package/templates/nodejs-express/mvc/src/models/README.md.hbs +10 -0
- package/templates/nodejs-express/mvc/src/prisma/client.ts.hbs +3 -0
- package/templates/nodejs-express/mvc/src/services/auth.service.ts.hbs +71 -0
- package/templates/nodejs-express/mvc/src/services/stripe.service.ts.hbs +35 -25
- package/templates/python-fastapi/clean/infra/main.tf.hbs +42 -18
- package/templates/python-fastapi/clean/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/python-fastapi/clean/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/python-fastapi/clean/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/python-fastapi/hexagonal/infra/main.tf.hbs +42 -18
- package/templates/python-fastapi/hexagonal/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/python-fastapi/hexagonal/infra/modules/rds/main.tf.hbs +15 -15
- package/templates/python-fastapi/hexagonal/infra/modules/vpc/main.tf.hbs +170 -30
- package/templates/python-fastapi/mvc/app/controllers/auth.py.hbs +25 -16
- package/templates/python-fastapi/mvc/app/controllers/items.py.hbs +9 -7
- package/templates/python-fastapi/mvc/app/controllers/payments.py.hbs +42 -15
- package/templates/python-fastapi/mvc/app/database.py.hbs +17 -0
- package/templates/python-fastapi/mvc/app/main.py.hbs +4 -0
- package/templates/python-fastapi/mvc/app/models/item.py.hbs +11 -8
- package/templates/python-fastapi/mvc/app/models/user.py.hbs +15 -0
- package/templates/python-fastapi/mvc/app/repositories/item_repository.py.hbs +15 -0
- package/templates/python-fastapi/mvc/app/repositories/user_repository.py.hbs +15 -0
- package/templates/python-fastapi/mvc/app/services/item_service.py.hbs +17 -19
- package/templates/python-fastapi/mvc/infra/main.tf.hbs +42 -18
- package/templates/python-fastapi/mvc/infra/modules/ecs/main.tf.hbs +217 -6
- package/templates/python-fastapi/mvc/infra/modules/rds/main.tf.hbs +15 -15
- 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
|
|
13
|
+
cidr_block = "10.0.0.0/16"
|
|
14
14
|
enable_dns_hostnames = true
|
|
15
|
-
enable_dns_support
|
|
15
|
+
enable_dns_support = true
|
|
16
16
|
|
|
17
17
|
tags = {
|
|
18
|
-
Name
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
41
|
-
vpc_id
|
|
42
|
-
cidr_block
|
|
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
|
|
107
|
+
Name = "${var.app_name}-${var.environment}-private-${count.index + 1}"
|
|
47
108
|
Environment = var.environment
|
|
48
109
|
}
|
|
49
110
|
}
|
|
50
111
|
|
|
51
|
-
#
|
|
52
|
-
resource "
|
|
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
|
|
122
|
+
Name = "${var.app_name}-${var.environment}-private-rt"
|
|
57
123
|
Environment = var.environment
|
|
58
124
|
}
|
|
59
125
|
}
|
|
60
126
|
|
|
61
|
-
#
|
|
62
|
-
|
|
63
|
-
|
|
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
|
|
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
|
|
199
|
+
name = "${var.app_name}-${var.environment}-db-sg"
|
|
69
200
|
description = "Security group for database"
|
|
70
|
-
vpc_id
|
|
201
|
+
vpc_id = aws_vpc.main.id
|
|
71
202
|
|
|
72
203
|
ingress {
|
|
73
|
-
from_port
|
|
74
|
-
to_port
|
|
75
|
-
protocol
|
|
76
|
-
|
|
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
|
|
81
|
-
to_port
|
|
82
|
-
protocol
|
|
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
|
|
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
|
|
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
|
|
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
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
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,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();
|