servcraft 0.1.0 → 0.1.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 (216) hide show
  1. package/.claude/settings.local.json +29 -0
  2. package/.github/CODEOWNERS +18 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +46 -0
  4. package/.github/dependabot.yml +59 -0
  5. package/.github/workflows/ci.yml +188 -0
  6. package/.github/workflows/release.yml +195 -0
  7. package/AUDIT.md +602 -0
  8. package/README.md +1070 -1
  9. package/dist/cli/index.cjs +2026 -2168
  10. package/dist/cli/index.cjs.map +1 -1
  11. package/dist/cli/index.js +2026 -2168
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/index.cjs +595 -616
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +114 -52
  16. package/dist/index.d.ts +114 -52
  17. package/dist/index.js +595 -616
  18. package/dist/index.js.map +1 -1
  19. package/docs/CLI-001_MULTI_DB_PLAN.md +546 -0
  20. package/docs/DATABASE_MULTI_ORM.md +399 -0
  21. package/docs/PHASE1_BREAKDOWN.md +346 -0
  22. package/docs/PROGRESS.md +550 -0
  23. package/docs/modules/ANALYTICS.md +226 -0
  24. package/docs/modules/API-VERSIONING.md +252 -0
  25. package/docs/modules/AUDIT.md +192 -0
  26. package/docs/modules/AUTH.md +431 -0
  27. package/docs/modules/CACHE.md +346 -0
  28. package/docs/modules/EMAIL.md +254 -0
  29. package/docs/modules/FEATURE-FLAG.md +291 -0
  30. package/docs/modules/I18N.md +294 -0
  31. package/docs/modules/MEDIA-PROCESSING.md +281 -0
  32. package/docs/modules/MFA.md +266 -0
  33. package/docs/modules/NOTIFICATION.md +311 -0
  34. package/docs/modules/OAUTH.md +237 -0
  35. package/docs/modules/PAYMENT.md +804 -0
  36. package/docs/modules/QUEUE.md +540 -0
  37. package/docs/modules/RATE-LIMIT.md +339 -0
  38. package/docs/modules/SEARCH.md +288 -0
  39. package/docs/modules/SECURITY.md +327 -0
  40. package/docs/modules/SESSION.md +382 -0
  41. package/docs/modules/SWAGGER.md +305 -0
  42. package/docs/modules/UPLOAD.md +296 -0
  43. package/docs/modules/USER.md +505 -0
  44. package/docs/modules/VALIDATION.md +294 -0
  45. package/docs/modules/WEBHOOK.md +270 -0
  46. package/docs/modules/WEBSOCKET.md +691 -0
  47. package/package.json +53 -38
  48. package/prisma/schema.prisma +395 -1
  49. package/src/cli/commands/add-module.ts +520 -87
  50. package/src/cli/commands/db.ts +3 -4
  51. package/src/cli/commands/docs.ts +256 -6
  52. package/src/cli/commands/generate.ts +12 -19
  53. package/src/cli/commands/init.ts +384 -214
  54. package/src/cli/index.ts +0 -4
  55. package/src/cli/templates/repository.ts +6 -1
  56. package/src/cli/templates/routes.ts +6 -21
  57. package/src/cli/utils/docs-generator.ts +6 -7
  58. package/src/cli/utils/env-manager.ts +717 -0
  59. package/src/cli/utils/field-parser.ts +16 -7
  60. package/src/cli/utils/interactive-prompt.ts +223 -0
  61. package/src/cli/utils/template-manager.ts +346 -0
  62. package/src/config/database.config.ts +183 -0
  63. package/src/config/env.ts +0 -10
  64. package/src/config/index.ts +0 -14
  65. package/src/core/server.ts +1 -1
  66. package/src/database/adapters/mongoose.adapter.ts +132 -0
  67. package/src/database/adapters/prisma.adapter.ts +118 -0
  68. package/src/database/connection.ts +190 -0
  69. package/src/database/interfaces/database.interface.ts +85 -0
  70. package/src/database/interfaces/index.ts +7 -0
  71. package/src/database/interfaces/repository.interface.ts +129 -0
  72. package/src/database/models/mongoose/index.ts +7 -0
  73. package/src/database/models/mongoose/payment.schema.ts +347 -0
  74. package/src/database/models/mongoose/user.schema.ts +154 -0
  75. package/src/database/prisma.ts +1 -4
  76. package/src/database/redis.ts +101 -0
  77. package/src/database/repositories/mongoose/index.ts +7 -0
  78. package/src/database/repositories/mongoose/payment.repository.ts +380 -0
  79. package/src/database/repositories/mongoose/user.repository.ts +255 -0
  80. package/src/database/seed.ts +6 -1
  81. package/src/index.ts +9 -20
  82. package/src/middleware/security.ts +2 -6
  83. package/src/modules/analytics/analytics.routes.ts +80 -0
  84. package/src/modules/analytics/analytics.service.ts +364 -0
  85. package/src/modules/analytics/index.ts +18 -0
  86. package/src/modules/analytics/types.ts +180 -0
  87. package/src/modules/api-versioning/index.ts +15 -0
  88. package/src/modules/api-versioning/types.ts +86 -0
  89. package/src/modules/api-versioning/versioning.middleware.ts +120 -0
  90. package/src/modules/api-versioning/versioning.routes.ts +54 -0
  91. package/src/modules/api-versioning/versioning.service.ts +189 -0
  92. package/src/modules/audit/audit.repository.ts +206 -0
  93. package/src/modules/audit/audit.service.ts +27 -59
  94. package/src/modules/auth/auth.controller.ts +2 -2
  95. package/src/modules/auth/auth.middleware.ts +3 -9
  96. package/src/modules/auth/auth.routes.ts +10 -107
  97. package/src/modules/auth/auth.service.ts +126 -23
  98. package/src/modules/auth/index.ts +3 -4
  99. package/src/modules/cache/cache.service.ts +367 -0
  100. package/src/modules/cache/index.ts +10 -0
  101. package/src/modules/cache/types.ts +44 -0
  102. package/src/modules/email/email.service.ts +3 -10
  103. package/src/modules/email/templates.ts +2 -8
  104. package/src/modules/feature-flag/feature-flag.repository.ts +303 -0
  105. package/src/modules/feature-flag/feature-flag.routes.ts +247 -0
  106. package/src/modules/feature-flag/feature-flag.service.ts +566 -0
  107. package/src/modules/feature-flag/index.ts +20 -0
  108. package/src/modules/feature-flag/types.ts +192 -0
  109. package/src/modules/i18n/i18n.middleware.ts +186 -0
  110. package/src/modules/i18n/i18n.routes.ts +191 -0
  111. package/src/modules/i18n/i18n.service.ts +456 -0
  112. package/src/modules/i18n/index.ts +18 -0
  113. package/src/modules/i18n/types.ts +118 -0
  114. package/src/modules/media-processing/index.ts +17 -0
  115. package/src/modules/media-processing/media-processing.routes.ts +111 -0
  116. package/src/modules/media-processing/media-processing.service.ts +245 -0
  117. package/src/modules/media-processing/types.ts +156 -0
  118. package/src/modules/mfa/index.ts +20 -0
  119. package/src/modules/mfa/mfa.repository.ts +206 -0
  120. package/src/modules/mfa/mfa.routes.ts +595 -0
  121. package/src/modules/mfa/mfa.service.ts +572 -0
  122. package/src/modules/mfa/totp.ts +150 -0
  123. package/src/modules/mfa/types.ts +57 -0
  124. package/src/modules/notification/index.ts +20 -0
  125. package/src/modules/notification/notification.repository.ts +356 -0
  126. package/src/modules/notification/notification.service.ts +483 -0
  127. package/src/modules/notification/types.ts +119 -0
  128. package/src/modules/oauth/index.ts +20 -0
  129. package/src/modules/oauth/oauth.repository.ts +219 -0
  130. package/src/modules/oauth/oauth.routes.ts +446 -0
  131. package/src/modules/oauth/oauth.service.ts +293 -0
  132. package/src/modules/oauth/providers/apple.provider.ts +250 -0
  133. package/src/modules/oauth/providers/facebook.provider.ts +181 -0
  134. package/src/modules/oauth/providers/github.provider.ts +248 -0
  135. package/src/modules/oauth/providers/google.provider.ts +189 -0
  136. package/src/modules/oauth/providers/twitter.provider.ts +214 -0
  137. package/src/modules/oauth/types.ts +94 -0
  138. package/src/modules/payment/index.ts +19 -0
  139. package/src/modules/payment/payment.repository.ts +733 -0
  140. package/src/modules/payment/payment.routes.ts +390 -0
  141. package/src/modules/payment/payment.service.ts +354 -0
  142. package/src/modules/payment/providers/mobile-money.provider.ts +274 -0
  143. package/src/modules/payment/providers/paypal.provider.ts +190 -0
  144. package/src/modules/payment/providers/stripe.provider.ts +215 -0
  145. package/src/modules/payment/types.ts +140 -0
  146. package/src/modules/queue/cron.ts +438 -0
  147. package/src/modules/queue/index.ts +87 -0
  148. package/src/modules/queue/queue.routes.ts +600 -0
  149. package/src/modules/queue/queue.service.ts +842 -0
  150. package/src/modules/queue/types.ts +222 -0
  151. package/src/modules/queue/workers.ts +366 -0
  152. package/src/modules/rate-limit/index.ts +59 -0
  153. package/src/modules/rate-limit/rate-limit.middleware.ts +134 -0
  154. package/src/modules/rate-limit/rate-limit.routes.ts +269 -0
  155. package/src/modules/rate-limit/rate-limit.service.ts +348 -0
  156. package/src/modules/rate-limit/stores/memory.store.ts +165 -0
  157. package/src/modules/rate-limit/stores/redis.store.ts +322 -0
  158. package/src/modules/rate-limit/types.ts +153 -0
  159. package/src/modules/search/adapters/elasticsearch.adapter.ts +326 -0
  160. package/src/modules/search/adapters/meilisearch.adapter.ts +261 -0
  161. package/src/modules/search/adapters/memory.adapter.ts +278 -0
  162. package/src/modules/search/index.ts +21 -0
  163. package/src/modules/search/search.service.ts +234 -0
  164. package/src/modules/search/types.ts +214 -0
  165. package/src/modules/security/index.ts +40 -0
  166. package/src/modules/security/sanitize.ts +223 -0
  167. package/src/modules/security/security-audit.service.ts +388 -0
  168. package/src/modules/security/security.middleware.ts +398 -0
  169. package/src/modules/session/index.ts +3 -0
  170. package/src/modules/session/session.repository.ts +159 -0
  171. package/src/modules/session/session.service.ts +340 -0
  172. package/src/modules/session/types.ts +38 -0
  173. package/src/modules/swagger/index.ts +7 -1
  174. package/src/modules/swagger/schema-builder.ts +16 -4
  175. package/src/modules/swagger/swagger.service.ts +9 -10
  176. package/src/modules/swagger/types.ts +0 -2
  177. package/src/modules/upload/index.ts +14 -0
  178. package/src/modules/upload/types.ts +83 -0
  179. package/src/modules/upload/upload.repository.ts +199 -0
  180. package/src/modules/upload/upload.routes.ts +311 -0
  181. package/src/modules/upload/upload.service.ts +448 -0
  182. package/src/modules/user/index.ts +3 -3
  183. package/src/modules/user/user.controller.ts +15 -9
  184. package/src/modules/user/user.repository.ts +237 -113
  185. package/src/modules/user/user.routes.ts +39 -164
  186. package/src/modules/user/user.service.ts +4 -3
  187. package/src/modules/validation/validator.ts +12 -17
  188. package/src/modules/webhook/index.ts +91 -0
  189. package/src/modules/webhook/retry.ts +196 -0
  190. package/src/modules/webhook/signature.ts +135 -0
  191. package/src/modules/webhook/types.ts +181 -0
  192. package/src/modules/webhook/webhook.repository.ts +358 -0
  193. package/src/modules/webhook/webhook.routes.ts +442 -0
  194. package/src/modules/webhook/webhook.service.ts +457 -0
  195. package/src/modules/websocket/features.ts +504 -0
  196. package/src/modules/websocket/index.ts +106 -0
  197. package/src/modules/websocket/middlewares.ts +298 -0
  198. package/src/modules/websocket/types.ts +181 -0
  199. package/src/modules/websocket/websocket.service.ts +692 -0
  200. package/src/utils/errors.ts +7 -0
  201. package/src/utils/pagination.ts +4 -1
  202. package/tests/helpers/db-check.ts +79 -0
  203. package/tests/integration/auth-redis.test.ts +94 -0
  204. package/tests/integration/cache-redis.test.ts +387 -0
  205. package/tests/integration/mongoose-repositories.test.ts +410 -0
  206. package/tests/integration/payment-prisma.test.ts +637 -0
  207. package/tests/integration/queue-bullmq.test.ts +417 -0
  208. package/tests/integration/user-prisma.test.ts +441 -0
  209. package/tests/integration/websocket-socketio.test.ts +552 -0
  210. package/tests/setup.ts +11 -9
  211. package/vitest.config.ts +3 -8
  212. package/npm-cache/_cacache/content-v2/sha512/1c/d0/03440d500a0487621aad1d6402978340698976602046db8e24fa03c01ee6c022c69b0582f969042d9442ee876ac35c038e960dd427d1e622fa24b8eb7dba +0 -0
  213. package/npm-cache/_cacache/content-v2/sha512/42/55/28b493ca491833e5aab0e9c3108d29ab3f36c248ca88f45d4630674fce9130959e56ae308797ac2b6328fa7f09a610b9550ed09cb971d039876d293fc69d +0 -0
  214. package/npm-cache/_cacache/content-v2/sha512/e0/12/f360dc9315ee5f17844a0c8c233ee6bf7c30837c4a02ea0d56c61c7f7ab21c0e958e50ed2c57c59f983c762b93056778c9009b2398ffc26def0183999b13 +0 -0
  215. package/npm-cache/_cacache/content-v2/sha512/ed/b0/fae1161902898f4c913c67d7f6cdf6be0665aec3b389b9c4f4f0a101ca1da59badf1b59c4e0030f5223023b8d63cfe501c46a32c20c895d4fb3f11ca2232 +0 -0
  216. package/npm-cache/_cacache/index-v5/58/94/c2cba79e0f16b4c10e95a87e32255741149e8222cc314a476aab67c39cc0 +0 -5
@@ -0,0 +1,505 @@
1
+ # User Module Documentation
2
+
3
+ ## Overview
4
+
5
+ The User module manages user data persistence using Prisma ORM with PostgreSQL/MySQL/SQLite support. It provides a complete CRUD interface with pagination, filtering, and search capabilities.
6
+
7
+ ## Features
8
+
9
+ - ✅ Prisma ORM integration (PostgreSQL, MySQL, SQLite)
10
+ - ✅ Full CRUD operations
11
+ - ✅ Pagination and filtering
12
+ - ✅ Case-insensitive email search
13
+ - ✅ Role-based access control (RBAC)
14
+ - ✅ User status management
15
+ - ✅ Metadata storage (JSON field)
16
+ - ✅ Enum mapping (Prisma ↔ Application types)
17
+
18
+ ## Architecture
19
+
20
+ ### Components
21
+
22
+ 1. **UserRepository** (`user.repository.ts`)
23
+ - Data access layer using Prisma
24
+ - **Migrated from Map<> to Prisma** ✅ (Completed 2025-12-19)
25
+ - Handles type conversions between Prisma and application types
26
+
27
+ 2. **UserService** (`user.service.ts`)
28
+ - Business logic layer
29
+ - Delegates to repository for data operations
30
+
31
+ 3. **UserController** (`user.controller.ts`)
32
+ - HTTP request handlers
33
+ - Input validation
34
+ - Response formatting
35
+
36
+ ## Database Schema
37
+
38
+ The User model in Prisma:
39
+
40
+ ```prisma
41
+ model User {
42
+ id String @id @default(uuid())
43
+ email String @unique
44
+ password String
45
+ name String?
46
+ role UserRole @default(USER)
47
+ status UserStatus @default(ACTIVE)
48
+ emailVerified Boolean @default(false)
49
+ lastLoginAt DateTime?
50
+ metadata Json?
51
+
52
+ createdAt DateTime @default(now())
53
+ updatedAt DateTime @updatedAt
54
+
55
+ // Relations
56
+ refreshTokens RefreshToken[]
57
+ sessions Session[]
58
+ auditLogs AuditLog[]
59
+
60
+ @@index([email])
61
+ @@index([status])
62
+ @@index([role])
63
+ @@map("users")
64
+ }
65
+
66
+ enum UserRole {
67
+ USER
68
+ MODERATOR
69
+ ADMIN
70
+ SUPER_ADMIN
71
+ }
72
+
73
+ enum UserStatus {
74
+ ACTIVE
75
+ INACTIVE
76
+ SUSPENDED
77
+ BANNED
78
+ }
79
+ ```
80
+
81
+ ## Repository API
82
+
83
+ ### Create Operations
84
+
85
+ #### `create(data: CreateUserData): Promise<User>`
86
+
87
+ Create a new user.
88
+
89
+ ```typescript
90
+ const user = await userRepository.create({
91
+ email: 'user@example.com',
92
+ password: await authService.hashPassword('password123'),
93
+ name: 'John Doe',
94
+ role: 'user', // optional, defaults to 'user'
95
+ });
96
+ ```
97
+
98
+ **Features:**
99
+ - Email is automatically lowercased
100
+ - Default role: 'user'
101
+ - Default status: 'active'
102
+ - Default emailVerified: false
103
+ - Throws error on duplicate email
104
+
105
+ ### Read Operations
106
+
107
+ #### `findById(id: string): Promise<User | null>`
108
+
109
+ Find user by ID.
110
+
111
+ ```typescript
112
+ const user = await userRepository.findById('user-uuid');
113
+ if (user) {
114
+ console.log(user.email);
115
+ }
116
+ ```
117
+
118
+ #### `findByEmail(email: string): Promise<User | null>`
119
+
120
+ Find user by email (case-insensitive).
121
+
122
+ ```typescript
123
+ const user = await userRepository.findByEmail('USER@EXAMPLE.COM');
124
+ // Returns user with email 'user@example.com'
125
+ ```
126
+
127
+ #### `findMany(params: PaginationParams, filters?: UserFilters): Promise<PaginatedResult<User>>`
128
+
129
+ Find multiple users with pagination and filtering.
130
+
131
+ ```typescript
132
+ const result = await userRepository.findMany(
133
+ { page: 1, limit: 10, sortBy: 'createdAt', sortOrder: 'desc' },
134
+ { role: 'admin', status: 'active', search: 'john' }
135
+ );
136
+
137
+ console.log(result.data); // Array of users
138
+ console.log(result.meta); // Pagination metadata
139
+ ```
140
+
141
+ **Pagination params:**
142
+ - `page`: Page number (1-indexed)
143
+ - `limit`: Items per page
144
+ - `sortBy`: Field to sort by (optional)
145
+ - `sortOrder`: 'asc' or 'desc' (optional)
146
+
147
+ **Filter options:**
148
+ - `role`: Filter by role
149
+ - `status`: Filter by status
150
+ - `emailVerified`: Filter by verification status
151
+ - `search`: Search in email or name (case-insensitive)
152
+
153
+ ### Update Operations
154
+
155
+ #### `update(id: string, data: UpdateUserData): Promise<User | null>`
156
+
157
+ Update user data.
158
+
159
+ ```typescript
160
+ const updated = await userRepository.update('user-id', {
161
+ name: 'Jane Doe',
162
+ role: 'admin',
163
+ emailVerified: true,
164
+ metadata: { preferences: { theme: 'dark' } },
165
+ });
166
+ ```
167
+
168
+ **Updatable fields:**
169
+ - `email`
170
+ - `name`
171
+ - `role`
172
+ - `status`
173
+ - `emailVerified`
174
+ - `metadata`
175
+
176
+ #### `updatePassword(id: string, password: string): Promise<User | null>`
177
+
178
+ Update user password.
179
+
180
+ ```typescript
181
+ const newHash = await authService.hashPassword('newPassword123');
182
+ await userRepository.updatePassword('user-id', newHash);
183
+ ```
184
+
185
+ #### `updateLastLogin(id: string): Promise<User | null>`
186
+
187
+ Update last login timestamp.
188
+
189
+ ```typescript
190
+ await userRepository.updateLastLogin('user-id');
191
+ ```
192
+
193
+ ### Delete Operations
194
+
195
+ #### `delete(id: string): Promise<boolean>`
196
+
197
+ Delete user by ID.
198
+
199
+ ```typescript
200
+ const deleted = await userRepository.delete('user-id');
201
+ if (deleted) {
202
+ console.log('User deleted successfully');
203
+ }
204
+ ```
205
+
206
+ **Note:** Cascades to related records (sessions, refresh tokens, audit logs).
207
+
208
+ ### Count Operations
209
+
210
+ #### `count(filters?: UserFilters): Promise<number>`
211
+
212
+ Count users with optional filters.
213
+
214
+ ```typescript
215
+ const totalUsers = await userRepository.count();
216
+ const activeAdmins = await userRepository.count({ role: 'admin', status: 'active' });
217
+ ```
218
+
219
+ ### Testing Utilities
220
+
221
+ #### `clear(): Promise<void>`
222
+
223
+ **⚠️ WARNING:** Deletes all users from the database. Use only in tests.
224
+
225
+ ```typescript
226
+ // In test setup
227
+ beforeEach(async () => {
228
+ await userRepository.clear();
229
+ });
230
+ ```
231
+
232
+ ## User Roles
233
+
234
+ | Role | Description | Permissions |
235
+ |------|-------------|-------------|
236
+ | `user` | Regular user | Profile read/update |
237
+ | `moderator` | Content moderator | User read, content CRUD |
238
+ | `admin` | Administrator | User CRUD, settings read |
239
+ | `super_admin` | Super administrator | All permissions |
240
+
241
+ ## User Statuses
242
+
243
+ | Status | Description |
244
+ |--------|-------------|
245
+ | `active` | Normal active user |
246
+ | `inactive` | Inactive account (can be reactivated) |
247
+ | `suspended` | Temporarily suspended |
248
+ | `banned` | Permanently banned |
249
+
250
+ ## Type Mapping
251
+
252
+ The repository handles enum conversions between Prisma (UPPERCASE) and application types (lowercase):
253
+
254
+ | Application Type | Prisma Enum |
255
+ |------------------|-------------|
256
+ | `user` | `UserRole.USER` |
257
+ | `admin` | `UserRole.ADMIN` |
258
+ | `moderator` | `UserRole.MODERATOR` |
259
+ | `super_admin` | `UserRole.SUPER_ADMIN` |
260
+ | `active` | `UserStatus.ACTIVE` |
261
+ | `inactive` | `UserStatus.INACTIVE` |
262
+ | `suspended` | `UserStatus.SUSPENDED` |
263
+ | `banned` | `UserStatus.BANNED` |
264
+
265
+ This is handled automatically by private mapping methods.
266
+
267
+ ## Usage Examples
268
+
269
+ ### Complete User Lifecycle
270
+
271
+ ```typescript
272
+ import { UserRepository } from './modules/user/user.repository.js';
273
+ import { AuthService } from './modules/auth/auth.service.js';
274
+
275
+ const userRepo = new UserRepository();
276
+ const authService = new AuthService(app);
277
+
278
+ // 1. Create user
279
+ const user = await userRepo.create({
280
+ email: 'newuser@example.com',
281
+ password: await authService.hashPassword('SecurePass123!'),
282
+ name: 'New User',
283
+ });
284
+
285
+ // 2. Find user
286
+ const found = await userRepo.findByEmail('newuser@example.com');
287
+
288
+ // 3. Update user
289
+ await userRepo.update(user.id, {
290
+ emailVerified: true,
291
+ metadata: { onboarded: true },
292
+ });
293
+
294
+ // 4. Track login
295
+ await userRepo.updateLastLogin(user.id);
296
+
297
+ // 5. Promote to admin
298
+ await userRepo.update(user.id, { role: 'admin' });
299
+
300
+ // 6. Suspend user
301
+ await userRepo.update(user.id, { status: 'suspended' });
302
+
303
+ // 7. Delete user
304
+ await userRepo.delete(user.id);
305
+ ```
306
+
307
+ ### Admin Dashboard - User List
308
+
309
+ ```typescript
310
+ // Get paginated users with filters
311
+ const result = await userRepo.findMany(
312
+ {
313
+ page: 1,
314
+ limit: 20,
315
+ sortBy: 'createdAt',
316
+ sortOrder: 'desc'
317
+ },
318
+ {
319
+ status: 'active',
320
+ // Optional: filter by role
321
+ // role: 'user',
322
+ }
323
+ );
324
+
325
+ // Display results
326
+ result.data.forEach(user => {
327
+ console.log(`${user.name} (${user.email}) - ${user.role}`);
328
+ });
329
+
330
+ console.log(`Page ${result.meta.page} of ${result.meta.totalPages}`);
331
+ console.log(`Total users: ${result.meta.total}`);
332
+ ```
333
+
334
+ ### Search Users
335
+
336
+ ```typescript
337
+ // Search by name or email
338
+ const searchResult = await userRepo.findMany(
339
+ { page: 1, limit: 10 },
340
+ { search: 'john' }
341
+ );
342
+ // Returns users with 'john' in name or email
343
+ ```
344
+
345
+ ## Migration from In-Memory
346
+
347
+ **Previous implementation** (v0.1.0):
348
+ ```typescript
349
+ // ❌ OLD: In-memory storage
350
+ const users = new Map<string, User>();
351
+ ```
352
+
353
+ **Current implementation** (v0.2.0):
354
+ ```typescript
355
+ // ✅ NEW: Prisma ORM
356
+ await prisma.user.create({ data: { ... } });
357
+ ```
358
+
359
+ ### Migration Steps
360
+
361
+ 1. **Setup database** (if not already done):
362
+ ```bash
363
+ # PostgreSQL (recommended)
364
+ docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:16-alpine
365
+ ```
366
+
367
+ 2. **Configure environment**:
368
+ ```bash
369
+ echo "DATABASE_URL=postgresql://postgres:postgres@localhost:5432/servcraft" >> .env
370
+ ```
371
+
372
+ 3. **Run migrations**:
373
+ ```bash
374
+ npm run db:migrate
375
+ npm run db:seed
376
+ ```
377
+
378
+ 4. **Update code** (already done):
379
+ - UserRepository now uses Prisma
380
+ - All Map<> operations replaced with Prisma queries
381
+
382
+ 5. **Test**:
383
+ ```bash
384
+ npm test tests/integration/user-prisma.test.ts
385
+ ```
386
+
387
+ ## Performance Considerations
388
+
389
+ ### Indexes
390
+
391
+ The User table has indexes on:
392
+ - `email` (unique + indexed for fast lookups)
393
+ - `status` (for filtering)
394
+ - `role` (for filtering)
395
+
396
+ ### Query Optimization
397
+
398
+ - Use `findByEmail()` for single lookups (indexed)
399
+ - Use `findMany()` with filters instead of loading all users
400
+ - Leverage pagination to avoid loading large datasets
401
+ - The `search` filter uses case-insensitive matching (may be slower on large datasets)
402
+
403
+ ### N+1 Query Prevention
404
+
405
+ ```typescript
406
+ // ❌ BAD: N+1 queries
407
+ const users = await userRepo.findMany({ page: 1, limit: 100 });
408
+ for (const user of users.data) {
409
+ const sessions = await prisma.session.findMany({ where: { userId: user.id } });
410
+ }
411
+
412
+ // ✅ GOOD: Use Prisma includes (future enhancement)
413
+ // Currently, the repository doesn't expose relations
414
+ // Use separate queries or extend the repository
415
+ ```
416
+
417
+ ## Production Checklist
418
+
419
+ - [x] Prisma client generated (`npm run db:generate`)
420
+ - [x] Migrations applied (`npm run db:migrate`)
421
+ - [ ] Database connection pooling configured
422
+ - [ ] Backup strategy in place
423
+ - [ ] Monitor slow queries
424
+ - [ ] Set up read replicas (for high traffic)
425
+ - [ ] Regular vacuum/analyze (PostgreSQL)
426
+
427
+ ## Troubleshooting
428
+
429
+ ### "No users found after restart"
430
+
431
+ **Problem**: Users created in previous session are gone.
432
+
433
+ **Solution**: With Prisma, this is no longer an issue. Data persists in the database.
434
+
435
+ ### "Prisma Client not generated"
436
+
437
+ **Problem**: Import errors with `@prisma/client`.
438
+
439
+ **Solution**:
440
+ ```bash
441
+ npm run db:generate
442
+ ```
443
+
444
+ ### "Database connection failed"
445
+
446
+ **Problem**: Can't connect to database.
447
+
448
+ **Solution**:
449
+ 1. Check if database is running: `pg_isready` (PostgreSQL)
450
+ 2. Verify `DATABASE_URL` in `.env`
451
+ 3. Check network connectivity
452
+ 4. Verify credentials
453
+
454
+ ### "Migration failed"
455
+
456
+ **Problem**: `npm run db:migrate` fails.
457
+
458
+ **Solution**:
459
+ ```bash
460
+ # Reset database (dev only!)
461
+ npm run db:push
462
+
463
+ # Or manually fix migration
464
+ npx prisma migrate resolve --rolled-back <migration-name>
465
+ ```
466
+
467
+ ## Testing
468
+
469
+ Run user repository tests:
470
+ ```bash
471
+ # All user tests
472
+ npm test tests/integration/user-prisma.test.ts
473
+
474
+ # With coverage
475
+ npm run test:coverage -- tests/integration/user-prisma.test.ts
476
+ ```
477
+
478
+ **Test coverage:** 100% (all CRUD operations, filtering, pagination, enum mapping)
479
+
480
+ ## Related Modules
481
+
482
+ - **Auth Module**: User authentication and JWT tokens
483
+ - **Audit Module**: Track user actions
484
+ - **Session Module**: User sessions (via RefreshToken, Session models)
485
+
486
+ ## API Reference
487
+
488
+ See `src/modules/user/types.ts` for complete type definitions.
489
+
490
+ ## Changelog
491
+
492
+ ### v0.2.0 (2025-12-19)
493
+
494
+ **USER-001 Completed:**
495
+ - ✅ Migrated from `Map<string, User>` to Prisma ORM
496
+ - ✅ Added full test coverage (33 integration tests)
497
+ - ✅ Implemented enum mapping (Prisma ↔ Application)
498
+ - ✅ Preserved API compatibility (no breaking changes to public interface)
499
+ - ✅ Added this documentation
500
+
501
+ ### v0.1.0 (Initial)
502
+
503
+ - In-memory storage with Map<>
504
+ - Basic CRUD operations
505
+ - No persistence across restarts