@bloomneo/appkit 1.2.9
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/LICENSE +21 -0
- package/README.md +902 -0
- package/bin/appkit.js +71 -0
- package/bin/commands/generate.js +1050 -0
- package/bin/templates/backend/README.md.template +39 -0
- package/bin/templates/backend/api.http.template +0 -0
- package/bin/templates/backend/docs/APPKIT_CLI.md +507 -0
- package/bin/templates/backend/docs/APPKIT_COMMENTS_GUIDELINES.md +61 -0
- package/bin/templates/backend/docs/APPKIT_LLM_GUIDE.md +2539 -0
- package/bin/templates/backend/package.json.template +34 -0
- package/bin/templates/backend/src/api/features/welcome/welcome.http.template +29 -0
- package/bin/templates/backend/src/api/features/welcome/welcome.route.ts.template +36 -0
- package/bin/templates/backend/src/api/features/welcome/welcome.service.ts.template +88 -0
- package/bin/templates/backend/src/api/features/welcome/welcome.types.ts.template +18 -0
- package/bin/templates/backend/src/api/lib/api-router.ts.template +84 -0
- package/bin/templates/backend/src/api/server.ts.template +188 -0
- package/bin/templates/backend/tsconfig.api.json.template +24 -0
- package/bin/templates/backend/tsconfig.json.template +40 -0
- package/bin/templates/feature/feature.http.template +63 -0
- package/bin/templates/feature/feature.route.ts.template +36 -0
- package/bin/templates/feature/feature.service.ts.template +81 -0
- package/bin/templates/feature/feature.types.ts.template +23 -0
- package/bin/templates/feature-db/feature.http.template +63 -0
- package/bin/templates/feature-db/feature.model.ts.template +74 -0
- package/bin/templates/feature-db/feature.route.ts.template +58 -0
- package/bin/templates/feature-db/feature.service.ts.template +231 -0
- package/bin/templates/feature-db/feature.types.ts.template +25 -0
- package/bin/templates/feature-db/schema-addition.prisma.template +9 -0
- package/bin/templates/feature-db/seeding/README.md.template +57 -0
- package/bin/templates/feature-db/seeding/feature.seed.js.template +67 -0
- package/bin/templates/feature-user/schema-addition.prisma.template +19 -0
- package/bin/templates/feature-user/user.http.template +157 -0
- package/bin/templates/feature-user/user.model.ts.template +244 -0
- package/bin/templates/feature-user/user.route.ts.template +379 -0
- package/bin/templates/feature-user/user.seed.js.template +182 -0
- package/bin/templates/feature-user/user.service.ts.template +426 -0
- package/bin/templates/feature-user/user.types.ts.template +127 -0
- package/dist/auth/auth.d.ts +182 -0
- package/dist/auth/auth.d.ts.map +1 -0
- package/dist/auth/auth.js +477 -0
- package/dist/auth/auth.js.map +1 -0
- package/dist/auth/defaults.d.ts +104 -0
- package/dist/auth/defaults.d.ts.map +1 -0
- package/dist/auth/defaults.js +374 -0
- package/dist/auth/defaults.js.map +1 -0
- package/dist/auth/index.d.ts +70 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +94 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/cache/cache.d.ts +118 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +249 -0
- package/dist/cache/cache.js.map +1 -0
- package/dist/cache/defaults.d.ts +63 -0
- package/dist/cache/defaults.d.ts.map +1 -0
- package/dist/cache/defaults.js +193 -0
- package/dist/cache/defaults.js.map +1 -0
- package/dist/cache/index.d.ts +101 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +203 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/strategies/memory.d.ts +138 -0
- package/dist/cache/strategies/memory.d.ts.map +1 -0
- package/dist/cache/strategies/memory.js +348 -0
- package/dist/cache/strategies/memory.js.map +1 -0
- package/dist/cache/strategies/redis.d.ts +105 -0
- package/dist/cache/strategies/redis.d.ts.map +1 -0
- package/dist/cache/strategies/redis.js +318 -0
- package/dist/cache/strategies/redis.js.map +1 -0
- package/dist/config/config.d.ts +62 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +107 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/defaults.d.ts +44 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +217 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +105 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +163 -0
- package/dist/config/index.js.map +1 -0
- package/dist/database/adapters/mongoose.d.ts +106 -0
- package/dist/database/adapters/mongoose.d.ts.map +1 -0
- package/dist/database/adapters/mongoose.js +480 -0
- package/dist/database/adapters/mongoose.js.map +1 -0
- package/dist/database/adapters/prisma.d.ts +106 -0
- package/dist/database/adapters/prisma.d.ts.map +1 -0
- package/dist/database/adapters/prisma.js +494 -0
- package/dist/database/adapters/prisma.js.map +1 -0
- package/dist/database/defaults.d.ts +87 -0
- package/dist/database/defaults.d.ts.map +1 -0
- package/dist/database/defaults.js +271 -0
- package/dist/database/defaults.js.map +1 -0
- package/dist/database/index.d.ts +137 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +490 -0
- package/dist/database/index.js.map +1 -0
- package/dist/email/defaults.d.ts +100 -0
- package/dist/email/defaults.d.ts.map +1 -0
- package/dist/email/defaults.js +400 -0
- package/dist/email/defaults.js.map +1 -0
- package/dist/email/email.d.ts +139 -0
- package/dist/email/email.d.ts.map +1 -0
- package/dist/email/email.js +316 -0
- package/dist/email/email.js.map +1 -0
- package/dist/email/index.d.ts +176 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +251 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/strategies/console.d.ts +90 -0
- package/dist/email/strategies/console.d.ts.map +1 -0
- package/dist/email/strategies/console.js +268 -0
- package/dist/email/strategies/console.js.map +1 -0
- package/dist/email/strategies/resend.d.ts +84 -0
- package/dist/email/strategies/resend.d.ts.map +1 -0
- package/dist/email/strategies/resend.js +266 -0
- package/dist/email/strategies/resend.js.map +1 -0
- package/dist/email/strategies/smtp.d.ts +77 -0
- package/dist/email/strategies/smtp.d.ts.map +1 -0
- package/dist/email/strategies/smtp.js +286 -0
- package/dist/email/strategies/smtp.js.map +1 -0
- package/dist/error/defaults.d.ts +40 -0
- package/dist/error/defaults.d.ts.map +1 -0
- package/dist/error/defaults.js +75 -0
- package/dist/error/defaults.js.map +1 -0
- package/dist/error/error.d.ts +140 -0
- package/dist/error/error.d.ts.map +1 -0
- package/dist/error/error.js +200 -0
- package/dist/error/error.js.map +1 -0
- package/dist/error/index.d.ts +145 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/error/index.js +145 -0
- package/dist/error/index.js.map +1 -0
- package/dist/event/defaults.d.ts +111 -0
- package/dist/event/defaults.d.ts.map +1 -0
- package/dist/event/defaults.js +378 -0
- package/dist/event/defaults.js.map +1 -0
- package/dist/event/event.d.ts +171 -0
- package/dist/event/event.d.ts.map +1 -0
- package/dist/event/event.js +391 -0
- package/dist/event/event.js.map +1 -0
- package/dist/event/index.d.ts +173 -0
- package/dist/event/index.d.ts.map +1 -0
- package/dist/event/index.js +302 -0
- package/dist/event/index.js.map +1 -0
- package/dist/event/strategies/memory.d.ts +122 -0
- package/dist/event/strategies/memory.d.ts.map +1 -0
- package/dist/event/strategies/memory.js +331 -0
- package/dist/event/strategies/memory.js.map +1 -0
- package/dist/event/strategies/redis.d.ts +115 -0
- package/dist/event/strategies/redis.d.ts.map +1 -0
- package/dist/event/strategies/redis.js +434 -0
- package/dist/event/strategies/redis.js.map +1 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/defaults.d.ts +67 -0
- package/dist/logger/defaults.d.ts.map +1 -0
- package/dist/logger/defaults.js +213 -0
- package/dist/logger/defaults.js.map +1 -0
- package/dist/logger/index.d.ts +84 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +101 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/logger.d.ts +165 -0
- package/dist/logger/logger.d.ts.map +1 -0
- package/dist/logger/logger.js +843 -0
- package/dist/logger/logger.js.map +1 -0
- package/dist/logger/transports/console.d.ts +102 -0
- package/dist/logger/transports/console.d.ts.map +1 -0
- package/dist/logger/transports/console.js +276 -0
- package/dist/logger/transports/console.js.map +1 -0
- package/dist/logger/transports/database.d.ts +153 -0
- package/dist/logger/transports/database.d.ts.map +1 -0
- package/dist/logger/transports/database.js +539 -0
- package/dist/logger/transports/database.js.map +1 -0
- package/dist/logger/transports/file.d.ts +146 -0
- package/dist/logger/transports/file.d.ts.map +1 -0
- package/dist/logger/transports/file.js +464 -0
- package/dist/logger/transports/file.js.map +1 -0
- package/dist/logger/transports/http.d.ts +128 -0
- package/dist/logger/transports/http.d.ts.map +1 -0
- package/dist/logger/transports/http.js +401 -0
- package/dist/logger/transports/http.js.map +1 -0
- package/dist/logger/transports/webhook.d.ts +152 -0
- package/dist/logger/transports/webhook.d.ts.map +1 -0
- package/dist/logger/transports/webhook.js +485 -0
- package/dist/logger/transports/webhook.js.map +1 -0
- package/dist/queue/defaults.d.ts +66 -0
- package/dist/queue/defaults.d.ts.map +1 -0
- package/dist/queue/defaults.js +205 -0
- package/dist/queue/defaults.js.map +1 -0
- package/dist/queue/index.d.ts +124 -0
- package/dist/queue/index.d.ts.map +1 -0
- package/dist/queue/index.js +116 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/queue/queue.d.ts +156 -0
- package/dist/queue/queue.d.ts.map +1 -0
- package/dist/queue/queue.js +387 -0
- package/dist/queue/queue.js.map +1 -0
- package/dist/queue/transports/database.d.ts +165 -0
- package/dist/queue/transports/database.d.ts.map +1 -0
- package/dist/queue/transports/database.js +595 -0
- package/dist/queue/transports/database.js.map +1 -0
- package/dist/queue/transports/memory.d.ts +143 -0
- package/dist/queue/transports/memory.d.ts.map +1 -0
- package/dist/queue/transports/memory.js +415 -0
- package/dist/queue/transports/memory.js.map +1 -0
- package/dist/queue/transports/redis.d.ts +203 -0
- package/dist/queue/transports/redis.d.ts.map +1 -0
- package/dist/queue/transports/redis.js +744 -0
- package/dist/queue/transports/redis.js.map +1 -0
- package/dist/security/defaults.d.ts +64 -0
- package/dist/security/defaults.d.ts.map +1 -0
- package/dist/security/defaults.js +159 -0
- package/dist/security/defaults.js.map +1 -0
- package/dist/security/index.d.ts +110 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +160 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/security.d.ts +138 -0
- package/dist/security/security.d.ts.map +1 -0
- package/dist/security/security.js +419 -0
- package/dist/security/security.js.map +1 -0
- package/dist/storage/defaults.d.ts +79 -0
- package/dist/storage/defaults.d.ts.map +1 -0
- package/dist/storage/defaults.js +358 -0
- package/dist/storage/defaults.js.map +1 -0
- package/dist/storage/index.d.ts +153 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +242 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/storage.d.ts +151 -0
- package/dist/storage/storage.d.ts.map +1 -0
- package/dist/storage/storage.js +439 -0
- package/dist/storage/storage.js.map +1 -0
- package/dist/storage/strategies/local.d.ts +117 -0
- package/dist/storage/strategies/local.d.ts.map +1 -0
- package/dist/storage/strategies/local.js +368 -0
- package/dist/storage/strategies/local.js.map +1 -0
- package/dist/storage/strategies/r2.d.ts +130 -0
- package/dist/storage/strategies/r2.d.ts.map +1 -0
- package/dist/storage/strategies/r2.js +470 -0
- package/dist/storage/strategies/r2.js.map +1 -0
- package/dist/storage/strategies/s3.d.ts +121 -0
- package/dist/storage/strategies/s3.d.ts.map +1 -0
- package/dist/storage/strategies/s3.js +461 -0
- package/dist/storage/strategies/s3.js.map +1 -0
- package/dist/util/defaults.d.ts +77 -0
- package/dist/util/defaults.d.ts.map +1 -0
- package/dist/util/defaults.js +193 -0
- package/dist/util/defaults.js.map +1 -0
- package/dist/util/index.d.ts +97 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +165 -0
- package/dist/util/index.js.map +1 -0
- package/dist/util/util.d.ts +145 -0
- package/dist/util/util.d.ts.map +1 -0
- package/dist/util/util.js +481 -0
- package/dist/util/util.js.map +1 -0
- package/package.json +234 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
model User {
|
|
2
|
+
id Int @id @default(autoincrement())
|
|
3
|
+
email String @unique
|
|
4
|
+
password String
|
|
5
|
+
name String?
|
|
6
|
+
phone String?
|
|
7
|
+
role String @default("user")
|
|
8
|
+
level String @default("basic")
|
|
9
|
+
tenantId String? // AppKit multi-tenant support
|
|
10
|
+
isVerified Boolean @default(false)
|
|
11
|
+
isActive Boolean @default(true)
|
|
12
|
+
lastLogin DateTime?
|
|
13
|
+
resetToken String?
|
|
14
|
+
resetTokenExpiry DateTime?
|
|
15
|
+
createdAt DateTime @default(now())
|
|
16
|
+
updatedAt DateTime @updatedAt
|
|
17
|
+
|
|
18
|
+
@@map("users")
|
|
19
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
###
|
|
2
|
+
# User Feature HTTP Tests
|
|
3
|
+
# @file src/api/features/user/user.http
|
|
4
|
+
#
|
|
5
|
+
# Test all user authentication endpoints
|
|
6
|
+
# Make sure to run the seeding first: node prisma/seeding/user.seed.js
|
|
7
|
+
###
|
|
8
|
+
|
|
9
|
+
@baseUrl = http://localhost:3000
|
|
10
|
+
@frontendKey = {{frontendKey}}
|
|
11
|
+
@token =
|
|
12
|
+
|
|
13
|
+
### 1. Test route (verify user routes are working)
|
|
14
|
+
GET {{baseUrl}}/api/user/test
|
|
15
|
+
X-Frontend-Key: {{frontendKey}}
|
|
16
|
+
|
|
17
|
+
### 2. Register a new user
|
|
18
|
+
POST {{baseUrl}}/api/user/register
|
|
19
|
+
Content-Type: application/json
|
|
20
|
+
X-Frontend-Key: {{frontendKey}}
|
|
21
|
+
|
|
22
|
+
{
|
|
23
|
+
"email": "test@example.com",
|
|
24
|
+
"password": "Password123!",
|
|
25
|
+
"name": "Test User",
|
|
26
|
+
"phone": "+1-555-1234",
|
|
27
|
+
"role": "user",
|
|
28
|
+
"level": "basic"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
### 3. Login with basic user
|
|
32
|
+
POST {{baseUrl}}/api/user/login
|
|
33
|
+
Content-Type: application/json
|
|
34
|
+
X-Frontend-Key: {{frontendKey}}
|
|
35
|
+
|
|
36
|
+
{
|
|
37
|
+
"email": "user.basic@{{projectName}}.com",
|
|
38
|
+
"password": "Password123!"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
### 4. Login with admin user
|
|
42
|
+
POST {{baseUrl}}/api/user/login
|
|
43
|
+
Content-Type: application/json
|
|
44
|
+
X-Frontend-Key: {{frontendKey}}
|
|
45
|
+
|
|
46
|
+
{
|
|
47
|
+
"email": "admin.system@{{projectName}}.com",
|
|
48
|
+
"password": "Password123!"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
### 5. Get user profile (requires auth token)
|
|
52
|
+
GET {{baseUrl}}/api/user/profile
|
|
53
|
+
Authorization: Bearer {{token}}
|
|
54
|
+
X-Frontend-Key: {{frontendKey}}
|
|
55
|
+
|
|
56
|
+
### 6. Update user profile (requires auth token)
|
|
57
|
+
PUT {{baseUrl}}/api/user/profile
|
|
58
|
+
Authorization: Bearer {{token}}
|
|
59
|
+
Content-Type: application/json
|
|
60
|
+
X-Frontend-Key: {{frontendKey}}
|
|
61
|
+
|
|
62
|
+
{
|
|
63
|
+
"name": "Updated Name",
|
|
64
|
+
"phone": "+1-555-9999"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
### 7. Change password (requires auth token)
|
|
68
|
+
POST {{baseUrl}}/api/user/change-password
|
|
69
|
+
Authorization: Bearer {{token}}
|
|
70
|
+
Content-Type: application/json
|
|
71
|
+
X-Frontend-Key: {{frontendKey}}
|
|
72
|
+
|
|
73
|
+
{
|
|
74
|
+
"currentPassword": "Password123!",
|
|
75
|
+
"newPassword": "NewPassword123!"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
### 8. Forgot password
|
|
79
|
+
POST {{baseUrl}}/api/user/forgot-password
|
|
80
|
+
Content-Type: application/json
|
|
81
|
+
X-Frontend-Key: {{frontendKey}}
|
|
82
|
+
|
|
83
|
+
{
|
|
84
|
+
"email": "user.basic@{{projectName}}.com"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
### 9. Reset password (use token from forgot password)
|
|
88
|
+
POST {{baseUrl}}/api/user/reset-password
|
|
89
|
+
Content-Type: application/json
|
|
90
|
+
X-Frontend-Key: {{frontendKey}}
|
|
91
|
+
|
|
92
|
+
{
|
|
93
|
+
"token": "your-reset-token-here",
|
|
94
|
+
"newPassword": "ResetPassword123!"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
### 10. Get all users (admin only)
|
|
98
|
+
GET {{baseUrl}}/api/user/all
|
|
99
|
+
Authorization: Bearer {{token}}
|
|
100
|
+
X-Frontend-Key: {{frontendKey}}
|
|
101
|
+
|
|
102
|
+
### 11. Get users list (moderator+ access)
|
|
103
|
+
GET {{baseUrl}}/api/user/list
|
|
104
|
+
Authorization: Bearer {{token}}
|
|
105
|
+
X-Frontend-Key: {{frontendKey}}
|
|
106
|
+
|
|
107
|
+
### 12. Update user by admin (admin only)
|
|
108
|
+
PUT {{baseUrl}}/api/user/list/2
|
|
109
|
+
Authorization: Bearer {{token}}
|
|
110
|
+
Content-Type: application/json
|
|
111
|
+
X-Frontend-Key: {{frontendKey}}
|
|
112
|
+
|
|
113
|
+
{
|
|
114
|
+
"name": "Admin Updated Name",
|
|
115
|
+
"role": "moderator",
|
|
116
|
+
"level": "review",
|
|
117
|
+
"isActive": true,
|
|
118
|
+
"isVerified": true
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
### 13. Delete user (admin only)
|
|
122
|
+
DELETE {{baseUrl}}/api/user/list/2
|
|
123
|
+
Authorization: Bearer {{token}}
|
|
124
|
+
X-Frontend-Key: {{frontendKey}}
|
|
125
|
+
|
|
126
|
+
###
|
|
127
|
+
# Test different role access
|
|
128
|
+
###
|
|
129
|
+
|
|
130
|
+
### 14. Login as moderator (can view users)
|
|
131
|
+
POST {{baseUrl}}/api/user/login
|
|
132
|
+
Content-Type: application/json
|
|
133
|
+
X-Frontend-Key: {{frontendKey}}
|
|
134
|
+
|
|
135
|
+
{
|
|
136
|
+
"email": "moderator.review@{{projectName}}.com",
|
|
137
|
+
"password": "Password123!"
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
### 15. Login as system admin (highest privileges)
|
|
141
|
+
POST {{baseUrl}}/api/user/login
|
|
142
|
+
Content-Type: application/json
|
|
143
|
+
X-Frontend-Key: {{frontendKey}}
|
|
144
|
+
|
|
145
|
+
{
|
|
146
|
+
"email": "admin.system@{{projectName}}.com",
|
|
147
|
+
"password": "Password123!"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
###
|
|
151
|
+
# Instructions:
|
|
152
|
+
# 1. First run: node prisma/seeding/user.seed.js
|
|
153
|
+
# 2. Start the API server: npm run dev:api
|
|
154
|
+
# 3. Test login endpoints to get JWT token
|
|
155
|
+
# 4. Copy the token to @token variable at the top
|
|
156
|
+
# 5. Test protected endpoints
|
|
157
|
+
###
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User Model - User database operations with AppKit integration
|
|
3
|
+
* @module {{projectName}}/user-model
|
|
4
|
+
* @file src/api/features/user/user.model.ts
|
|
5
|
+
*
|
|
6
|
+
* @llm-rule WHEN: Need database layer separation for user feature with multi-tenant support
|
|
7
|
+
* @llm-rule AVOID: Database operations directly in service - use model layer
|
|
8
|
+
* @llm-rule NOTE: Handles all Prisma database operations for User authentication
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { databaseClass } from '@bloomneo/appkit/database';
|
|
12
|
+
import { loggerClass } from '@bloomneo/appkit/logger';
|
|
13
|
+
import { authClass } from '@bloomneo/appkit/auth';
|
|
14
|
+
import type { UserRegisterRequest, UserUpdateRequest } from './user.types.js';
|
|
15
|
+
|
|
16
|
+
const logger = loggerClass.get('user-model');
|
|
17
|
+
const auth = authClass.get();
|
|
18
|
+
|
|
19
|
+
export const model = {
|
|
20
|
+
/**
|
|
21
|
+
* Find user by email (for login)
|
|
22
|
+
*/
|
|
23
|
+
async findByEmail(email: string) {
|
|
24
|
+
logger.info('Finding user by email', { email });
|
|
25
|
+
const db = await databaseClass.get();
|
|
26
|
+
return await db.user.findUnique({
|
|
27
|
+
where: { email: email.toLowerCase().trim() }
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Find user by ID
|
|
33
|
+
*/
|
|
34
|
+
async findById(id: number) {
|
|
35
|
+
logger.info('Finding user by ID', { id });
|
|
36
|
+
const db = await databaseClass.get();
|
|
37
|
+
return await db.user.findUnique({
|
|
38
|
+
where: { id },
|
|
39
|
+
select: {
|
|
40
|
+
id: true,
|
|
41
|
+
email: true,
|
|
42
|
+
name: true,
|
|
43
|
+
phone: true,
|
|
44
|
+
role: true,
|
|
45
|
+
level: true,
|
|
46
|
+
tenantId: true,
|
|
47
|
+
isVerified: true,
|
|
48
|
+
isActive: true,
|
|
49
|
+
lastLogin: true,
|
|
50
|
+
createdAt: true,
|
|
51
|
+
updatedAt: true
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get all users (admin only)
|
|
58
|
+
*/
|
|
59
|
+
async findAll(tenantId?: string) {
|
|
60
|
+
logger.info('Finding all users', { tenantId });
|
|
61
|
+
const db = await databaseClass.get();
|
|
62
|
+
const where = tenantId ? { tenantId } : {};
|
|
63
|
+
|
|
64
|
+
return await db.user.findMany({
|
|
65
|
+
where,
|
|
66
|
+
select: {
|
|
67
|
+
id: true,
|
|
68
|
+
email: true,
|
|
69
|
+
name: true,
|
|
70
|
+
phone: true,
|
|
71
|
+
role: true,
|
|
72
|
+
level: true,
|
|
73
|
+
tenantId: true,
|
|
74
|
+
isVerified: true,
|
|
75
|
+
isActive: true,
|
|
76
|
+
lastLogin: true,
|
|
77
|
+
createdAt: true,
|
|
78
|
+
updatedAt: true
|
|
79
|
+
},
|
|
80
|
+
orderBy: { createdAt: 'desc' }
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Create new user with hashed password
|
|
86
|
+
*/
|
|
87
|
+
async create(data: UserRegisterRequest) {
|
|
88
|
+
logger.info('Creating new user', { email: data.email, role: data.role, level: data.level });
|
|
89
|
+
const db = await databaseClass.get();
|
|
90
|
+
|
|
91
|
+
// Hash password using AppKit auth
|
|
92
|
+
const hashedPassword = await auth.hashPassword(data.password);
|
|
93
|
+
|
|
94
|
+
return await db.user.create({
|
|
95
|
+
data: {
|
|
96
|
+
email: data.email.toLowerCase().trim(),
|
|
97
|
+
password: hashedPassword,
|
|
98
|
+
name: data.name?.trim(),
|
|
99
|
+
phone: data.phone?.trim(),
|
|
100
|
+
role: data.role || 'user',
|
|
101
|
+
level: data.level || 'basic',
|
|
102
|
+
tenantId: data.tenantId,
|
|
103
|
+
},
|
|
104
|
+
select: {
|
|
105
|
+
id: true,
|
|
106
|
+
email: true,
|
|
107
|
+
name: true,
|
|
108
|
+
phone: true,
|
|
109
|
+
role: true,
|
|
110
|
+
level: true,
|
|
111
|
+
tenantId: true,
|
|
112
|
+
isVerified: true,
|
|
113
|
+
isActive: true,
|
|
114
|
+
createdAt: true,
|
|
115
|
+
updatedAt: true
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Update user profile
|
|
122
|
+
*/
|
|
123
|
+
async update(id: number, data: UserUpdateRequest) {
|
|
124
|
+
logger.info('Updating user', { id, data });
|
|
125
|
+
const db = await databaseClass.get();
|
|
126
|
+
|
|
127
|
+
return await db.user.update({
|
|
128
|
+
where: { id },
|
|
129
|
+
data,
|
|
130
|
+
select: {
|
|
131
|
+
id: true,
|
|
132
|
+
email: true,
|
|
133
|
+
name: true,
|
|
134
|
+
phone: true,
|
|
135
|
+
role: true,
|
|
136
|
+
level: true,
|
|
137
|
+
tenantId: true,
|
|
138
|
+
isVerified: true,
|
|
139
|
+
isActive: true,
|
|
140
|
+
lastLogin: true,
|
|
141
|
+
createdAt: true,
|
|
142
|
+
updatedAt: true
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Update user's last login time
|
|
149
|
+
*/
|
|
150
|
+
async updateLastLogin(id: number) {
|
|
151
|
+
logger.info('Updating last login', { id });
|
|
152
|
+
const db = await databaseClass.get();
|
|
153
|
+
|
|
154
|
+
return await db.user.update({
|
|
155
|
+
where: { id },
|
|
156
|
+
data: { lastLogin: new Date() },
|
|
157
|
+
select: { id: true, lastLogin: true }
|
|
158
|
+
});
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Verify user password (for login)
|
|
163
|
+
*/
|
|
164
|
+
async verifyPassword(plainPassword: string, hashedPassword: string): Promise<boolean> {
|
|
165
|
+
return await auth.comparePassword(plainPassword, hashedPassword);
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Update user password
|
|
170
|
+
*/
|
|
171
|
+
async updatePassword(id: number, newPassword: string) {
|
|
172
|
+
logger.info('Updating user password', { id });
|
|
173
|
+
const db = await databaseClass.get();
|
|
174
|
+
|
|
175
|
+
const hashedPassword = await auth.hashPassword(newPassword);
|
|
176
|
+
|
|
177
|
+
return await db.user.update({
|
|
178
|
+
where: { id },
|
|
179
|
+
data: { password: hashedPassword },
|
|
180
|
+
select: { id: true, email: true }
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Set password reset token
|
|
186
|
+
*/
|
|
187
|
+
async setResetToken(email: string, token: string, expiry: Date) {
|
|
188
|
+
logger.info('Setting reset token', { email });
|
|
189
|
+
const db = await databaseClass.get();
|
|
190
|
+
|
|
191
|
+
return await db.user.update({
|
|
192
|
+
where: { email: email.toLowerCase().trim() },
|
|
193
|
+
data: {
|
|
194
|
+
resetToken: token,
|
|
195
|
+
resetTokenExpiry: expiry
|
|
196
|
+
},
|
|
197
|
+
select: { id: true, email: true }
|
|
198
|
+
});
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Find user by reset token
|
|
203
|
+
*/
|
|
204
|
+
async findByResetToken(token: string) {
|
|
205
|
+
logger.info('Finding user by reset token');
|
|
206
|
+
const db = await databaseClass.get();
|
|
207
|
+
|
|
208
|
+
return await db.user.findFirst({
|
|
209
|
+
where: {
|
|
210
|
+
resetToken: token,
|
|
211
|
+
resetTokenExpiry: { gt: new Date() }
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Clear reset token after use
|
|
218
|
+
*/
|
|
219
|
+
async clearResetToken(id: number) {
|
|
220
|
+
logger.info('Clearing reset token', { id });
|
|
221
|
+
const db = await databaseClass.get();
|
|
222
|
+
|
|
223
|
+
return await db.user.update({
|
|
224
|
+
where: { id },
|
|
225
|
+
data: {
|
|
226
|
+
resetToken: null,
|
|
227
|
+
resetTokenExpiry: null
|
|
228
|
+
},
|
|
229
|
+
select: { id: true, email: true }
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Delete user (admin only)
|
|
235
|
+
*/
|
|
236
|
+
async delete(id: number) {
|
|
237
|
+
logger.info('Deleting user', { id });
|
|
238
|
+
const db = await databaseClass.get();
|
|
239
|
+
|
|
240
|
+
return await db.user.delete({
|
|
241
|
+
where: { id }
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
};
|