@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.
Files changed (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +902 -0
  3. package/bin/appkit.js +71 -0
  4. package/bin/commands/generate.js +1050 -0
  5. package/bin/templates/backend/README.md.template +39 -0
  6. package/bin/templates/backend/api.http.template +0 -0
  7. package/bin/templates/backend/docs/APPKIT_CLI.md +507 -0
  8. package/bin/templates/backend/docs/APPKIT_COMMENTS_GUIDELINES.md +61 -0
  9. package/bin/templates/backend/docs/APPKIT_LLM_GUIDE.md +2539 -0
  10. package/bin/templates/backend/package.json.template +34 -0
  11. package/bin/templates/backend/src/api/features/welcome/welcome.http.template +29 -0
  12. package/bin/templates/backend/src/api/features/welcome/welcome.route.ts.template +36 -0
  13. package/bin/templates/backend/src/api/features/welcome/welcome.service.ts.template +88 -0
  14. package/bin/templates/backend/src/api/features/welcome/welcome.types.ts.template +18 -0
  15. package/bin/templates/backend/src/api/lib/api-router.ts.template +84 -0
  16. package/bin/templates/backend/src/api/server.ts.template +188 -0
  17. package/bin/templates/backend/tsconfig.api.json.template +24 -0
  18. package/bin/templates/backend/tsconfig.json.template +40 -0
  19. package/bin/templates/feature/feature.http.template +63 -0
  20. package/bin/templates/feature/feature.route.ts.template +36 -0
  21. package/bin/templates/feature/feature.service.ts.template +81 -0
  22. package/bin/templates/feature/feature.types.ts.template +23 -0
  23. package/bin/templates/feature-db/feature.http.template +63 -0
  24. package/bin/templates/feature-db/feature.model.ts.template +74 -0
  25. package/bin/templates/feature-db/feature.route.ts.template +58 -0
  26. package/bin/templates/feature-db/feature.service.ts.template +231 -0
  27. package/bin/templates/feature-db/feature.types.ts.template +25 -0
  28. package/bin/templates/feature-db/schema-addition.prisma.template +9 -0
  29. package/bin/templates/feature-db/seeding/README.md.template +57 -0
  30. package/bin/templates/feature-db/seeding/feature.seed.js.template +67 -0
  31. package/bin/templates/feature-user/schema-addition.prisma.template +19 -0
  32. package/bin/templates/feature-user/user.http.template +157 -0
  33. package/bin/templates/feature-user/user.model.ts.template +244 -0
  34. package/bin/templates/feature-user/user.route.ts.template +379 -0
  35. package/bin/templates/feature-user/user.seed.js.template +182 -0
  36. package/bin/templates/feature-user/user.service.ts.template +426 -0
  37. package/bin/templates/feature-user/user.types.ts.template +127 -0
  38. package/dist/auth/auth.d.ts +182 -0
  39. package/dist/auth/auth.d.ts.map +1 -0
  40. package/dist/auth/auth.js +477 -0
  41. package/dist/auth/auth.js.map +1 -0
  42. package/dist/auth/defaults.d.ts +104 -0
  43. package/dist/auth/defaults.d.ts.map +1 -0
  44. package/dist/auth/defaults.js +374 -0
  45. package/dist/auth/defaults.js.map +1 -0
  46. package/dist/auth/index.d.ts +70 -0
  47. package/dist/auth/index.d.ts.map +1 -0
  48. package/dist/auth/index.js +94 -0
  49. package/dist/auth/index.js.map +1 -0
  50. package/dist/cache/cache.d.ts +118 -0
  51. package/dist/cache/cache.d.ts.map +1 -0
  52. package/dist/cache/cache.js +249 -0
  53. package/dist/cache/cache.js.map +1 -0
  54. package/dist/cache/defaults.d.ts +63 -0
  55. package/dist/cache/defaults.d.ts.map +1 -0
  56. package/dist/cache/defaults.js +193 -0
  57. package/dist/cache/defaults.js.map +1 -0
  58. package/dist/cache/index.d.ts +101 -0
  59. package/dist/cache/index.d.ts.map +1 -0
  60. package/dist/cache/index.js +203 -0
  61. package/dist/cache/index.js.map +1 -0
  62. package/dist/cache/strategies/memory.d.ts +138 -0
  63. package/dist/cache/strategies/memory.d.ts.map +1 -0
  64. package/dist/cache/strategies/memory.js +348 -0
  65. package/dist/cache/strategies/memory.js.map +1 -0
  66. package/dist/cache/strategies/redis.d.ts +105 -0
  67. package/dist/cache/strategies/redis.d.ts.map +1 -0
  68. package/dist/cache/strategies/redis.js +318 -0
  69. package/dist/cache/strategies/redis.js.map +1 -0
  70. package/dist/config/config.d.ts +62 -0
  71. package/dist/config/config.d.ts.map +1 -0
  72. package/dist/config/config.js +107 -0
  73. package/dist/config/config.js.map +1 -0
  74. package/dist/config/defaults.d.ts +44 -0
  75. package/dist/config/defaults.d.ts.map +1 -0
  76. package/dist/config/defaults.js +217 -0
  77. package/dist/config/defaults.js.map +1 -0
  78. package/dist/config/index.d.ts +105 -0
  79. package/dist/config/index.d.ts.map +1 -0
  80. package/dist/config/index.js +163 -0
  81. package/dist/config/index.js.map +1 -0
  82. package/dist/database/adapters/mongoose.d.ts +106 -0
  83. package/dist/database/adapters/mongoose.d.ts.map +1 -0
  84. package/dist/database/adapters/mongoose.js +480 -0
  85. package/dist/database/adapters/mongoose.js.map +1 -0
  86. package/dist/database/adapters/prisma.d.ts +106 -0
  87. package/dist/database/adapters/prisma.d.ts.map +1 -0
  88. package/dist/database/adapters/prisma.js +494 -0
  89. package/dist/database/adapters/prisma.js.map +1 -0
  90. package/dist/database/defaults.d.ts +87 -0
  91. package/dist/database/defaults.d.ts.map +1 -0
  92. package/dist/database/defaults.js +271 -0
  93. package/dist/database/defaults.js.map +1 -0
  94. package/dist/database/index.d.ts +137 -0
  95. package/dist/database/index.d.ts.map +1 -0
  96. package/dist/database/index.js +490 -0
  97. package/dist/database/index.js.map +1 -0
  98. package/dist/email/defaults.d.ts +100 -0
  99. package/dist/email/defaults.d.ts.map +1 -0
  100. package/dist/email/defaults.js +400 -0
  101. package/dist/email/defaults.js.map +1 -0
  102. package/dist/email/email.d.ts +139 -0
  103. package/dist/email/email.d.ts.map +1 -0
  104. package/dist/email/email.js +316 -0
  105. package/dist/email/email.js.map +1 -0
  106. package/dist/email/index.d.ts +176 -0
  107. package/dist/email/index.d.ts.map +1 -0
  108. package/dist/email/index.js +251 -0
  109. package/dist/email/index.js.map +1 -0
  110. package/dist/email/strategies/console.d.ts +90 -0
  111. package/dist/email/strategies/console.d.ts.map +1 -0
  112. package/dist/email/strategies/console.js +268 -0
  113. package/dist/email/strategies/console.js.map +1 -0
  114. package/dist/email/strategies/resend.d.ts +84 -0
  115. package/dist/email/strategies/resend.d.ts.map +1 -0
  116. package/dist/email/strategies/resend.js +266 -0
  117. package/dist/email/strategies/resend.js.map +1 -0
  118. package/dist/email/strategies/smtp.d.ts +77 -0
  119. package/dist/email/strategies/smtp.d.ts.map +1 -0
  120. package/dist/email/strategies/smtp.js +286 -0
  121. package/dist/email/strategies/smtp.js.map +1 -0
  122. package/dist/error/defaults.d.ts +40 -0
  123. package/dist/error/defaults.d.ts.map +1 -0
  124. package/dist/error/defaults.js +75 -0
  125. package/dist/error/defaults.js.map +1 -0
  126. package/dist/error/error.d.ts +140 -0
  127. package/dist/error/error.d.ts.map +1 -0
  128. package/dist/error/error.js +200 -0
  129. package/dist/error/error.js.map +1 -0
  130. package/dist/error/index.d.ts +145 -0
  131. package/dist/error/index.d.ts.map +1 -0
  132. package/dist/error/index.js +145 -0
  133. package/dist/error/index.js.map +1 -0
  134. package/dist/event/defaults.d.ts +111 -0
  135. package/dist/event/defaults.d.ts.map +1 -0
  136. package/dist/event/defaults.js +378 -0
  137. package/dist/event/defaults.js.map +1 -0
  138. package/dist/event/event.d.ts +171 -0
  139. package/dist/event/event.d.ts.map +1 -0
  140. package/dist/event/event.js +391 -0
  141. package/dist/event/event.js.map +1 -0
  142. package/dist/event/index.d.ts +173 -0
  143. package/dist/event/index.d.ts.map +1 -0
  144. package/dist/event/index.js +302 -0
  145. package/dist/event/index.js.map +1 -0
  146. package/dist/event/strategies/memory.d.ts +122 -0
  147. package/dist/event/strategies/memory.d.ts.map +1 -0
  148. package/dist/event/strategies/memory.js +331 -0
  149. package/dist/event/strategies/memory.js.map +1 -0
  150. package/dist/event/strategies/redis.d.ts +115 -0
  151. package/dist/event/strategies/redis.d.ts.map +1 -0
  152. package/dist/event/strategies/redis.js +434 -0
  153. package/dist/event/strategies/redis.js.map +1 -0
  154. package/dist/index.d.ts +58 -0
  155. package/dist/index.d.ts.map +1 -0
  156. package/dist/index.js +72 -0
  157. package/dist/index.js.map +1 -0
  158. package/dist/logger/defaults.d.ts +67 -0
  159. package/dist/logger/defaults.d.ts.map +1 -0
  160. package/dist/logger/defaults.js +213 -0
  161. package/dist/logger/defaults.js.map +1 -0
  162. package/dist/logger/index.d.ts +84 -0
  163. package/dist/logger/index.d.ts.map +1 -0
  164. package/dist/logger/index.js +101 -0
  165. package/dist/logger/index.js.map +1 -0
  166. package/dist/logger/logger.d.ts +165 -0
  167. package/dist/logger/logger.d.ts.map +1 -0
  168. package/dist/logger/logger.js +843 -0
  169. package/dist/logger/logger.js.map +1 -0
  170. package/dist/logger/transports/console.d.ts +102 -0
  171. package/dist/logger/transports/console.d.ts.map +1 -0
  172. package/dist/logger/transports/console.js +276 -0
  173. package/dist/logger/transports/console.js.map +1 -0
  174. package/dist/logger/transports/database.d.ts +153 -0
  175. package/dist/logger/transports/database.d.ts.map +1 -0
  176. package/dist/logger/transports/database.js +539 -0
  177. package/dist/logger/transports/database.js.map +1 -0
  178. package/dist/logger/transports/file.d.ts +146 -0
  179. package/dist/logger/transports/file.d.ts.map +1 -0
  180. package/dist/logger/transports/file.js +464 -0
  181. package/dist/logger/transports/file.js.map +1 -0
  182. package/dist/logger/transports/http.d.ts +128 -0
  183. package/dist/logger/transports/http.d.ts.map +1 -0
  184. package/dist/logger/transports/http.js +401 -0
  185. package/dist/logger/transports/http.js.map +1 -0
  186. package/dist/logger/transports/webhook.d.ts +152 -0
  187. package/dist/logger/transports/webhook.d.ts.map +1 -0
  188. package/dist/logger/transports/webhook.js +485 -0
  189. package/dist/logger/transports/webhook.js.map +1 -0
  190. package/dist/queue/defaults.d.ts +66 -0
  191. package/dist/queue/defaults.d.ts.map +1 -0
  192. package/dist/queue/defaults.js +205 -0
  193. package/dist/queue/defaults.js.map +1 -0
  194. package/dist/queue/index.d.ts +124 -0
  195. package/dist/queue/index.d.ts.map +1 -0
  196. package/dist/queue/index.js +116 -0
  197. package/dist/queue/index.js.map +1 -0
  198. package/dist/queue/queue.d.ts +156 -0
  199. package/dist/queue/queue.d.ts.map +1 -0
  200. package/dist/queue/queue.js +387 -0
  201. package/dist/queue/queue.js.map +1 -0
  202. package/dist/queue/transports/database.d.ts +165 -0
  203. package/dist/queue/transports/database.d.ts.map +1 -0
  204. package/dist/queue/transports/database.js +595 -0
  205. package/dist/queue/transports/database.js.map +1 -0
  206. package/dist/queue/transports/memory.d.ts +143 -0
  207. package/dist/queue/transports/memory.d.ts.map +1 -0
  208. package/dist/queue/transports/memory.js +415 -0
  209. package/dist/queue/transports/memory.js.map +1 -0
  210. package/dist/queue/transports/redis.d.ts +203 -0
  211. package/dist/queue/transports/redis.d.ts.map +1 -0
  212. package/dist/queue/transports/redis.js +744 -0
  213. package/dist/queue/transports/redis.js.map +1 -0
  214. package/dist/security/defaults.d.ts +64 -0
  215. package/dist/security/defaults.d.ts.map +1 -0
  216. package/dist/security/defaults.js +159 -0
  217. package/dist/security/defaults.js.map +1 -0
  218. package/dist/security/index.d.ts +110 -0
  219. package/dist/security/index.d.ts.map +1 -0
  220. package/dist/security/index.js +160 -0
  221. package/dist/security/index.js.map +1 -0
  222. package/dist/security/security.d.ts +138 -0
  223. package/dist/security/security.d.ts.map +1 -0
  224. package/dist/security/security.js +419 -0
  225. package/dist/security/security.js.map +1 -0
  226. package/dist/storage/defaults.d.ts +79 -0
  227. package/dist/storage/defaults.d.ts.map +1 -0
  228. package/dist/storage/defaults.js +358 -0
  229. package/dist/storage/defaults.js.map +1 -0
  230. package/dist/storage/index.d.ts +153 -0
  231. package/dist/storage/index.d.ts.map +1 -0
  232. package/dist/storage/index.js +242 -0
  233. package/dist/storage/index.js.map +1 -0
  234. package/dist/storage/storage.d.ts +151 -0
  235. package/dist/storage/storage.d.ts.map +1 -0
  236. package/dist/storage/storage.js +439 -0
  237. package/dist/storage/storage.js.map +1 -0
  238. package/dist/storage/strategies/local.d.ts +117 -0
  239. package/dist/storage/strategies/local.d.ts.map +1 -0
  240. package/dist/storage/strategies/local.js +368 -0
  241. package/dist/storage/strategies/local.js.map +1 -0
  242. package/dist/storage/strategies/r2.d.ts +130 -0
  243. package/dist/storage/strategies/r2.d.ts.map +1 -0
  244. package/dist/storage/strategies/r2.js +470 -0
  245. package/dist/storage/strategies/r2.js.map +1 -0
  246. package/dist/storage/strategies/s3.d.ts +121 -0
  247. package/dist/storage/strategies/s3.d.ts.map +1 -0
  248. package/dist/storage/strategies/s3.js +461 -0
  249. package/dist/storage/strategies/s3.js.map +1 -0
  250. package/dist/util/defaults.d.ts +77 -0
  251. package/dist/util/defaults.d.ts.map +1 -0
  252. package/dist/util/defaults.js +193 -0
  253. package/dist/util/defaults.js.map +1 -0
  254. package/dist/util/index.d.ts +97 -0
  255. package/dist/util/index.d.ts.map +1 -0
  256. package/dist/util/index.js +165 -0
  257. package/dist/util/index.js.map +1 -0
  258. package/dist/util/util.d.ts +145 -0
  259. package/dist/util/util.d.ts.map +1 -0
  260. package/dist/util/util.js +481 -0
  261. package/dist/util/util.js.map +1 -0
  262. 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
+ };