@friggframework/core 2.0.0-next.10 → 2.0.0-next.101

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 (344) hide show
  1. package/CLAUDE.md +702 -0
  2. package/README.md +959 -50
  3. package/admin-scripts/index.js +52 -0
  4. package/admin-scripts/repositories/admin-script-execution-repository-documentdb.js +21 -0
  5. package/admin-scripts/repositories/admin-script-execution-repository-factory.js +51 -0
  6. package/admin-scripts/repositories/admin-script-execution-repository-interface.js +166 -0
  7. package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +228 -0
  8. package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +268 -0
  9. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  10. package/admin-scripts/repositories/script-schedule-repository-factory.js +51 -0
  11. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  12. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  13. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  14. package/application/commands/README.md +451 -0
  15. package/application/commands/admin-script-commands.js +358 -0
  16. package/application/commands/credential-commands.js +245 -0
  17. package/application/commands/entity-commands.js +336 -0
  18. package/application/commands/integration-commands.js +343 -0
  19. package/application/commands/process-commands.js +135 -0
  20. package/application/commands/scheduler-commands.js +263 -0
  21. package/application/commands/user-commands.js +312 -0
  22. package/application/index.js +82 -0
  23. package/assertions/index.js +0 -3
  24. package/core/CLAUDE.md +690 -0
  25. package/core/Worker.js +60 -24
  26. package/core/create-handler.js +84 -6
  27. package/credential/repositories/credential-repository-documentdb.js +304 -0
  28. package/credential/repositories/credential-repository-factory.js +54 -0
  29. package/credential/repositories/credential-repository-interface.js +98 -0
  30. package/credential/repositories/credential-repository-mongo.js +269 -0
  31. package/credential/repositories/credential-repository-postgres.js +287 -0
  32. package/credential/repositories/credential-repository.js +300 -0
  33. package/credential/use-cases/get-credential-for-user.js +25 -0
  34. package/credential/use-cases/update-authentication-status.js +15 -0
  35. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  36. package/database/adapters/lambda-invoker.js +97 -0
  37. package/database/config.js +154 -0
  38. package/database/documentdb-encryption-service.js +330 -0
  39. package/database/documentdb-utils.js +136 -0
  40. package/database/encryption/README.md +839 -0
  41. package/database/encryption/documentdb-encryption-service.md +3575 -0
  42. package/database/encryption/encryption-schema-registry.js +401 -0
  43. package/database/encryption/field-encryption-service.js +254 -0
  44. package/database/encryption/logger.js +79 -0
  45. package/database/encryption/prisma-encryption-extension.js +230 -0
  46. package/database/index.js +21 -21
  47. package/database/prisma.js +182 -0
  48. package/database/repositories/health-check-repository-documentdb.js +138 -0
  49. package/database/repositories/health-check-repository-factory.js +48 -0
  50. package/database/repositories/health-check-repository-interface.js +82 -0
  51. package/database/repositories/health-check-repository-mongodb.js +89 -0
  52. package/database/repositories/health-check-repository-postgres.js +82 -0
  53. package/database/repositories/migration-status-repository-s3.js +137 -0
  54. package/database/use-cases/check-database-health-use-case.js +29 -0
  55. package/database/use-cases/check-database-state-use-case.js +81 -0
  56. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  57. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  58. package/database/use-cases/get-migration-status-use-case.js +93 -0
  59. package/database/use-cases/run-database-migration-use-case.js +139 -0
  60. package/database/use-cases/test-encryption-use-case.js +253 -0
  61. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  62. package/database/utils/mongodb-collection-utils.js +94 -0
  63. package/database/utils/mongodb-schema-init.js +108 -0
  64. package/database/utils/prisma-runner.js +477 -0
  65. package/database/utils/prisma-schema-parser.js +182 -0
  66. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  67. package/encrypt/Cryptor.js +34 -168
  68. package/encrypt/index.js +1 -2
  69. package/errors/client-safe-error.js +26 -0
  70. package/errors/fetch-error.js +15 -7
  71. package/errors/index.js +2 -0
  72. package/generated/prisma-mongodb/client.d.ts +1 -0
  73. package/generated/prisma-mongodb/client.js +5 -0
  74. package/generated/prisma-mongodb/default.d.ts +1 -0
  75. package/generated/prisma-mongodb/default.js +5 -0
  76. package/generated/prisma-mongodb/edge.d.ts +1 -0
  77. package/generated/prisma-mongodb/edge.js +374 -0
  78. package/generated/prisma-mongodb/index-browser.js +356 -0
  79. package/generated/prisma-mongodb/index.d.ts +25667 -0
  80. package/generated/prisma-mongodb/index.js +399 -0
  81. package/generated/prisma-mongodb/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  82. package/generated/prisma-mongodb/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  83. package/generated/prisma-mongodb/package.json +183 -0
  84. package/generated/prisma-mongodb/runtime/edge-esm.js +35 -0
  85. package/generated/prisma-mongodb/runtime/edge.js +35 -0
  86. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  87. package/generated/prisma-mongodb/runtime/index-browser.js +17 -0
  88. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  89. package/generated/prisma-mongodb/runtime/library.js +147 -0
  90. package/generated/prisma-mongodb/runtime/react-native.js +84 -0
  91. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +85 -0
  92. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +38 -0
  93. package/generated/prisma-mongodb/schema.prisma +432 -0
  94. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +5 -0
  95. package/generated/prisma-mongodb/wasm-worker-loader.mjs +5 -0
  96. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  97. package/generated/prisma-mongodb/wasm.js +381 -0
  98. package/generated/prisma-postgresql/client.d.ts +1 -0
  99. package/generated/prisma-postgresql/client.js +5 -0
  100. package/generated/prisma-postgresql/default.d.ts +1 -0
  101. package/generated/prisma-postgresql/default.js +5 -0
  102. package/generated/prisma-postgresql/edge.d.ts +1 -0
  103. package/generated/prisma-postgresql/edge.js +395 -0
  104. package/generated/prisma-postgresql/index-browser.js +377 -0
  105. package/generated/prisma-postgresql/index.d.ts +28455 -0
  106. package/generated/prisma-postgresql/index.js +420 -0
  107. package/generated/prisma-postgresql/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  108. package/generated/prisma-postgresql/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  109. package/generated/prisma-postgresql/package.json +183 -0
  110. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  111. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  112. package/generated/prisma-postgresql/runtime/edge-esm.js +35 -0
  113. package/generated/prisma-postgresql/runtime/edge.js +35 -0
  114. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  115. package/generated/prisma-postgresql/runtime/index-browser.js +17 -0
  116. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  117. package/generated/prisma-postgresql/runtime/library.js +147 -0
  118. package/generated/prisma-postgresql/runtime/react-native.js +84 -0
  119. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +85 -0
  120. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +38 -0
  121. package/generated/prisma-postgresql/schema.prisma +414 -0
  122. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +5 -0
  123. package/generated/prisma-postgresql/wasm-worker-loader.mjs +5 -0
  124. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  125. package/generated/prisma-postgresql/wasm.js +402 -0
  126. package/handlers/WEBHOOKS.md +653 -0
  127. package/handlers/app-definition-loader.js +43 -0
  128. package/handlers/app-handler-helpers.js +3 -3
  129. package/handlers/backend-utils.js +271 -42
  130. package/handlers/database-migration-handler.js +227 -0
  131. package/handlers/integration-event-dispatcher.js +54 -0
  132. package/handlers/middleware/admin-auth.js +73 -0
  133. package/handlers/routers/HEALTHCHECK.md +342 -0
  134. package/handlers/routers/auth.js +4 -15
  135. package/handlers/routers/db-migration.handler.js +29 -0
  136. package/handlers/routers/db-migration.js +311 -0
  137. package/handlers/routers/health.js +518 -0
  138. package/handlers/routers/integration-defined-routers.js +85 -10
  139. package/handlers/routers/integration-webhook-routers.js +67 -0
  140. package/handlers/routers/reporting.js +9 -0
  141. package/handlers/routers/user.js +27 -5
  142. package/handlers/routers/websocket.js +5 -3
  143. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  144. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  145. package/handlers/workers/db-migration.js +352 -0
  146. package/handlers/workers/dlq-processor.js +63 -0
  147. package/handlers/workers/integration-defined-workers.js +13 -7
  148. package/index.js +91 -46
  149. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +184 -0
  150. package/infrastructure/scheduler/index.js +33 -0
  151. package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
  152. package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
  153. package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
  154. package/integrations/EXTENSIONS.md +240 -0
  155. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  156. package/integrations/extension.js +254 -0
  157. package/integrations/index.js +20 -10
  158. package/integrations/integration-base.js +633 -72
  159. package/integrations/integration-router.js +398 -180
  160. package/integrations/options.js +1 -1
  161. package/integrations/repositories/config-patch-shared.js +43 -0
  162. package/integrations/repositories/integration-mapping-repository-documentdb.js +280 -0
  163. package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
  164. package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
  165. package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
  166. package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
  167. package/integrations/repositories/integration-mapping-repository.js +156 -0
  168. package/integrations/repositories/integration-repository-documentdb.js +284 -0
  169. package/integrations/repositories/integration-repository-factory.js +51 -0
  170. package/integrations/repositories/integration-repository-interface.js +173 -0
  171. package/integrations/repositories/integration-repository-mongo.js +414 -0
  172. package/integrations/repositories/integration-repository-postgres.js +452 -0
  173. package/integrations/repositories/process-repository-documentdb.js +311 -0
  174. package/integrations/repositories/process-repository-factory.js +53 -0
  175. package/integrations/repositories/process-repository-interface.js +136 -0
  176. package/integrations/repositories/process-repository-mongo.js +262 -0
  177. package/integrations/repositories/process-repository-postgres.js +380 -0
  178. package/integrations/repositories/process-update-ops-shared.js +112 -0
  179. package/integrations/tests/doubles/config-capturing-integration.js +81 -0
  180. package/integrations/tests/doubles/dummy-integration-class.js +113 -0
  181. package/integrations/tests/doubles/test-integration-repository.js +146 -0
  182. package/integrations/use-cases/create-integration.js +215 -0
  183. package/integrations/use-cases/create-process.js +130 -0
  184. package/integrations/use-cases/delete-integration-for-user.js +119 -0
  185. package/integrations/use-cases/find-integration-by-entity-external-id.js +74 -0
  186. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +76 -0
  187. package/integrations/use-cases/get-integration-for-user.js +78 -0
  188. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  189. package/integrations/use-cases/get-integration-instance.js +83 -0
  190. package/integrations/use-cases/get-integrations-for-user.js +88 -0
  191. package/integrations/use-cases/get-possible-integrations.js +27 -0
  192. package/integrations/use-cases/get-process.js +89 -0
  193. package/integrations/use-cases/index.js +19 -0
  194. package/integrations/use-cases/list-integrations-by-entity-external-id.js +46 -0
  195. package/integrations/use-cases/load-integration-context.js +71 -0
  196. package/integrations/use-cases/patch-integration-config.js +39 -0
  197. package/integrations/use-cases/process-errors.js +28 -0
  198. package/integrations/use-cases/update-integration-config.js +32 -0
  199. package/integrations/use-cases/update-integration-messages.js +44 -0
  200. package/integrations/use-cases/update-integration-status.js +32 -0
  201. package/integrations/use-cases/update-integration.js +92 -0
  202. package/integrations/use-cases/update-process-metrics.js +216 -0
  203. package/integrations/use-cases/update-process-state.js +163 -0
  204. package/integrations/utils/map-integration-dto.js +37 -0
  205. package/jest-global-setup-noop.js +3 -0
  206. package/jest-global-teardown-noop.js +3 -0
  207. package/logs/logger.js +0 -4
  208. package/{module-plugin → modules}/index.js +0 -10
  209. package/modules/module-factory.js +56 -0
  210. package/modules/module.js +287 -0
  211. package/modules/repositories/module-repository-documentdb.js +350 -0
  212. package/modules/repositories/module-repository-factory.js +40 -0
  213. package/modules/repositories/module-repository-interface.js +145 -0
  214. package/modules/repositories/module-repository-mongo.js +436 -0
  215. package/modules/repositories/module-repository-postgres.js +481 -0
  216. package/modules/repositories/module-repository.js +369 -0
  217. package/modules/requester/api-key.js +52 -0
  218. package/modules/requester/oauth-2.js +396 -0
  219. package/modules/requester/requester.js +334 -0
  220. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  221. package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
  222. package/modules/tests/doubles/test-module-factory.js +16 -0
  223. package/modules/tests/doubles/test-module-repository.js +39 -0
  224. package/modules/use-cases/get-entities-for-user.js +32 -0
  225. package/modules/use-cases/get-entity-options-by-id.js +71 -0
  226. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  227. package/modules/use-cases/get-module-instance-from-type.js +34 -0
  228. package/modules/use-cases/get-module.js +74 -0
  229. package/modules/use-cases/process-authorization-callback.js +243 -0
  230. package/modules/use-cases/refresh-entity-options.js +72 -0
  231. package/modules/use-cases/test-module-auth.js +72 -0
  232. package/modules/utils/map-module-dto.js +18 -0
  233. package/package.json +82 -50
  234. package/prisma-mongodb/schema.prisma +432 -0
  235. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  236. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  237. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  238. package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
  239. package/prisma-postgresql/migrations/20260422120000_add_entity_data_column/migration.sql +10 -0
  240. package/prisma-postgresql/migrations/20260422120001_create_process_table/migration.sql +48 -0
  241. package/prisma-postgresql/migrations/20260625000000_add_user_organization_id_index/migration.sql +2 -0
  242. package/prisma-postgresql/migrations/20260703000000_add_integration_status_in_creation_in_deletion/migration.sql +11 -0
  243. package/prisma-postgresql/migrations/20260703000001_integration_status_default_in_creation/migration.sql +8 -0
  244. package/prisma-postgresql/migrations/20260706000000_add_admin_script_execution_and_schedule/migration.sql +61 -0
  245. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  246. package/prisma-postgresql/schema.prisma +414 -0
  247. package/queues/queuer-util.js +103 -21
  248. package/reporting/README.md +86 -0
  249. package/reporting/index.js +17 -0
  250. package/reporting/reporting-router.js +77 -0
  251. package/reporting/repositories/reporting-repository-documentdb.js +127 -0
  252. package/reporting/repositories/reporting-repository-factory.js +35 -0
  253. package/reporting/repositories/reporting-repository-interface.js +16 -0
  254. package/reporting/repositories/reporting-repository-mongo.js +54 -0
  255. package/reporting/repositories/reporting-repository-postgres.js +70 -0
  256. package/reporting/use-cases/index.js +6 -0
  257. package/reporting/use-cases/list-integrations-report.js +142 -0
  258. package/syncs/manager.js +468 -443
  259. package/syncs/repositories/sync-repository-documentdb.js +240 -0
  260. package/syncs/repositories/sync-repository-factory.js +43 -0
  261. package/syncs/repositories/sync-repository-interface.js +109 -0
  262. package/syncs/repositories/sync-repository-mongo.js +239 -0
  263. package/syncs/repositories/sync-repository-postgres.js +319 -0
  264. package/syncs/sync.js +0 -1
  265. package/token/repositories/token-repository-documentdb.js +137 -0
  266. package/token/repositories/token-repository-factory.js +40 -0
  267. package/token/repositories/token-repository-interface.js +131 -0
  268. package/token/repositories/token-repository-mongo.js +219 -0
  269. package/token/repositories/token-repository-postgres.js +264 -0
  270. package/token/repositories/token-repository.js +219 -0
  271. package/types/associations/index.d.ts +0 -17
  272. package/types/core/index.d.ts +12 -4
  273. package/types/database/index.d.ts +10 -2
  274. package/types/encrypt/index.d.ts +5 -3
  275. package/types/integrations/index.d.ts +3 -8
  276. package/types/module-plugin/index.d.ts +17 -69
  277. package/types/syncs/index.d.ts +0 -17
  278. package/user/repositories/user-repository-documentdb.js +458 -0
  279. package/user/repositories/user-repository-factory.js +52 -0
  280. package/user/repositories/user-repository-interface.js +214 -0
  281. package/user/repositories/user-repository-mongo.js +323 -0
  282. package/user/repositories/user-repository-postgres.js +377 -0
  283. package/user/tests/doubles/test-user-repository.js +72 -0
  284. package/user/use-cases/authenticate-user.js +127 -0
  285. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  286. package/user/use-cases/create-individual-user.js +61 -0
  287. package/user/use-cases/create-organization-user.js +47 -0
  288. package/user/use-cases/create-token-for-user-id.js +30 -0
  289. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  290. package/user/use-cases/get-user-from-bearer-token.js +77 -0
  291. package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
  292. package/user/use-cases/login-user.js +122 -0
  293. package/user/user.js +125 -0
  294. package/utils/backend-path.js +38 -0
  295. package/utils/index.js +6 -0
  296. package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
  297. package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
  298. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  299. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  300. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  301. package/websocket/repositories/websocket-connection-repository.js +161 -0
  302. package/assertions/is-equal.js +0 -17
  303. package/associations/model.js +0 -54
  304. package/database/models/IndividualUser.js +0 -76
  305. package/database/models/OrganizationUser.js +0 -29
  306. package/database/models/State.js +0 -9
  307. package/database/models/Token.js +0 -70
  308. package/database/models/UserModel.js +0 -7
  309. package/database/models/WebsocketConnection.js +0 -49
  310. package/database/mongo.js +0 -45
  311. package/database/mongoose.js +0 -5
  312. package/encrypt/Cryptor.test.js +0 -32
  313. package/encrypt/encrypt.js +0 -132
  314. package/encrypt/encrypt.test.js +0 -1069
  315. package/encrypt/test-encrypt.js +0 -107
  316. package/errors/base-error.test.js +0 -32
  317. package/errors/fetch-error.test.js +0 -79
  318. package/errors/halt-error.test.js +0 -11
  319. package/errors/validation-errors.test.js +0 -120
  320. package/handlers/routers/middleware/loadUser.js +0 -15
  321. package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
  322. package/integrations/create-frigg-backend.js +0 -31
  323. package/integrations/integration-factory.js +0 -251
  324. package/integrations/integration-mapping.js +0 -43
  325. package/integrations/integration-model.js +0 -46
  326. package/integrations/integration-user.js +0 -144
  327. package/integrations/test/integration-base.test.js +0 -144
  328. package/lambda/TimeoutCatcher.test.js +0 -68
  329. package/logs/logger.test.js +0 -76
  330. package/module-plugin/auther.js +0 -393
  331. package/module-plugin/credential.js +0 -22
  332. package/module-plugin/entity-manager.js +0 -70
  333. package/module-plugin/entity.js +0 -46
  334. package/module-plugin/manager.js +0 -169
  335. package/module-plugin/module-factory.js +0 -61
  336. package/module-plugin/requester/api-key.js +0 -36
  337. package/module-plugin/requester/oauth-2.js +0 -219
  338. package/module-plugin/requester/requester.js +0 -165
  339. package/module-plugin/requester/requester.test.js +0 -28
  340. package/module-plugin/test/auther.test.js +0 -97
  341. package/syncs/model.js +0 -62
  342. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  343. /package/{module-plugin → modules}/requester/basic.js +0 -0
  344. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Database Migration Router
3
+ *
4
+ * HTTP API for triggering and monitoring database migrations.
5
+ *
6
+ * Endpoints:
7
+ * - GET /admin/db-migrate/status - Check if migrations are pending
8
+ * - POST /admin/db-migrate - Trigger async migration (queues job)
9
+ * - GET /admin/db-migrate/:processId - Check migration status
10
+ * - POST /admin/db-migrate/resolve - Resolve failed migration
11
+ *
12
+ * Security:
13
+ * - Requires x-frigg-admin-api-key header for all requests
14
+ * - Uses shared validateAdminApiKey middleware
15
+ *
16
+ * Architecture:
17
+ * - Router (Adapter Layer) → Use Cases (Domain) → Repositories (Infrastructure)
18
+ * - Follows DDD/Hexagonal architecture
19
+ */
20
+
21
+ const { Router } = require('express');
22
+ const catchAsyncError = require('express-async-handler');
23
+ const { validateAdminApiKey } = require('../middleware/admin-auth');
24
+ const { MigrationStatusRepositoryS3 } = require('../../database/repositories/migration-status-repository-s3');
25
+ const {
26
+ TriggerDatabaseMigrationUseCase,
27
+ ValidationError: TriggerValidationError,
28
+ } = require('../../database/use-cases/trigger-database-migration-use-case');
29
+ const {
30
+ GetMigrationStatusUseCase,
31
+ ValidationError: GetValidationError,
32
+ NotFoundError,
33
+ } = require('../../database/use-cases/get-migration-status-use-case');
34
+ const { LambdaInvoker } = require('../../database/adapters/lambda-invoker');
35
+ const {
36
+ GetDatabaseStateViaWorkerUseCase,
37
+ } = require('../../database/use-cases/get-database-state-via-worker-use-case');
38
+
39
+ const router = Router();
40
+
41
+ // Dependency injection
42
+ // Use S3 repository to avoid User table dependency (chicken-and-egg problem)
43
+ const bucketName = process.env.S3_BUCKET_NAME || process.env.MIGRATION_STATUS_BUCKET;
44
+ const migrationStatusRepository = new MigrationStatusRepositoryS3(bucketName);
45
+
46
+ const triggerMigrationUseCase = new TriggerDatabaseMigrationUseCase({
47
+ migrationStatusRepository,
48
+ // Note: QueuerUtil is used directly in the use case (static utility)
49
+ });
50
+ const getStatusUseCase = new GetMigrationStatusUseCase({ migrationStatusRepository });
51
+
52
+ // Lambda invocation for database state check (keeps router lightweight)
53
+ const lambdaInvoker = new LambdaInvoker();
54
+ const workerFunctionName = process.env.WORKER_FUNCTION_NAME ||
55
+ `${process.env.SERVICE || 'unknown'}-${process.env.STAGE || 'production'}-dbMigrationWorker`;
56
+
57
+ const getDatabaseStateUseCase = new GetDatabaseStateViaWorkerUseCase({
58
+ lambdaInvoker,
59
+ workerFunctionName,
60
+ });
61
+
62
+ // Apply admin API key validation to all routes (shared middleware)
63
+ router.use(validateAdminApiKey);
64
+
65
+ /**
66
+ * POST /admin/db-migrate
67
+ *
68
+ * Trigger database migration (async via SQS queue)
69
+ *
70
+ * Request body:
71
+ * {
72
+ * userId: string (optional, defaults to 'admin'),
73
+ * dbType: 'postgresql' | 'mongodb' | 'documentdb',
74
+ * stage: string (e.g., 'production', 'dev')
75
+ * }
76
+ *
77
+ * Response (202 Accepted):
78
+ * {
79
+ * success: true,
80
+ * processId: string,
81
+ * state: 'INITIALIZING',
82
+ * statusUrl: string,
83
+ * message: string
84
+ * }
85
+ */
86
+ router.post(
87
+ '/admin/db-migrate',
88
+ catchAsyncError(async (req, res) => {
89
+ const dbType = req.body.dbType || process.env.DB_TYPE || 'postgresql';
90
+ const { stage } = req.body;
91
+ // TODO: Extract userId from JWT token when auth is implemented
92
+ const userId = req.body.userId || 'admin';
93
+
94
+ console.log(`Migration trigger request: dbType=${dbType}, stage=${stage || 'auto-detect'}, userId=${userId}`);
95
+
96
+ try {
97
+ const result = await triggerMigrationUseCase.execute({
98
+ userId,
99
+ dbType,
100
+ stage,
101
+ });
102
+
103
+ // 202 Accepted - request accepted but not completed
104
+ res.status(202).json(result);
105
+ } catch (error) {
106
+ // Handle validation errors (400 Bad Request)
107
+ if (error instanceof TriggerValidationError) {
108
+ return res.status(400).json({
109
+ success: false,
110
+ error: error.message,
111
+ });
112
+ }
113
+
114
+ // Re-throw other errors for global error handler
115
+ throw error;
116
+ }
117
+ })
118
+ );
119
+
120
+ /**
121
+ * GET /admin/db-migrate/status
122
+ *
123
+ * Check if database has pending migrations
124
+ *
125
+ * Query params:
126
+ * - stage: string (optional, defaults to STAGE env var or 'production')
127
+ *
128
+ * Response (200 OK):
129
+ * {
130
+ * upToDate: boolean,
131
+ * pendingMigrations: number,
132
+ * dbType: 'postgresql',
133
+ * stage: string,
134
+ * recommendation?: string (if migrations pending),
135
+ * error?: string (if database check failed)
136
+ * }
137
+ */
138
+ router.get(
139
+ '/admin/db-migrate/status',
140
+ catchAsyncError(async (req, res) => {
141
+ const stage = req.query.stage || process.env.STAGE || 'production';
142
+
143
+ console.log(`Checking database state: stage=${stage}, worker=${workerFunctionName}`);
144
+
145
+ try {
146
+ // Invoke worker Lambda to check database state
147
+ const status = await getDatabaseStateUseCase.execute(stage);
148
+
149
+ res.status(200).json(status);
150
+ } catch (error) {
151
+ // Log full error for debugging
152
+ console.error('Database state check failed:', error);
153
+
154
+ // Return sanitized error to client
155
+ return res.status(500).json({
156
+ success: false,
157
+ error: 'Failed to check database state',
158
+ details: error.message,
159
+ });
160
+ }
161
+ })
162
+ );
163
+
164
+ /**
165
+ * GET /admin/db-migrate/:migrationId
166
+ *
167
+ * Get migration status by migration ID
168
+ *
169
+ * Response (200 OK):
170
+ * {
171
+ * processId: string,
172
+ * type: 'DATABASE_MIGRATION',
173
+ * state: 'INITIALIZING' | 'RUNNING' | 'COMPLETED' | 'FAILED',
174
+ * context: {
175
+ * dbType: string,
176
+ * stage: string,
177
+ * migrationCommand: string (if started)
178
+ * },
179
+ * results: {
180
+ * success: boolean (if completed),
181
+ * duration: string (if completed),
182
+ * error: string (if failed)
183
+ * },
184
+ * createdAt: string,
185
+ * updatedAt: string
186
+ * }
187
+ */
188
+ router.get(
189
+ '/admin/db-migrate/:migrationId',
190
+ catchAsyncError(async (req, res) => {
191
+ const { migrationId } = req.params;
192
+ const stage = req.query.stage || process.env.STAGE || 'production';
193
+
194
+ console.log(`Migration status request: migrationId=${migrationId}, stage=${stage}`);
195
+
196
+ try {
197
+ const status = await getStatusUseCase.execute(migrationId, stage);
198
+
199
+ res.status(200).json(status);
200
+ } catch (error) {
201
+ // Handle not found errors (404 Not Found)
202
+ if (error instanceof NotFoundError) {
203
+ return res.status(404).json({
204
+ success: false,
205
+ error: error.message,
206
+ });
207
+ }
208
+
209
+ // Handle validation errors (400 Bad Request)
210
+ if (error instanceof GetValidationError) {
211
+ return res.status(400).json({
212
+ success: false,
213
+ error: error.message,
214
+ });
215
+ }
216
+
217
+ // Re-throw other errors for global error handler
218
+ throw error;
219
+ }
220
+ })
221
+ );
222
+
223
+ /**
224
+ * POST /admin/db-migrate/resolve
225
+ *
226
+ * Resolve a failed migration by marking it as applied or rolled back
227
+ *
228
+ * Request body:
229
+ * {
230
+ * migrationName: string (e.g., '20251112195422_update_user_unique_constraints'),
231
+ * action: 'applied' | 'rolled-back',
232
+ * stage: string (optional, defaults to STAGE env var or 'production')
233
+ * }
234
+ *
235
+ * Response (200 OK):
236
+ * {
237
+ * success: true,
238
+ * message: string,
239
+ * migrationName: string,
240
+ * action: string
241
+ * }
242
+ */
243
+ router.post(
244
+ '/admin/db-migrate/resolve',
245
+ catchAsyncError(async (req, res) => {
246
+ const { migrationName, action = 'applied' } = req.body;
247
+
248
+ console.log(`Migration resolve request: migration=${migrationName}, action=${action}`);
249
+
250
+ // Validation
251
+ if (!migrationName) {
252
+ return res.status(400).json({
253
+ success: false,
254
+ error: 'migrationName is required'
255
+ });
256
+ }
257
+
258
+ if (!['applied', 'rolled-back'].includes(action)) {
259
+ return res.status(400).json({
260
+ success: false,
261
+ error: 'action must be either "applied" or "rolled-back"'
262
+ });
263
+ }
264
+
265
+ try {
266
+ // Import prismaRunner here to avoid circular dependencies
267
+ const prismaRunner = require('../../database/utils/prisma-runner');
268
+
269
+ const result = await prismaRunner.runPrismaMigrateResolve(migrationName, action, true);
270
+
271
+ if (!result.success) {
272
+ return res.status(500).json({
273
+ success: false,
274
+ error: `Failed to resolve migration: ${result.error}`
275
+ });
276
+ }
277
+
278
+ res.status(200).json({
279
+ success: true,
280
+ message: `Migration ${migrationName} marked as ${action}`,
281
+ migrationName,
282
+ action
283
+ });
284
+ } catch (error) {
285
+ console.error('Migration resolve failed:', error);
286
+ return res.status(500).json({
287
+ success: false,
288
+ error: error.message
289
+ });
290
+ }
291
+ })
292
+ );
293
+
294
+ // Minimal Lambda handler (avoids app-handler-helpers which loads core/index.js → user/**)
295
+ const serverlessHttp = require('serverless-http');
296
+ const express = require('express');
297
+ const cors = require('cors');
298
+
299
+ const app = express();
300
+ app.use(cors());
301
+ app.use(express.json());
302
+ app.use(router);
303
+ app.use((err, _req, res, _next) => {
304
+ console.error('Migration Router Error:', err);
305
+ res.status(500).json({ message: 'Internal Server Error' });
306
+ });
307
+
308
+ const handler = serverlessHttp(app);
309
+
310
+ module.exports = { handler, router };
311
+