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,226 @@
1
+ # Analytics Module
2
+
3
+ Prometheus-style metrics collection for monitoring and observability.
4
+
5
+ ## Features
6
+
7
+ - **Counters** - Monotonically increasing values
8
+ - **Gauges** - Values that can go up and down
9
+ - **Histograms** - Distribution of values with buckets
10
+ - **Events** - Track custom application events
11
+ - **Prometheus Export** - Native Prometheus format output
12
+ - **Metric Queries** - Query and aggregate metrics
13
+
14
+ ## Metric Types
15
+
16
+ | Type | Description | Example |
17
+ |------|-------------|---------|
18
+ | Counter | Only increases | Request count, errors |
19
+ | Gauge | Can increase/decrease | Active connections, queue size |
20
+ | Histogram | Value distribution | Response times, payload sizes |
21
+
22
+ ## Usage
23
+
24
+ ### Basic Setup
25
+
26
+ ```typescript
27
+ import { AnalyticsService } from 'servcraft/modules/analytics';
28
+
29
+ const analytics = new AnalyticsService({
30
+ enabled: true,
31
+ prefix: 'myapp',
32
+ defaultLabels: { env: 'production' },
33
+ flushInterval: 60000,
34
+ });
35
+ ```
36
+
37
+ ### Counters
38
+
39
+ ```typescript
40
+ // Simple increment
41
+ analytics.incrementCounter('http_requests_total');
42
+
43
+ // Increment by value
44
+ analytics.incrementCounter('bytes_received', 1024);
45
+
46
+ // With labels
47
+ analytics.incrementCounter('http_requests_total', 1, {
48
+ method: 'GET',
49
+ path: '/api/users',
50
+ status: '200',
51
+ });
52
+ ```
53
+
54
+ ### Gauges
55
+
56
+ ```typescript
57
+ // Set gauge value
58
+ analytics.setGauge('active_connections', 42);
59
+
60
+ // With labels
61
+ analytics.setGauge('queue_size', 150, { queue: 'emails' });
62
+
63
+ // Update periodically
64
+ setInterval(() => {
65
+ analytics.setGauge('memory_usage_bytes', process.memoryUsage().heapUsed);
66
+ }, 5000);
67
+ ```
68
+
69
+ ### Histograms
70
+
71
+ ```typescript
72
+ // Observe value with default buckets
73
+ analytics.observeHistogram('http_request_duration_seconds', 0.125);
74
+
75
+ // Custom buckets
76
+ analytics.observeHistogram(
77
+ 'http_request_duration_seconds',
78
+ 0.125,
79
+ [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
80
+ { method: 'GET', path: '/api/users' }
81
+ );
82
+
83
+ // Timing helper
84
+ const start = Date.now();
85
+ // ... do work ...
86
+ const duration = (Date.now() - start) / 1000;
87
+ analytics.observeHistogram('operation_duration_seconds', duration);
88
+ ```
89
+
90
+ ### Events
91
+
92
+ ```typescript
93
+ // Track event
94
+ analytics.trackEvent({
95
+ name: 'user_signup',
96
+ properties: {
97
+ source: 'google',
98
+ plan: 'free',
99
+ },
100
+ });
101
+
102
+ // Get recent events
103
+ const events = analytics.getEvents(100);
104
+ ```
105
+
106
+ ### Querying Metrics
107
+
108
+ ```typescript
109
+ const result = await analytics.queryMetrics({
110
+ name: 'myapp_http_requests_total',
111
+ startTime: new Date('2024-01-01'),
112
+ endTime: new Date('2024-01-31'),
113
+ labels: { method: 'GET' },
114
+ groupBy: ['path'],
115
+ aggregation: 'sum',
116
+ });
117
+
118
+ // result: { name, data: [...], aggregated: 12345 }
119
+ ```
120
+
121
+ ### Prometheus Export
122
+
123
+ ```typescript
124
+ // Get Prometheus format
125
+ const metrics = analytics.getPrometheusMetrics();
126
+
127
+ // Example output:
128
+ // myapp_http_requests_total{method="GET",status="200"} 1234
129
+ // myapp_active_connections{} 42
130
+ // myapp_http_request_duration_seconds_bucket{le="0.1"} 500
131
+ // myapp_http_request_duration_seconds_bucket{le="0.5"} 900
132
+ // myapp_http_request_duration_seconds_sum{} 125.5
133
+ // myapp_http_request_duration_seconds_count{} 1000
134
+ ```
135
+
136
+ ### Fastify Integration
137
+
138
+ ```typescript
139
+ // Metrics endpoint
140
+ fastify.get('/metrics', async (request, reply) => {
141
+ reply.type('text/plain').send(analytics.getPrometheusMetrics());
142
+ });
143
+
144
+ // Request duration middleware
145
+ fastify.addHook('onRequest', async (request) => {
146
+ request.startTime = Date.now();
147
+ });
148
+
149
+ fastify.addHook('onResponse', async (request, reply) => {
150
+ const duration = (Date.now() - request.startTime) / 1000;
151
+
152
+ analytics.incrementCounter('http_requests_total', 1, {
153
+ method: request.method,
154
+ path: request.routerPath || request.url,
155
+ status: String(reply.statusCode),
156
+ });
157
+
158
+ analytics.observeHistogram('http_request_duration_seconds', duration, undefined, {
159
+ method: request.method,
160
+ path: request.routerPath || request.url,
161
+ });
162
+ });
163
+ ```
164
+
165
+ ## Configuration
166
+
167
+ ```typescript
168
+ interface AnalyticsConfig {
169
+ enabled?: boolean; // Enable/disable metrics (default: true)
170
+ prefix?: string; // Metric name prefix (default: 'app')
171
+ defaultLabels?: Record<string, string>; // Labels added to all metrics
172
+ prometheusEnabled?: boolean; // Enable Prometheus export (default: true)
173
+ flushInterval?: number; // Cleanup interval in ms (default: 60000)
174
+ }
175
+ ```
176
+
177
+ ## Aggregation Types
178
+
179
+ | Aggregation | Description |
180
+ |-------------|-------------|
181
+ | `sum` | Sum of all values |
182
+ | `avg` | Average of values |
183
+ | `min` | Minimum value |
184
+ | `max` | Maximum value |
185
+ | `count` | Number of data points |
186
+
187
+ ## Utility Methods
188
+
189
+ ```typescript
190
+ // Get all counters
191
+ const counters = analytics.getCounters();
192
+
193
+ // Get all gauges
194
+ const gauges = analytics.getGauges();
195
+
196
+ // Clear all metrics
197
+ analytics.clear();
198
+ ```
199
+
200
+ ## Prometheus Configuration
201
+
202
+ ```yaml
203
+ # prometheus.yml
204
+ scrape_configs:
205
+ - job_name: 'myapp'
206
+ static_configs:
207
+ - targets: ['localhost:3000']
208
+ metrics_path: '/metrics'
209
+ scrape_interval: 15s
210
+ ```
211
+
212
+ ## Grafana Dashboard
213
+
214
+ Common panels:
215
+ - Request rate: `rate(myapp_http_requests_total[5m])`
216
+ - Error rate: `rate(myapp_http_requests_total{status=~"5.."}[5m])`
217
+ - P99 latency: `histogram_quantile(0.99, rate(myapp_http_request_duration_seconds_bucket[5m]))`
218
+ - Active connections: `myapp_active_connections`
219
+
220
+ ## Best Practices
221
+
222
+ 1. **Use Labels Wisely** - Don't create high-cardinality labels
223
+ 2. **Consistent Naming** - Follow Prometheus naming conventions
224
+ 3. **Default Buckets** - Use appropriate histogram buckets for your use case
225
+ 4. **Memory Management** - Configure flush interval to prevent memory growth
226
+ 5. **Metric Types** - Use the right metric type for your use case
@@ -0,0 +1,252 @@
1
+ # API Versioning Module
2
+
3
+ API versioning support with multiple detection strategies.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Strategies** - URL path, header, query param, Accept header
8
+ - **Version Detection** - Automatic version detection from requests
9
+ - **Deprecation Warnings** - Warn clients about deprecated versions
10
+ - **Migration Support** - Data migration between versions
11
+ - **Sunset Dates** - Track version end-of-life dates
12
+
13
+ ## Strategies
14
+
15
+ | Strategy | Example | Best For |
16
+ |----------|---------|----------|
17
+ | URL Path | `/v1/users`, `/v2/users` | RESTful APIs, clear versioning |
18
+ | Header | `X-API-Version: v2` | Clean URLs, flexible |
19
+ | Query | `?version=v2` | Simple implementation |
20
+ | Accept Header | `Accept: application/vnd.api.v2+json` | Content negotiation |
21
+
22
+ ## Usage
23
+
24
+ ### Configuration
25
+
26
+ ```typescript
27
+ import { VersioningService } from 'servcraft/modules/api-versioning';
28
+
29
+ const versionService = new VersioningService({
30
+ strategy: 'url',
31
+ defaultVersion: 'v1',
32
+ versions: [
33
+ {
34
+ version: 'v1',
35
+ status: 'deprecated',
36
+ releasedAt: new Date('2023-01-01'),
37
+ sunsetAt: new Date('2024-06-01'),
38
+ },
39
+ {
40
+ version: 'v2',
41
+ status: 'active',
42
+ releasedAt: new Date('2024-01-01'),
43
+ },
44
+ {
45
+ version: 'v3',
46
+ status: 'active',
47
+ releasedAt: new Date('2024-06-01'),
48
+ },
49
+ ],
50
+ headerName: 'X-API-Version',
51
+ queryParam: 'version',
52
+ strict: true,
53
+ deprecationWarnings: true,
54
+ });
55
+ ```
56
+
57
+ ### Version Detection
58
+
59
+ ```typescript
60
+ // Detect version from request
61
+ const result = versionService.detectVersion({
62
+ url: '/v2/users',
63
+ headers: { 'x-api-version': 'v2' },
64
+ query: { version: 'v2' },
65
+ });
66
+ // {
67
+ // version: 'v2',
68
+ // source: 'url',
69
+ // isValid: true,
70
+ // warning: undefined
71
+ // }
72
+
73
+ // Deprecated version warning
74
+ const deprecatedResult = versionService.detectVersion({
75
+ url: '/v1/users',
76
+ });
77
+ // {
78
+ // version: 'v1',
79
+ // source: 'url',
80
+ // isValid: true,
81
+ // warning: 'API version v1 is deprecated and will be removed on 2024-06-01'
82
+ // }
83
+ ```
84
+
85
+ ### Version Information
86
+
87
+ ```typescript
88
+ // Get version info
89
+ const info = versionService.getVersion('v2');
90
+ // { version: 'v2', status: 'active', releasedAt: Date }
91
+
92
+ // Get all versions
93
+ const all = versionService.getAllVersions();
94
+
95
+ // Get active versions
96
+ const active = versionService.getActiveVersions();
97
+
98
+ // Check if version is valid
99
+ const isValid = versionService.isVersionValid('v3');
100
+
101
+ // Compare versions
102
+ const comparison = versionService.compareVersions('v1', 'v2');
103
+ // Returns: -1 (v1 < v2)
104
+ ```
105
+
106
+ ### Migrations
107
+
108
+ ```typescript
109
+ // Add migration
110
+ versionService.addMigration({
111
+ from: 'v1',
112
+ to: 'v2',
113
+ transform: (data) => ({
114
+ ...data,
115
+ // v2 renames 'name' to 'fullName'
116
+ fullName: data.name,
117
+ name: undefined,
118
+ // v2 adds required field
119
+ version: 2,
120
+ }),
121
+ });
122
+
123
+ // Get migration
124
+ const migration = versionService.getMigration('v1', 'v2');
125
+ if (migration) {
126
+ const v2Data = migration.transform(v1Data);
127
+ }
128
+ ```
129
+
130
+ ## Configuration Types
131
+
132
+ ```typescript
133
+ interface VersioningConfig {
134
+ strategy: 'url' | 'header' | 'query' | 'accept-header';
135
+ defaultVersion: string;
136
+ versions: ApiVersion[];
137
+ headerName?: string; // default: 'X-API-Version'
138
+ queryParam?: string; // default: 'version'
139
+ strict?: boolean; // Reject invalid versions
140
+ deprecationWarnings?: boolean;
141
+ }
142
+
143
+ interface ApiVersion {
144
+ version: string;
145
+ status: 'active' | 'deprecated' | 'sunset';
146
+ releasedAt: Date;
147
+ sunsetAt?: Date;
148
+ changelog?: string;
149
+ }
150
+
151
+ interface VersionMigration {
152
+ from: string;
153
+ to: string;
154
+ transform: (data: unknown) => unknown;
155
+ }
156
+ ```
157
+
158
+ ## Fastify Integration
159
+
160
+ ```typescript
161
+ import { versioningMiddleware } from 'servcraft/modules/api-versioning';
162
+
163
+ // Register middleware
164
+ fastify.addHook('preHandler', async (request, reply) => {
165
+ const result = versionService.detectVersion({
166
+ url: request.url,
167
+ headers: request.headers,
168
+ query: request.query,
169
+ });
170
+
171
+ if (!result.isValid && versionService.config.strict) {
172
+ return reply.status(400).send({
173
+ error: `Invalid API version: ${result.version}`,
174
+ supportedVersions: versionService.getActiveVersions().map(v => v.version),
175
+ });
176
+ }
177
+
178
+ request.apiVersion = result.version;
179
+
180
+ // Add deprecation warning header
181
+ if (result.warning) {
182
+ reply.header('X-API-Deprecation-Warning', result.warning);
183
+ reply.header('Sunset', versionService.getVersion(result.version)?.sunsetAt?.toISOString());
184
+ }
185
+ });
186
+ ```
187
+
188
+ ### Versioned Routes
189
+
190
+ ```typescript
191
+ // URL-based versioning
192
+ fastify.get('/v1/users', async (request, reply) => {
193
+ // v1 response format
194
+ return users.map(u => ({ name: u.name, email: u.email }));
195
+ });
196
+
197
+ fastify.get('/v2/users', async (request, reply) => {
198
+ // v2 response format with pagination
199
+ return {
200
+ data: users.map(u => ({ fullName: u.fullName, email: u.email })),
201
+ meta: { total: users.length },
202
+ };
203
+ });
204
+
205
+ // Header-based versioning (single route)
206
+ fastify.get('/users', async (request, reply) => {
207
+ const version = request.apiVersion;
208
+
209
+ if (version === 'v1') {
210
+ return users.map(u => ({ name: u.name }));
211
+ }
212
+
213
+ // v2 and later
214
+ return {
215
+ data: users.map(u => ({ fullName: u.fullName })),
216
+ meta: { total: users.length },
217
+ };
218
+ });
219
+ ```
220
+
221
+ ## Response Headers
222
+
223
+ ```http
224
+ # Deprecation warning
225
+ X-API-Deprecation-Warning: API version v1 is deprecated and will be removed on 2024-06-01
226
+ Sunset: 2024-06-01T00:00:00.000Z
227
+
228
+ # Current version
229
+ X-API-Version: v2
230
+ ```
231
+
232
+ ## Version Lifecycle
233
+
234
+ ```
235
+ ┌─────────────────────────────────────────────────────────────┐
236
+ │ Version Lifecycle │
237
+ ├─────────────────────────────────────────────────────────────┤
238
+ │ ACTIVE ──────► DEPRECATED ──────► SUNSET ──────► REMOVED │
239
+ │ │ │ │
240
+ │ Warning Error │
241
+ │ Headers Response │
242
+ └─────────────────────────────────────────────────────────────┘
243
+ ```
244
+
245
+ ## Best Practices
246
+
247
+ 1. **Semantic Versioning** - Use v1, v2, v3 for major breaking changes
248
+ 2. **Deprecation Period** - Give clients 6+ months notice
249
+ 3. **Sunset Headers** - Include Sunset header for deprecated versions
250
+ 4. **Documentation** - Document changes between versions
251
+ 5. **Default Version** - Don't change default version without notice
252
+ 6. **Migration Guides** - Provide clear migration instructions
@@ -0,0 +1,192 @@
1
+ # Audit Module
2
+
3
+ Audit logging for tracking user actions and system events.
4
+
5
+ ## Features
6
+
7
+ - **Automatic Logging** - Track CRUD operations automatically
8
+ - **User Attribution** - Link actions to users
9
+ - **Resource Tracking** - Track changes by resource type
10
+ - **IP & User Agent** - Capture request metadata
11
+ - **Data Retention** - Configurable log retention
12
+
13
+ ## Usage
14
+
15
+ ### Basic Setup
16
+
17
+ ```typescript
18
+ import { getAuditService } from 'servcraft/modules/audit';
19
+
20
+ const auditService = getAuditService();
21
+ ```
22
+
23
+ ### Logging Actions
24
+
25
+ ```typescript
26
+ // Generic log entry
27
+ await auditService.log({
28
+ action: 'create',
29
+ resource: 'order',
30
+ resourceId: 'order-123',
31
+ userId: 'user-456',
32
+ newValue: { total: 99.99, items: 3 },
33
+ ipAddress: request.ip,
34
+ userAgent: request.headers['user-agent'],
35
+ });
36
+
37
+ // Shortcut methods
38
+ await auditService.logCreate('order', 'order-123', 'user-456', { total: 99.99 });
39
+
40
+ await auditService.logUpdate('order', 'order-123', 'user-456',
41
+ { status: 'pending' }, // old value
42
+ { status: 'shipped' } // new value
43
+ );
44
+
45
+ await auditService.logDelete('order', 'order-123', 'user-456', { total: 99.99 });
46
+ ```
47
+
48
+ ### Auth Events
49
+
50
+ ```typescript
51
+ // Login event
52
+ await auditService.logLogin('user-123', {
53
+ ipAddress: '192.168.1.1',
54
+ userAgent: 'Mozilla/5.0...',
55
+ });
56
+
57
+ // Logout event
58
+ await auditService.logLogout('user-123');
59
+
60
+ // Password change
61
+ await auditService.logPasswordChange('user-123', {
62
+ ipAddress: '192.168.1.1',
63
+ });
64
+ ```
65
+
66
+ ### Querying Logs
67
+
68
+ ```typescript
69
+ // Query with filters
70
+ const result = await auditService.query({
71
+ userId: 'user-123',
72
+ action: 'update',
73
+ resource: 'order',
74
+ startDate: new Date('2024-01-01'),
75
+ endDate: new Date('2024-01-31'),
76
+ page: 1,
77
+ limit: 50,
78
+ });
79
+ // { data: [...], total: 150, page: 1, totalPages: 3 }
80
+
81
+ // Find by user
82
+ const userLogs = await auditService.findByUser('user-123', 100);
83
+
84
+ // Find by resource
85
+ const orderLogs = await auditService.findByResource('order', 'order-123', 50);
86
+ ```
87
+
88
+ ### Data Retention
89
+
90
+ ```typescript
91
+ // Delete logs older than 90 days
92
+ const deleted = await auditService.cleanupOldLogs(90);
93
+ console.log(`Deleted ${deleted} old audit logs`);
94
+ ```
95
+
96
+ ## Types
97
+
98
+ ```typescript
99
+ interface AuditLogEntry {
100
+ action: string;
101
+ resource: string;
102
+ resourceId?: string;
103
+ userId?: string;
104
+ oldValue?: Record<string, unknown>;
105
+ newValue?: Record<string, unknown>;
106
+ ipAddress?: string;
107
+ userAgent?: string;
108
+ }
109
+
110
+ interface AuditLogQuery {
111
+ userId?: string;
112
+ action?: string;
113
+ resource?: string;
114
+ resourceId?: string;
115
+ startDate?: Date;
116
+ endDate?: Date;
117
+ page?: number;
118
+ limit?: number;
119
+ }
120
+
121
+ interface AuditLogRecord extends AuditLogEntry {
122
+ id: string;
123
+ timestamp: Date;
124
+ }
125
+ ```
126
+
127
+ ## Common Actions
128
+
129
+ | Action | Description |
130
+ |--------|-------------|
131
+ | `create` | Resource created |
132
+ | `update` | Resource updated |
133
+ | `delete` | Resource deleted |
134
+ | `login` | User logged in |
135
+ | `logout` | User logged out |
136
+ | `password_change` | Password changed |
137
+ | `permission_change` | Permissions modified |
138
+ | `export` | Data exported |
139
+ | `import` | Data imported |
140
+
141
+ ## Middleware Integration
142
+
143
+ ```typescript
144
+ // Fastify hook for automatic audit logging
145
+ fastify.addHook('onResponse', async (request, reply) => {
146
+ // Only log mutations
147
+ if (!['POST', 'PUT', 'PATCH', 'DELETE'].includes(request.method)) {
148
+ return;
149
+ }
150
+
151
+ const userId = request.user?.id;
152
+ const resource = request.routerPath.split('/')[2]; // e.g., /api/orders -> orders
153
+
154
+ await auditService.log({
155
+ action: request.method.toLowerCase(),
156
+ resource,
157
+ resourceId: request.params?.id,
158
+ userId,
159
+ ipAddress: request.ip,
160
+ userAgent: request.headers['user-agent'],
161
+ });
162
+ });
163
+ ```
164
+
165
+ ## Database Schema
166
+
167
+ ```sql
168
+ CREATE TABLE audit_logs (
169
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
170
+ action TEXT NOT NULL,
171
+ resource TEXT NOT NULL,
172
+ resource_id TEXT,
173
+ user_id TEXT,
174
+ old_value JSONB,
175
+ new_value JSONB,
176
+ ip_address TEXT,
177
+ user_agent TEXT,
178
+ timestamp TIMESTAMP DEFAULT NOW()
179
+ );
180
+
181
+ CREATE INDEX idx_audit_user ON audit_logs(user_id);
182
+ CREATE INDEX idx_audit_resource ON audit_logs(resource, resource_id);
183
+ CREATE INDEX idx_audit_timestamp ON audit_logs(timestamp);
184
+ ```
185
+
186
+ ## Best Practices
187
+
188
+ 1. **Log Sensitive Actions** - Always log auth, permission, and data changes
189
+ 2. **Don't Log Sensitive Data** - Exclude passwords, tokens from logs
190
+ 3. **Retention Policy** - Implement data retention per compliance requirements
191
+ 4. **Async Logging** - Use async logging to not block requests
192
+ 5. **Structured Data** - Use consistent action and resource names