servcraft 0.1.0 → 0.1.3

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 (217) hide show
  1. package/.claude/settings.local.json +30 -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/LICENSE +21 -0
  9. package/README.md +1102 -1
  10. package/dist/cli/index.cjs +2026 -2168
  11. package/dist/cli/index.cjs.map +1 -1
  12. package/dist/cli/index.js +2026 -2168
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/index.cjs +595 -616
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +114 -52
  17. package/dist/index.d.ts +114 -52
  18. package/dist/index.js +595 -616
  19. package/dist/index.js.map +1 -1
  20. package/docs/CLI-001_MULTI_DB_PLAN.md +546 -0
  21. package/docs/DATABASE_MULTI_ORM.md +399 -0
  22. package/docs/PHASE1_BREAKDOWN.md +346 -0
  23. package/docs/PROGRESS.md +550 -0
  24. package/docs/modules/ANALYTICS.md +226 -0
  25. package/docs/modules/API-VERSIONING.md +252 -0
  26. package/docs/modules/AUDIT.md +192 -0
  27. package/docs/modules/AUTH.md +431 -0
  28. package/docs/modules/CACHE.md +346 -0
  29. package/docs/modules/EMAIL.md +254 -0
  30. package/docs/modules/FEATURE-FLAG.md +291 -0
  31. package/docs/modules/I18N.md +294 -0
  32. package/docs/modules/MEDIA-PROCESSING.md +281 -0
  33. package/docs/modules/MFA.md +266 -0
  34. package/docs/modules/NOTIFICATION.md +311 -0
  35. package/docs/modules/OAUTH.md +237 -0
  36. package/docs/modules/PAYMENT.md +804 -0
  37. package/docs/modules/QUEUE.md +540 -0
  38. package/docs/modules/RATE-LIMIT.md +339 -0
  39. package/docs/modules/SEARCH.md +288 -0
  40. package/docs/modules/SECURITY.md +327 -0
  41. package/docs/modules/SESSION.md +382 -0
  42. package/docs/modules/SWAGGER.md +305 -0
  43. package/docs/modules/UPLOAD.md +296 -0
  44. package/docs/modules/USER.md +505 -0
  45. package/docs/modules/VALIDATION.md +294 -0
  46. package/docs/modules/WEBHOOK.md +270 -0
  47. package/docs/modules/WEBSOCKET.md +691 -0
  48. package/package.json +53 -38
  49. package/prisma/schema.prisma +395 -1
  50. package/src/cli/commands/add-module.ts +520 -87
  51. package/src/cli/commands/db.ts +3 -4
  52. package/src/cli/commands/docs.ts +256 -6
  53. package/src/cli/commands/generate.ts +12 -19
  54. package/src/cli/commands/init.ts +384 -214
  55. package/src/cli/index.ts +0 -4
  56. package/src/cli/templates/repository.ts +6 -1
  57. package/src/cli/templates/routes.ts +6 -21
  58. package/src/cli/utils/docs-generator.ts +6 -7
  59. package/src/cli/utils/env-manager.ts +717 -0
  60. package/src/cli/utils/field-parser.ts +16 -7
  61. package/src/cli/utils/interactive-prompt.ts +223 -0
  62. package/src/cli/utils/template-manager.ts +346 -0
  63. package/src/config/database.config.ts +183 -0
  64. package/src/config/env.ts +0 -10
  65. package/src/config/index.ts +0 -14
  66. package/src/core/server.ts +1 -1
  67. package/src/database/adapters/mongoose.adapter.ts +132 -0
  68. package/src/database/adapters/prisma.adapter.ts +118 -0
  69. package/src/database/connection.ts +190 -0
  70. package/src/database/interfaces/database.interface.ts +85 -0
  71. package/src/database/interfaces/index.ts +7 -0
  72. package/src/database/interfaces/repository.interface.ts +129 -0
  73. package/src/database/models/mongoose/index.ts +7 -0
  74. package/src/database/models/mongoose/payment.schema.ts +347 -0
  75. package/src/database/models/mongoose/user.schema.ts +154 -0
  76. package/src/database/prisma.ts +1 -4
  77. package/src/database/redis.ts +101 -0
  78. package/src/database/repositories/mongoose/index.ts +7 -0
  79. package/src/database/repositories/mongoose/payment.repository.ts +380 -0
  80. package/src/database/repositories/mongoose/user.repository.ts +255 -0
  81. package/src/database/seed.ts +6 -1
  82. package/src/index.ts +9 -20
  83. package/src/middleware/security.ts +2 -6
  84. package/src/modules/analytics/analytics.routes.ts +80 -0
  85. package/src/modules/analytics/analytics.service.ts +364 -0
  86. package/src/modules/analytics/index.ts +18 -0
  87. package/src/modules/analytics/types.ts +180 -0
  88. package/src/modules/api-versioning/index.ts +15 -0
  89. package/src/modules/api-versioning/types.ts +86 -0
  90. package/src/modules/api-versioning/versioning.middleware.ts +120 -0
  91. package/src/modules/api-versioning/versioning.routes.ts +54 -0
  92. package/src/modules/api-versioning/versioning.service.ts +189 -0
  93. package/src/modules/audit/audit.repository.ts +206 -0
  94. package/src/modules/audit/audit.service.ts +27 -59
  95. package/src/modules/auth/auth.controller.ts +2 -2
  96. package/src/modules/auth/auth.middleware.ts +3 -9
  97. package/src/modules/auth/auth.routes.ts +10 -107
  98. package/src/modules/auth/auth.service.ts +126 -23
  99. package/src/modules/auth/index.ts +3 -4
  100. package/src/modules/cache/cache.service.ts +367 -0
  101. package/src/modules/cache/index.ts +10 -0
  102. package/src/modules/cache/types.ts +44 -0
  103. package/src/modules/email/email.service.ts +3 -10
  104. package/src/modules/email/templates.ts +2 -8
  105. package/src/modules/feature-flag/feature-flag.repository.ts +303 -0
  106. package/src/modules/feature-flag/feature-flag.routes.ts +247 -0
  107. package/src/modules/feature-flag/feature-flag.service.ts +566 -0
  108. package/src/modules/feature-flag/index.ts +20 -0
  109. package/src/modules/feature-flag/types.ts +192 -0
  110. package/src/modules/i18n/i18n.middleware.ts +186 -0
  111. package/src/modules/i18n/i18n.routes.ts +191 -0
  112. package/src/modules/i18n/i18n.service.ts +456 -0
  113. package/src/modules/i18n/index.ts +18 -0
  114. package/src/modules/i18n/types.ts +118 -0
  115. package/src/modules/media-processing/index.ts +17 -0
  116. package/src/modules/media-processing/media-processing.routes.ts +111 -0
  117. package/src/modules/media-processing/media-processing.service.ts +245 -0
  118. package/src/modules/media-processing/types.ts +156 -0
  119. package/src/modules/mfa/index.ts +20 -0
  120. package/src/modules/mfa/mfa.repository.ts +206 -0
  121. package/src/modules/mfa/mfa.routes.ts +595 -0
  122. package/src/modules/mfa/mfa.service.ts +572 -0
  123. package/src/modules/mfa/totp.ts +150 -0
  124. package/src/modules/mfa/types.ts +57 -0
  125. package/src/modules/notification/index.ts +20 -0
  126. package/src/modules/notification/notification.repository.ts +356 -0
  127. package/src/modules/notification/notification.service.ts +483 -0
  128. package/src/modules/notification/types.ts +119 -0
  129. package/src/modules/oauth/index.ts +20 -0
  130. package/src/modules/oauth/oauth.repository.ts +219 -0
  131. package/src/modules/oauth/oauth.routes.ts +446 -0
  132. package/src/modules/oauth/oauth.service.ts +293 -0
  133. package/src/modules/oauth/providers/apple.provider.ts +250 -0
  134. package/src/modules/oauth/providers/facebook.provider.ts +181 -0
  135. package/src/modules/oauth/providers/github.provider.ts +248 -0
  136. package/src/modules/oauth/providers/google.provider.ts +189 -0
  137. package/src/modules/oauth/providers/twitter.provider.ts +214 -0
  138. package/src/modules/oauth/types.ts +94 -0
  139. package/src/modules/payment/index.ts +19 -0
  140. package/src/modules/payment/payment.repository.ts +733 -0
  141. package/src/modules/payment/payment.routes.ts +390 -0
  142. package/src/modules/payment/payment.service.ts +354 -0
  143. package/src/modules/payment/providers/mobile-money.provider.ts +274 -0
  144. package/src/modules/payment/providers/paypal.provider.ts +190 -0
  145. package/src/modules/payment/providers/stripe.provider.ts +215 -0
  146. package/src/modules/payment/types.ts +140 -0
  147. package/src/modules/queue/cron.ts +438 -0
  148. package/src/modules/queue/index.ts +87 -0
  149. package/src/modules/queue/queue.routes.ts +600 -0
  150. package/src/modules/queue/queue.service.ts +842 -0
  151. package/src/modules/queue/types.ts +222 -0
  152. package/src/modules/queue/workers.ts +366 -0
  153. package/src/modules/rate-limit/index.ts +59 -0
  154. package/src/modules/rate-limit/rate-limit.middleware.ts +134 -0
  155. package/src/modules/rate-limit/rate-limit.routes.ts +269 -0
  156. package/src/modules/rate-limit/rate-limit.service.ts +348 -0
  157. package/src/modules/rate-limit/stores/memory.store.ts +165 -0
  158. package/src/modules/rate-limit/stores/redis.store.ts +322 -0
  159. package/src/modules/rate-limit/types.ts +153 -0
  160. package/src/modules/search/adapters/elasticsearch.adapter.ts +326 -0
  161. package/src/modules/search/adapters/meilisearch.adapter.ts +261 -0
  162. package/src/modules/search/adapters/memory.adapter.ts +278 -0
  163. package/src/modules/search/index.ts +21 -0
  164. package/src/modules/search/search.service.ts +234 -0
  165. package/src/modules/search/types.ts +214 -0
  166. package/src/modules/security/index.ts +40 -0
  167. package/src/modules/security/sanitize.ts +223 -0
  168. package/src/modules/security/security-audit.service.ts +388 -0
  169. package/src/modules/security/security.middleware.ts +398 -0
  170. package/src/modules/session/index.ts +3 -0
  171. package/src/modules/session/session.repository.ts +159 -0
  172. package/src/modules/session/session.service.ts +340 -0
  173. package/src/modules/session/types.ts +38 -0
  174. package/src/modules/swagger/index.ts +7 -1
  175. package/src/modules/swagger/schema-builder.ts +16 -4
  176. package/src/modules/swagger/swagger.service.ts +9 -10
  177. package/src/modules/swagger/types.ts +0 -2
  178. package/src/modules/upload/index.ts +14 -0
  179. package/src/modules/upload/types.ts +83 -0
  180. package/src/modules/upload/upload.repository.ts +199 -0
  181. package/src/modules/upload/upload.routes.ts +311 -0
  182. package/src/modules/upload/upload.service.ts +448 -0
  183. package/src/modules/user/index.ts +3 -3
  184. package/src/modules/user/user.controller.ts +15 -9
  185. package/src/modules/user/user.repository.ts +237 -113
  186. package/src/modules/user/user.routes.ts +39 -164
  187. package/src/modules/user/user.service.ts +4 -3
  188. package/src/modules/validation/validator.ts +12 -17
  189. package/src/modules/webhook/index.ts +91 -0
  190. package/src/modules/webhook/retry.ts +196 -0
  191. package/src/modules/webhook/signature.ts +135 -0
  192. package/src/modules/webhook/types.ts +181 -0
  193. package/src/modules/webhook/webhook.repository.ts +358 -0
  194. package/src/modules/webhook/webhook.routes.ts +442 -0
  195. package/src/modules/webhook/webhook.service.ts +457 -0
  196. package/src/modules/websocket/features.ts +504 -0
  197. package/src/modules/websocket/index.ts +106 -0
  198. package/src/modules/websocket/middlewares.ts +298 -0
  199. package/src/modules/websocket/types.ts +181 -0
  200. package/src/modules/websocket/websocket.service.ts +692 -0
  201. package/src/utils/errors.ts +7 -0
  202. package/src/utils/pagination.ts +4 -1
  203. package/tests/helpers/db-check.ts +79 -0
  204. package/tests/integration/auth-redis.test.ts +94 -0
  205. package/tests/integration/cache-redis.test.ts +387 -0
  206. package/tests/integration/mongoose-repositories.test.ts +410 -0
  207. package/tests/integration/payment-prisma.test.ts +637 -0
  208. package/tests/integration/queue-bullmq.test.ts +417 -0
  209. package/tests/integration/user-prisma.test.ts +441 -0
  210. package/tests/integration/websocket-socketio.test.ts +552 -0
  211. package/tests/setup.ts +11 -9
  212. package/vitest.config.ts +3 -8
  213. package/npm-cache/_cacache/content-v2/sha512/1c/d0/03440d500a0487621aad1d6402978340698976602046db8e24fa03c01ee6c022c69b0582f969042d9442ee876ac35c038e960dd427d1e622fa24b8eb7dba +0 -0
  214. package/npm-cache/_cacache/content-v2/sha512/42/55/28b493ca491833e5aab0e9c3108d29ab3f36c248ca88f45d4630674fce9130959e56ae308797ac2b6328fa7f09a610b9550ed09cb971d039876d293fc69d +0 -0
  215. package/npm-cache/_cacache/content-v2/sha512/e0/12/f360dc9315ee5f17844a0c8c233ee6bf7c30837c4a02ea0d56c61c7f7ab21c0e958e50ed2c57c59f983c762b93056778c9009b2398ffc26def0183999b13 +0 -0
  216. package/npm-cache/_cacache/content-v2/sha512/ed/b0/fae1161902898f4c913c67d7f6cdf6be0665aec3b389b9c4f4f0a101ca1da59badf1b59c4e0030f5223023b8d63cfe501c46a32c20c895d4fb3f11ca2232 +0 -0
  217. package/npm-cache/_cacache/index-v5/58/94/c2cba79e0f16b4c10e95a87e32255741149e8222cc314a476aab67c39cc0 +0 -5
@@ -0,0 +1,291 @@
1
+ # Feature Flag Module
2
+
3
+ Feature flags for A/B testing, progressive rollouts, and feature management.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Strategies** - Boolean, percentage, user list, user attributes, date range
8
+ - **User Targeting** - Target specific users or user segments
9
+ - **Overrides** - Per-user or per-session overrides
10
+ - **Analytics** - Track flag evaluations and usage statistics
11
+ - **Environment Support** - Different flags per environment
12
+
13
+ ## Architecture
14
+
15
+ ```
16
+ ┌──────────────────────────────────────────────────────────────┐
17
+ │ Feature Flag Service │
18
+ ├──────────────────────────────────────────────────────────────┤
19
+ │ Flag CRUD │ Evaluation Engine │ Override Mgmt │ Stats │
20
+ └──────┬──────┴─────────┬───────────┴────────┬────────┴───┬────┘
21
+ │ │ │ │
22
+ ▼ ▼ ▼ ▼
23
+ ┌──────────────────────────────────────────────────────────────┐
24
+ │ Prisma (Flags & Overrides) │
25
+ │ Redis (Statistics) │
26
+ └──────────────────────────────────────────────────────────────┘
27
+ ```
28
+
29
+ ## Strategies
30
+
31
+ | Strategy | Description | Use Case |
32
+ |----------|-------------|----------|
33
+ | `boolean` | Simple on/off | Kill switches |
34
+ | `percentage` | Percentage rollout | Gradual releases |
35
+ | `user-list` | Specific user IDs | Beta testers |
36
+ | `user-attribute` | User property rules | Segment targeting |
37
+ | `date-range` | Time-based activation | Scheduled features |
38
+
39
+ ## Usage
40
+
41
+ ### Basic Setup
42
+
43
+ ```typescript
44
+ import { createFeatureFlagService } from 'servcraft/modules/feature-flag';
45
+
46
+ const flagService = createFeatureFlagService({
47
+ defaultEnvironment: 'production',
48
+ analytics: true,
49
+ cacheTtl: 300,
50
+ });
51
+ ```
52
+
53
+ ### Creating Flags
54
+
55
+ ```typescript
56
+ // Boolean flag
57
+ await flagService.createFlag({
58
+ key: 'new-dashboard',
59
+ name: 'New Dashboard',
60
+ description: 'Enable the redesigned dashboard',
61
+ strategy: 'boolean',
62
+ config: { value: false },
63
+ status: 'active',
64
+ environment: 'production',
65
+ });
66
+
67
+ // Percentage rollout
68
+ await flagService.createFlag({
69
+ key: 'new-checkout',
70
+ name: 'New Checkout Flow',
71
+ strategy: 'percentage',
72
+ config: { percentage: 25 }, // 25% of users
73
+ status: 'active',
74
+ });
75
+
76
+ // User list (beta testers)
77
+ await flagService.createFlag({
78
+ key: 'beta-features',
79
+ name: 'Beta Features',
80
+ strategy: 'user-list',
81
+ config: { userIds: ['user-1', 'user-2', 'user-3'] },
82
+ status: 'active',
83
+ });
84
+
85
+ // User attributes
86
+ await flagService.createFlag({
87
+ key: 'premium-features',
88
+ name: 'Premium Features',
89
+ strategy: 'user-attribute',
90
+ config: {
91
+ userAttributes: [
92
+ { attribute: 'plan', operator: 'in', value: ['pro', 'enterprise'] },
93
+ { attribute: 'accountAge', operator: 'gte', value: 30 },
94
+ ],
95
+ },
96
+ status: 'active',
97
+ });
98
+
99
+ // Date range
100
+ await flagService.createFlag({
101
+ key: 'holiday-theme',
102
+ name: 'Holiday Theme',
103
+ strategy: 'date-range',
104
+ config: {
105
+ dateRange: {
106
+ start: '2024-12-20T00:00:00Z',
107
+ end: '2025-01-02T23:59:59Z',
108
+ },
109
+ },
110
+ status: 'active',
111
+ });
112
+ ```
113
+
114
+ ### Evaluating Flags
115
+
116
+ ```typescript
117
+ // Simple check
118
+ const isEnabled = await flagService.isEnabled('new-dashboard', {
119
+ userId: 'user-123',
120
+ environment: 'production',
121
+ });
122
+
123
+ // Full evaluation with reason
124
+ const result = await flagService.evaluateFlag('new-checkout', {
125
+ userId: 'user-123',
126
+ sessionId: 'session-456',
127
+ environment: 'production',
128
+ userAttributes: {
129
+ plan: 'pro',
130
+ accountAge: 45,
131
+ country: 'US',
132
+ },
133
+ });
134
+ // {
135
+ // key: 'new-checkout',
136
+ // enabled: true,
137
+ // reason: 'Percentage rollout: 25%',
138
+ // strategy: 'percentage',
139
+ // evaluatedAt: Date
140
+ // }
141
+
142
+ // Evaluate multiple flags
143
+ const flags = await flagService.evaluateFlags(
144
+ ['new-dashboard', 'new-checkout', 'beta-features'],
145
+ { userId: 'user-123' }
146
+ );
147
+ // { 'new-dashboard': {...}, 'new-checkout': {...}, 'beta-features': {...} }
148
+ ```
149
+
150
+ ### Managing Flags
151
+
152
+ ```typescript
153
+ // Update flag
154
+ await flagService.updateFlag('new-checkout', {
155
+ config: { percentage: 50 }, // Increase to 50%
156
+ });
157
+
158
+ // Get flag
159
+ const flag = await flagService.getFlag('new-checkout');
160
+
161
+ // List flags
162
+ const allFlags = await flagService.listFlags({
163
+ status: 'active',
164
+ environment: 'production',
165
+ });
166
+
167
+ // Delete flag
168
+ await flagService.deleteFlag('old-feature');
169
+ ```
170
+
171
+ ### Overrides
172
+
173
+ ```typescript
174
+ // Set user override (for testing/support)
175
+ await flagService.setOverride(
176
+ 'new-checkout',
177
+ 'user-123',
178
+ 'user',
179
+ true, // force enabled
180
+ new Date('2024-02-01') // expires
181
+ );
182
+
183
+ // Set session override
184
+ await flagService.setOverride('new-checkout', 'session-456', 'session', false);
185
+
186
+ // Remove override
187
+ await flagService.removeOverride('new-checkout', 'user-123');
188
+ ```
189
+
190
+ ### Statistics
191
+
192
+ ```typescript
193
+ const stats = await flagService.getStats('new-checkout');
194
+ // {
195
+ // totalEvaluations: 10000,
196
+ // enabledCount: 2500,
197
+ // disabledCount: 7500,
198
+ // uniqueUsers: 5000,
199
+ // lastEvaluatedAt: Date
200
+ // }
201
+
202
+ // Get events for a flag
203
+ const events = await flagService.getEvents('new-checkout', 100);
204
+ ```
205
+
206
+ ## Attribute Operators
207
+
208
+ | Operator | Description | Example |
209
+ |----------|-------------|---------|
210
+ | `eq` | Equals | `{ attribute: 'plan', operator: 'eq', value: 'pro' }` |
211
+ | `ne` | Not equals | `{ attribute: 'status', operator: 'ne', value: 'banned' }` |
212
+ | `in` | In array | `{ attribute: 'country', operator: 'in', value: ['US', 'CA'] }` |
213
+ | `nin` | Not in array | `{ attribute: 'role', operator: 'nin', value: ['guest'] }` |
214
+ | `gt` | Greater than | `{ attribute: 'age', operator: 'gt', value: 18 }` |
215
+ | `gte` | Greater or equal | `{ attribute: 'score', operator: 'gte', value: 100 }` |
216
+ | `lt` | Less than | `{ attribute: 'failedLogins', operator: 'lt', value: 5 }` |
217
+ | `lte` | Less or equal | `{ attribute: 'cart', operator: 'lte', value: 1000 }` |
218
+ | `contains` | String contains | `{ attribute: 'email', operator: 'contains', value: '@company.com' }` |
219
+ | `starts-with` | String starts with | `{ attribute: 'name', operator: 'starts-with', value: 'Admin' }` |
220
+ | `ends-with` | String ends with | `{ attribute: 'domain', operator: 'ends-with', value: '.edu' }` |
221
+
222
+ ## Types
223
+
224
+ ```typescript
225
+ interface FeatureFlag {
226
+ key: string;
227
+ name: string;
228
+ description?: string;
229
+ strategy: 'boolean' | 'percentage' | 'user-list' | 'user-attribute' | 'date-range';
230
+ config: FlagConfig;
231
+ status: 'active' | 'disabled' | 'archived';
232
+ environment?: string;
233
+ tags?: string[];
234
+ createdBy?: string;
235
+ createdAt: Date;
236
+ updatedAt: Date;
237
+ }
238
+
239
+ interface FlagEvaluationContext {
240
+ userId?: string;
241
+ sessionId?: string;
242
+ environment?: string;
243
+ userAttributes?: Record<string, string | number | boolean>;
244
+ }
245
+
246
+ interface FlagEvaluationResult {
247
+ key: string;
248
+ enabled: boolean;
249
+ reason: string;
250
+ strategy: string;
251
+ evaluatedAt: Date;
252
+ }
253
+ ```
254
+
255
+ ## React Integration Example
256
+
257
+ ```typescript
258
+ // Hook
259
+ function useFeatureFlag(key: string): boolean {
260
+ const [enabled, setEnabled] = useState(false);
261
+ const user = useUser();
262
+
263
+ useEffect(() => {
264
+ flagService.isEnabled(key, {
265
+ userId: user.id,
266
+ userAttributes: {
267
+ plan: user.plan,
268
+ country: user.country,
269
+ },
270
+ }).then(setEnabled);
271
+ }, [key, user]);
272
+
273
+ return enabled;
274
+ }
275
+
276
+ // Usage
277
+ function Dashboard() {
278
+ const showNewDashboard = useFeatureFlag('new-dashboard');
279
+
280
+ return showNewDashboard ? <NewDashboard /> : <OldDashboard />;
281
+ }
282
+ ```
283
+
284
+ ## Best Practices
285
+
286
+ 1. **Naming Convention** - Use kebab-case: `new-feature`, `beta-checkout`
287
+ 2. **Short-lived Flags** - Remove flags after full rollout
288
+ 3. **Default Off** - New flags should default to disabled
289
+ 4. **Documentation** - Add descriptions to all flags
290
+ 5. **Cleanup** - Archive unused flags regularly
291
+ 6. **Testing** - Use overrides for testing specific states
@@ -0,0 +1,294 @@
1
+ # I18n Module
2
+
3
+ Internationalization and localization support for multi-language applications.
4
+
5
+ ## Features
6
+
7
+ - **Translation Management** - Load and manage translations from files or programmatically
8
+ - **Variable Interpolation** - Dynamic values in translations
9
+ - **Pluralization** - Proper plural forms using Intl.PluralRules
10
+ - **Date/Number/Currency Formatting** - Locale-aware formatting
11
+ - **Relative Time** - Human-readable relative time (e.g., "2 hours ago")
12
+ - **RTL Support** - Right-to-left language support
13
+
14
+ ## Supported Locales (Built-in)
15
+
16
+ | Code | Language | Direction | Currency |
17
+ |------|----------|-----------|----------|
18
+ | `en` | English | LTR | USD |
19
+ | `fr` | Français | LTR | EUR |
20
+ | `es` | Español | LTR | EUR |
21
+ | `de` | Deutsch | LTR | EUR |
22
+ | `ar` | العربية | RTL | SAR |
23
+ | `zh` | 中文 | LTR | CNY |
24
+ | `ja` | 日本語 | LTR | JPY |
25
+
26
+ ## Usage
27
+
28
+ ### Configuration
29
+
30
+ ```typescript
31
+ import { I18nService } from 'servcraft/modules/i18n';
32
+
33
+ const i18n = new I18nService({
34
+ defaultLocale: 'en',
35
+ supportedLocales: ['en', 'fr', 'es', 'de'],
36
+ fallbackLocale: 'en',
37
+ translationsDir: './locales',
38
+ cache: true,
39
+ debug: false,
40
+ });
41
+
42
+ // Load translations from files
43
+ await i18n.loadTranslations('en', 'common');
44
+ await i18n.loadTranslations('fr', 'common');
45
+ ```
46
+
47
+ ### File Structure
48
+
49
+ ```
50
+ locales/
51
+ ├── en/
52
+ │ ├── common.json
53
+ │ └── errors.json
54
+ ├── fr/
55
+ │ ├── common.json
56
+ │ └── errors.json
57
+ └── es/
58
+ ├── common.json
59
+ └── errors.json
60
+ ```
61
+
62
+ ### Translation File Format
63
+
64
+ ```json
65
+ // locales/en/common.json
66
+ {
67
+ "welcome": "Welcome, {{name}}!",
68
+ "items": "You have {{count}} item{s}",
69
+ "user": {
70
+ "profile": {
71
+ "title": "User Profile",
72
+ "settings": "Settings"
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ ### Basic Translation
79
+
80
+ ```typescript
81
+ // Simple translation
82
+ const text = i18n.t('welcome');
83
+ // "Welcome, {{name}}!"
84
+
85
+ // With locale
86
+ const frText = i18n.t('welcome', { locale: 'fr' });
87
+
88
+ // With namespace
89
+ const errorText = i18n.t('notFound', { namespace: 'errors' });
90
+
91
+ // Nested keys
92
+ const title = i18n.t('user.profile.title');
93
+ // "User Profile"
94
+ ```
95
+
96
+ ### Variable Interpolation
97
+
98
+ ```typescript
99
+ const welcome = i18n.t('welcome', {
100
+ variables: { name: 'John' }
101
+ });
102
+ // "Welcome, John!"
103
+ ```
104
+
105
+ ### Pluralization
106
+
107
+ ```typescript
108
+ // Translation: "You have {{count}} item{s}"
109
+ const items1 = i18n.t('items', { count: 1 });
110
+ // "You have 1 item"
111
+
112
+ const items5 = i18n.t('items', { count: 5 });
113
+ // "You have 5 items"
114
+ ```
115
+
116
+ ### Formatting
117
+
118
+ ```typescript
119
+ // Date formatting
120
+ const date = i18n.formatDate(new Date(), 'en', {
121
+ year: 'numeric',
122
+ month: 'long',
123
+ day: 'numeric',
124
+ });
125
+ // "December 20, 2024"
126
+
127
+ // Number formatting
128
+ const number = i18n.formatNumber(1234567.89, 'de');
129
+ // "1.234.567,89"
130
+
131
+ // Currency formatting
132
+ const price = i18n.formatCurrency(99.99, 'en', 'USD');
133
+ // "$99.99"
134
+
135
+ const euroPrice = i18n.formatCurrency(99.99, 'fr', 'EUR');
136
+ // "99,99 €"
137
+
138
+ // Relative time
139
+ const relative = i18n.formatRelativeTime(new Date(Date.now() - 3600000), 'en');
140
+ // "1 hour ago"
141
+ ```
142
+
143
+ ### Programmatic Translations
144
+
145
+ ```typescript
146
+ // Add translations at runtime
147
+ i18n.addTranslations({
148
+ locale: 'en',
149
+ namespace: 'common',
150
+ data: {
151
+ newFeature: 'Check out our new feature!',
152
+ button: {
153
+ save: 'Save',
154
+ cancel: 'Cancel',
155
+ },
156
+ },
157
+ });
158
+ ```
159
+
160
+ ### Locale Information
161
+
162
+ ```typescript
163
+ // Get locale info
164
+ const info = i18n.getLocaleInfo('ar');
165
+ // {
166
+ // code: 'ar',
167
+ // name: 'العربية',
168
+ // englishName: 'Arabic',
169
+ // direction: 'rtl',
170
+ // dateFormat: 'DD/MM/YYYY',
171
+ // currency: 'SAR'
172
+ // }
173
+
174
+ // Check if locale is supported
175
+ if (i18n.isLocaleSupported('fr')) {
176
+ // Use French
177
+ }
178
+
179
+ // Get supported locales
180
+ const locales = i18n.getSupportedLocales();
181
+ // ['en', 'fr', 'es', 'de']
182
+ ```
183
+
184
+ ### Translation Metadata
185
+
186
+ ```typescript
187
+ // Get translation statistics
188
+ const metadata = await i18n.getTranslationMetadata('fr', 'common');
189
+ // {
190
+ // totalKeys: 50,
191
+ // translatedKeys: 45,
192
+ // completionPercentage: 90
193
+ // }
194
+
195
+ // Find missing translations
196
+ const missing = i18n.getMissingTranslations('en', 'fr', 'common');
197
+ // ['newFeature', 'button.help']
198
+ ```
199
+
200
+ ### Cache Management
201
+
202
+ ```typescript
203
+ // Clear translation cache
204
+ i18n.clearCache();
205
+
206
+ // Export translations for backup/editing
207
+ const translations = i18n.exportTranslations('en', 'common');
208
+ ```
209
+
210
+ ## Configuration Types
211
+
212
+ ```typescript
213
+ interface I18nConfig {
214
+ defaultLocale: string;
215
+ supportedLocales: string[];
216
+ fallbackLocale?: string;
217
+ translationsDir?: string;
218
+ cache?: boolean;
219
+ debug?: boolean;
220
+ }
221
+
222
+ interface TranslationOptions {
223
+ locale?: string;
224
+ namespace?: string;
225
+ variables?: Record<string, string | number>;
226
+ count?: number;
227
+ defaultValue?: string;
228
+ }
229
+ ```
230
+
231
+ ## Fastify Integration
232
+
233
+ ```typescript
234
+ // Detect locale from request
235
+ fastify.addHook('preHandler', async (request) => {
236
+ const acceptLanguage = request.headers['accept-language'];
237
+ const locale = parseAcceptLanguage(acceptLanguage) || 'en';
238
+
239
+ if (i18n.isLocaleSupported(locale)) {
240
+ request.locale = locale;
241
+ } else {
242
+ request.locale = 'en';
243
+ }
244
+ });
245
+
246
+ // Use in routes
247
+ fastify.get('/api/welcome', async (request, reply) => {
248
+ const message = i18n.t('welcome', {
249
+ locale: request.locale,
250
+ variables: { name: request.user?.name },
251
+ });
252
+
253
+ return { message };
254
+ });
255
+ ```
256
+
257
+ ## React Integration Example
258
+
259
+ ```typescript
260
+ // Create hook
261
+ function useTranslation(namespace = 'common') {
262
+ const locale = useLocale();
263
+
264
+ return {
265
+ t: (key: string, options?: TranslationOptions) =>
266
+ i18n.t(key, { locale, namespace, ...options }),
267
+ formatDate: (date: Date, options?: DateFormatOptions) =>
268
+ i18n.formatDate(date, locale, options),
269
+ formatCurrency: (value: number, currency?: string) =>
270
+ i18n.formatCurrency(value, locale, currency),
271
+ };
272
+ }
273
+
274
+ // Usage
275
+ function Welcome({ user }) {
276
+ const { t, formatCurrency } = useTranslation();
277
+
278
+ return (
279
+ <div>
280
+ <h1>{t('welcome', { variables: { name: user.name } })}</h1>
281
+ <p>{t('balance')}: {formatCurrency(user.balance)}</p>
282
+ </div>
283
+ );
284
+ }
285
+ ```
286
+
287
+ ## Best Practices
288
+
289
+ 1. **Key Naming** - Use dot notation for namespacing: `user.profile.title`
290
+ 2. **Variables** - Use meaningful variable names: `{{userName}}` not `{{n}}`
291
+ 3. **Fallback** - Always configure a fallback locale
292
+ 4. **Lazy Loading** - Load translations on demand for large apps
293
+ 5. **Missing Keys** - Log missing translations in development
294
+ 6. **RTL** - Test with RTL languages early in development