@intranefr/superbackend 1.4.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 (188) hide show
  1. package/.commiat +4 -0
  2. package/.env.example +47 -0
  3. package/README.md +110 -0
  4. package/index.js +94 -0
  5. package/package.json +67 -0
  6. package/public/css/styles.css +139 -0
  7. package/public/js/animations.js +41 -0
  8. package/sdk/error-tracking/browser/package.json +16 -0
  9. package/sdk/error-tracking/browser/src/core.js +270 -0
  10. package/sdk/error-tracking/browser/src/embed.js +18 -0
  11. package/sdk/error-tracking/browser/src/index.js +1 -0
  12. package/server.js +5 -0
  13. package/src/admin/endpointRegistry.js +300 -0
  14. package/src/controllers/admin.controller.js +321 -0
  15. package/src/controllers/adminAssets.controller.js +530 -0
  16. package/src/controllers/adminAssetsStorage.controller.js +260 -0
  17. package/src/controllers/adminEjsVirtual.controller.js +354 -0
  18. package/src/controllers/adminFeatureFlags.controller.js +155 -0
  19. package/src/controllers/adminHeadless.controller.js +1071 -0
  20. package/src/controllers/adminI18n.controller.js +604 -0
  21. package/src/controllers/adminJsonConfigs.controller.js +97 -0
  22. package/src/controllers/adminLlm.controller.js +273 -0
  23. package/src/controllers/adminMigration.controller.js +257 -0
  24. package/src/controllers/adminSeoConfig.controller.js +515 -0
  25. package/src/controllers/adminStats.controller.js +121 -0
  26. package/src/controllers/adminUploadNamespaces.controller.js +208 -0
  27. package/src/controllers/assets.controller.js +248 -0
  28. package/src/controllers/auth.controller.js +93 -0
  29. package/src/controllers/billing.controller.js +223 -0
  30. package/src/controllers/featureFlags.controller.js +35 -0
  31. package/src/controllers/forms.controller.js +217 -0
  32. package/src/controllers/globalSettings.controller.js +252 -0
  33. package/src/controllers/headlessCrud.controller.js +126 -0
  34. package/src/controllers/i18n.controller.js +12 -0
  35. package/src/controllers/invite.controller.js +249 -0
  36. package/src/controllers/jsonConfigs.controller.js +19 -0
  37. package/src/controllers/metrics.controller.js +149 -0
  38. package/src/controllers/notificationAdmin.controller.js +264 -0
  39. package/src/controllers/notifications.controller.js +131 -0
  40. package/src/controllers/org.controller.js +357 -0
  41. package/src/controllers/orgAdmin.controller.js +491 -0
  42. package/src/controllers/stripeAdmin.controller.js +410 -0
  43. package/src/controllers/user.controller.js +361 -0
  44. package/src/controllers/userAdmin.controller.js +277 -0
  45. package/src/controllers/waitingList.controller.js +167 -0
  46. package/src/controllers/webhook.controller.js +200 -0
  47. package/src/middleware/auth.js +66 -0
  48. package/src/middleware/errorCapture.js +170 -0
  49. package/src/middleware/headlessApiTokenAuth.js +57 -0
  50. package/src/middleware/org.js +108 -0
  51. package/src/middleware.js +901 -0
  52. package/src/models/ActionEvent.js +31 -0
  53. package/src/models/ActivityLog.js +41 -0
  54. package/src/models/Asset.js +84 -0
  55. package/src/models/AuditEvent.js +93 -0
  56. package/src/models/EmailLog.js +28 -0
  57. package/src/models/ErrorAggregate.js +72 -0
  58. package/src/models/FormSubmission.js +41 -0
  59. package/src/models/GlobalSetting.js +38 -0
  60. package/src/models/HeadlessApiToken.js +24 -0
  61. package/src/models/HeadlessModelDefinition.js +41 -0
  62. package/src/models/I18nEntry.js +77 -0
  63. package/src/models/I18nLocale.js +33 -0
  64. package/src/models/Invite.js +70 -0
  65. package/src/models/JsonConfig.js +46 -0
  66. package/src/models/Notification.js +60 -0
  67. package/src/models/Organization.js +57 -0
  68. package/src/models/OrganizationMember.js +43 -0
  69. package/src/models/StripeCatalogItem.js +77 -0
  70. package/src/models/StripeWebhookEvent.js +57 -0
  71. package/src/models/User.js +89 -0
  72. package/src/models/VirtualEjsFile.js +60 -0
  73. package/src/models/VirtualEjsFileVersion.js +43 -0
  74. package/src/models/VirtualEjsGroupChange.js +32 -0
  75. package/src/models/WaitingList.js +41 -0
  76. package/src/models/Webhook.js +63 -0
  77. package/src/models/Workflow.js +29 -0
  78. package/src/models/WorkflowExecution.js +12 -0
  79. package/src/routes/admin.routes.js +26 -0
  80. package/src/routes/adminAssets.routes.js +28 -0
  81. package/src/routes/adminAssetsStorage.routes.js +13 -0
  82. package/src/routes/adminAudit.routes.js +196 -0
  83. package/src/routes/adminEjsVirtual.routes.js +17 -0
  84. package/src/routes/adminErrors.routes.js +164 -0
  85. package/src/routes/adminFeatureFlags.routes.js +12 -0
  86. package/src/routes/adminHeadless.routes.js +38 -0
  87. package/src/routes/adminI18n.routes.js +22 -0
  88. package/src/routes/adminJsonConfigs.routes.js +15 -0
  89. package/src/routes/adminLlm.routes.js +12 -0
  90. package/src/routes/adminMigration.routes.js +81 -0
  91. package/src/routes/adminSeoConfig.routes.js +20 -0
  92. package/src/routes/adminUploadNamespaces.routes.js +13 -0
  93. package/src/routes/assets.routes.js +21 -0
  94. package/src/routes/auth.routes.js +12 -0
  95. package/src/routes/billing.routes.js +11 -0
  96. package/src/routes/errorTracking.routes.js +31 -0
  97. package/src/routes/featureFlags.routes.js +9 -0
  98. package/src/routes/forms.routes.js +9 -0
  99. package/src/routes/formsAdmin.routes.js +13 -0
  100. package/src/routes/globalSettings.routes.js +18 -0
  101. package/src/routes/headless.routes.js +15 -0
  102. package/src/routes/i18n.routes.js +8 -0
  103. package/src/routes/invite.routes.js +9 -0
  104. package/src/routes/jsonConfigs.routes.js +8 -0
  105. package/src/routes/log.routes.js +111 -0
  106. package/src/routes/metrics.routes.js +9 -0
  107. package/src/routes/notificationAdmin.routes.js +15 -0
  108. package/src/routes/notifications.routes.js +12 -0
  109. package/src/routes/org.routes.js +31 -0
  110. package/src/routes/orgAdmin.routes.js +20 -0
  111. package/src/routes/publicAssets.routes.js +7 -0
  112. package/src/routes/stripeAdmin.routes.js +20 -0
  113. package/src/routes/user.routes.js +22 -0
  114. package/src/routes/userAdmin.routes.js +15 -0
  115. package/src/routes/waitingList.routes.js +13 -0
  116. package/src/routes/waitingListAdmin.routes.js +9 -0
  117. package/src/routes/webhook.routes.js +32 -0
  118. package/src/routes/workflowWebhook.routes.js +54 -0
  119. package/src/routes/workflows.routes.js +110 -0
  120. package/src/services/assets.service.js +110 -0
  121. package/src/services/audit.service.js +62 -0
  122. package/src/services/auditLogger.js +165 -0
  123. package/src/services/ejsVirtual.service.js +614 -0
  124. package/src/services/email.service.js +351 -0
  125. package/src/services/errorLogger.js +221 -0
  126. package/src/services/featureFlags.service.js +202 -0
  127. package/src/services/forms.service.js +214 -0
  128. package/src/services/globalSettings.service.js +49 -0
  129. package/src/services/headlessApiTokens.service.js +158 -0
  130. package/src/services/headlessCrypto.service.js +31 -0
  131. package/src/services/headlessModels.service.js +356 -0
  132. package/src/services/i18n.service.js +314 -0
  133. package/src/services/i18nInferredKeys.service.js +337 -0
  134. package/src/services/jsonConfigs.service.js +392 -0
  135. package/src/services/llm.service.js +749 -0
  136. package/src/services/migration.service.js +581 -0
  137. package/src/services/migrationAssets/fsLocal.js +58 -0
  138. package/src/services/migrationAssets/index.js +134 -0
  139. package/src/services/migrationAssets/s3.js +75 -0
  140. package/src/services/migrationAssets/sftp.js +92 -0
  141. package/src/services/notification.service.js +212 -0
  142. package/src/services/objectStorage.service.js +514 -0
  143. package/src/services/seoConfig.service.js +402 -0
  144. package/src/services/storage.js +150 -0
  145. package/src/services/stripe.service.js +185 -0
  146. package/src/services/stripeHelper.service.js +264 -0
  147. package/src/services/uploadNamespaces.service.js +326 -0
  148. package/src/services/webhook.service.js +157 -0
  149. package/src/services/workflow.service.js +271 -0
  150. package/src/utils/asyncHandler.js +5 -0
  151. package/src/utils/encryption.js +80 -0
  152. package/src/utils/jwt.js +40 -0
  153. package/src/utils/orgRoles.js +156 -0
  154. package/src/utils/validation.js +26 -0
  155. package/src/utils/webhookRetry.js +93 -0
  156. package/views/admin-assets.ejs +444 -0
  157. package/views/admin-audit.ejs +283 -0
  158. package/views/admin-coolify-deploy.ejs +207 -0
  159. package/views/admin-dashboard-home.ejs +291 -0
  160. package/views/admin-dashboard.ejs +397 -0
  161. package/views/admin-ejs-virtual.ejs +280 -0
  162. package/views/admin-errors.ejs +368 -0
  163. package/views/admin-feature-flags.ejs +390 -0
  164. package/views/admin-forms.ejs +526 -0
  165. package/views/admin-global-settings.ejs +436 -0
  166. package/views/admin-headless.ejs +2020 -0
  167. package/views/admin-i18n-locales.ejs +221 -0
  168. package/views/admin-i18n.ejs +728 -0
  169. package/views/admin-json-configs.ejs +410 -0
  170. package/views/admin-llm.ejs +884 -0
  171. package/views/admin-metrics.ejs +274 -0
  172. package/views/admin-migration.ejs +814 -0
  173. package/views/admin-notifications.ejs +430 -0
  174. package/views/admin-organizations.ejs +984 -0
  175. package/views/admin-seo-config.ejs +673 -0
  176. package/views/admin-stripe-pricing.ejs +558 -0
  177. package/views/admin-test.ejs +342 -0
  178. package/views/admin-users.ejs +452 -0
  179. package/views/admin-waiting-list.ejs +547 -0
  180. package/views/admin-webhooks.ejs +329 -0
  181. package/views/admin-workflows.ejs +310 -0
  182. package/views/partials/admin-assets-script.ejs +2022 -0
  183. package/views/partials/admin-test-sidebar.ejs +14 -0
  184. package/views/partials/dashboard/nav-items.ejs +66 -0
  185. package/views/partials/dashboard/palette.ejs +63 -0
  186. package/views/partials/dashboard/sidebar.ejs +21 -0
  187. package/views/partials/dashboard/tab-bar.ejs +26 -0
  188. package/views/partials/footer.ejs +3 -0
@@ -0,0 +1,13 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { basicAuth } = require('../middleware/auth');
4
+ const adminUploadNamespacesController = require('../controllers/adminUploadNamespaces.controller');
5
+
6
+ router.get('/', basicAuth, adminUploadNamespacesController.listNamespaces);
7
+ router.get('/summary', basicAuth, adminUploadNamespacesController.getNamespacesSummary);
8
+ router.get('/:key', basicAuth, adminUploadNamespacesController.getNamespace);
9
+ router.post('/', basicAuth, adminUploadNamespacesController.createNamespace);
10
+ router.put('/:key', basicAuth, adminUploadNamespacesController.updateNamespace);
11
+ router.delete('/:key', basicAuth, adminUploadNamespacesController.deleteNamespace);
12
+
13
+ module.exports = router;
@@ -0,0 +1,21 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const multer = require('multer');
4
+ const { authenticate } = require('../middleware/auth');
5
+ const assetsController = require('../controllers/assets.controller');
6
+ const { auditMiddleware } = require('../services/auditLogger');
7
+
8
+ const upload = multer({
9
+ storage: multer.memoryStorage(),
10
+ limits: {
11
+ fileSize: parseInt(process.env.MULTER_FILE_SIZE_LIMIT || '1073741824', 10)
12
+ }
13
+ });
14
+
15
+ router.post('/upload', authenticate, auditMiddleware('user.asset.upload', { entityType: 'Asset' }), upload.single('file'), assetsController.upload);
16
+ router.get('/', authenticate, assetsController.list);
17
+ router.get('/:id', authenticate, assetsController.get);
18
+ router.get('/:id/download', authenticate, assetsController.download);
19
+ router.delete('/:id', authenticate, auditMiddleware('user.asset.delete', { entityType: 'Asset', getEntityId: (req) => req.params.id }), assetsController.delete);
20
+
21
+ module.exports = router;
@@ -0,0 +1,12 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const authController = require('../controllers/auth.controller');
4
+ const { authenticate } = require('../middleware/auth');
5
+ const { auditMiddleware } = require('../services/auditLogger');
6
+
7
+ router.post('/register', auditMiddleware('public.auth.register', { entityType: 'User' }), authController.register);
8
+ router.post('/login', auditMiddleware('public.auth.login', { entityType: 'User' }), authController.login);
9
+ router.post('/refresh-token', auditMiddleware('public.auth.refresh', { entityType: 'User' }), authController.refresh);
10
+ router.get('/me', authenticate, authController.me);
11
+
12
+ module.exports = router;
@@ -0,0 +1,11 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const billingController = require('../controllers/billing.controller');
4
+ const { authenticate } = require('../middleware/auth');
5
+ const { auditMiddleware } = require('../services/auditLogger');
6
+
7
+ router.post('/create-checkout-session', authenticate, auditMiddleware('user.billing.checkout_session.create', { entityType: 'StripeCheckoutSession' }), billingController.createCheckoutSession);
8
+ router.post('/create-portal-session', authenticate, auditMiddleware('user.billing.portal_session.create', { entityType: 'StripePortalSession' }), billingController.createPortalSession);
9
+ router.post('/reconcile-subscription', authenticate, auditMiddleware('user.billing.subscription.reconcile', { entityType: 'Subscription' }), billingController.reconcileSubscription);
10
+
11
+ module.exports = router;
@@ -0,0 +1,31 @@
1
+ const express = require('express');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+
5
+ const router = express.Router();
6
+
7
+ router.get('/browser-sdk', (req, res) => {
8
+ const filePath = path.join(
9
+ __dirname,
10
+ '..',
11
+ '..',
12
+ 'sdk',
13
+ 'error-tracking',
14
+ 'browser',
15
+ 'dist',
16
+ 'embed.iife.js',
17
+ );
18
+
19
+ fs.readFile(filePath, 'utf8', (err, contents) => {
20
+ if (err) {
21
+ res.status(404).type('text/plain').send('Browser SDK not found');
22
+ return;
23
+ }
24
+
25
+ res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
26
+ res.setHeader('Cache-Control', 'no-cache');
27
+ res.send(contents);
28
+ });
29
+ });
30
+
31
+ module.exports = router;
@@ -0,0 +1,9 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { authenticate } = require('../middleware/auth');
4
+ const featureFlagsController = require('../controllers/featureFlags.controller');
5
+
6
+ router.get('/public', featureFlagsController.getPublicFlags);
7
+ router.get('/', authenticate, featureFlagsController.getEvaluatedFlags);
8
+
9
+ module.exports = router;
@@ -0,0 +1,9 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const formsController = require('../controllers/forms.controller');
4
+ const asyncHandler = require('../utils/asyncHandler');
5
+ const { auditMiddleware } = require('../services/auditLogger');
6
+
7
+ router.post('/submit/:formId', auditMiddleware('public.form.submit', { entityType: 'FormSubmission' }), asyncHandler(formsController.submit));
8
+
9
+ module.exports = router;
@@ -0,0 +1,13 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { basicAuth } = require('../middleware/auth');
4
+ const formsController = require('../controllers/forms.controller');
5
+ const asyncHandler = require('../utils/asyncHandler');
6
+
7
+ router.get('/', basicAuth, asyncHandler(formsController.adminList));
8
+ router.delete('/:id', basicAuth, asyncHandler(formsController.deleteSubmission));
9
+ router.get('/definitions', basicAuth, asyncHandler(formsController.getForms));
10
+ router.post('/definitions', basicAuth, asyncHandler(formsController.saveForm));
11
+ router.delete('/definitions/:id', basicAuth, asyncHandler(formsController.deleteForm));
12
+
13
+ module.exports = router;
@@ -0,0 +1,18 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { basicAuth } = require('../middleware/auth');
4
+ const globalSettingsController = require('../controllers/globalSettings.controller');
5
+
6
+ // Public route (no auth)
7
+ router.get('/public', globalSettingsController.getPublicSettings);
8
+
9
+ // Protected routes (Basic Auth)
10
+ router.get('/', basicAuth, globalSettingsController.getAllSettings);
11
+ // more specific path before :key catch-all
12
+ router.get('/:key/reveal', basicAuth, globalSettingsController.revealSetting);
13
+ router.get('/:key', basicAuth, globalSettingsController.getSetting);
14
+ router.put('/:key', basicAuth, globalSettingsController.updateSetting);
15
+ router.post('/', basicAuth, globalSettingsController.createSetting);
16
+ router.delete('/:key', basicAuth, globalSettingsController.deleteSetting);
17
+
18
+ module.exports = router;
@@ -0,0 +1,15 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+
4
+ const headlessCrudController = require('../controllers/headlessCrud.controller');
5
+ const { headlessApiTokenAuth, requireHeadlessPermission } = require('../middleware/headlessApiTokenAuth');
6
+
7
+ router.use(headlessApiTokenAuth());
8
+
9
+ router.get('/:modelCode', requireHeadlessPermission(), headlessCrudController.list);
10
+ router.post('/:modelCode', requireHeadlessPermission(), headlessCrudController.create);
11
+ router.get('/:modelCode/:id', requireHeadlessPermission(), headlessCrudController.get);
12
+ router.put('/:modelCode/:id', requireHeadlessPermission(), headlessCrudController.update);
13
+ router.delete('/:modelCode/:id', requireHeadlessPermission(), headlessCrudController.remove);
14
+
15
+ module.exports = router;
@@ -0,0 +1,8 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+
4
+ const i18nController = require('../controllers/i18n.controller');
5
+
6
+ router.get('/bundle', i18nController.getBundle);
7
+
8
+ module.exports = router;
@@ -0,0 +1,9 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const inviteController = require('../controllers/invite.controller');
4
+ const { auditMiddleware } = require('../services/auditLogger');
5
+
6
+ router.get('/info', inviteController.getInviteInfo);
7
+ router.post('/accept', auditMiddleware('user.invite.accept', { entityType: 'Invite' }), inviteController.acceptInvite);
8
+
9
+ module.exports = router;
@@ -0,0 +1,8 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+
4
+ const jsonConfigsController = require('../controllers/jsonConfigs.controller');
5
+
6
+ router.get('/:slug', jsonConfigsController.getPublic);
7
+
8
+ module.exports = router;
@@ -0,0 +1,111 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { logError, getConfig } = require('../services/errorLogger');
4
+ const { verifyAccessToken } = require('../utils/jwt');
5
+
6
+ const rateLimitStore = new Map();
7
+ const CLEANUP_INTERVAL = 60000;
8
+
9
+ setInterval(() => {
10
+ const now = Date.now();
11
+ for (const [key, data] of rateLimitStore) {
12
+ if (now - data.windowStart > 60000) {
13
+ rateLimitStore.delete(key);
14
+ }
15
+ }
16
+ }, CLEANUP_INTERVAL);
17
+
18
+ async function checkRateLimit(ip, isAuthenticated) {
19
+ const config = await getConfig();
20
+ const limit = isAuthenticated ? config.errorRateLimitPerMinute : config.errorRateLimitAnonPerMinute;
21
+ const key = `${ip}:${isAuthenticated ? 'auth' : 'anon'}`;
22
+ const now = Date.now();
23
+
24
+ let data = rateLimitStore.get(key);
25
+ if (!data || now - data.windowStart > 60000) {
26
+ data = { windowStart: now, count: 0 };
27
+ rateLimitStore.set(key, data);
28
+ }
29
+
30
+ data.count++;
31
+
32
+ if (data.count > limit) {
33
+ return { allowed: false, remaining: 0, limit };
34
+ }
35
+
36
+ return { allowed: true, remaining: limit - data.count, limit };
37
+ }
38
+
39
+ function extractUserFromToken(req) {
40
+ try {
41
+ const authHeader = req.headers.authorization;
42
+ if (!authHeader || !authHeader.startsWith('Bearer ')) return null;
43
+ const token = authHeader.slice(7).trim();
44
+ if (!token) return null;
45
+ const decoded = verifyAccessToken(token);
46
+ return { userId: decoded.userId, role: decoded.role };
47
+ } catch (e) {
48
+ return null;
49
+ }
50
+ }
51
+
52
+ router.post('/error', async (req, res) => {
53
+ try {
54
+ const ip = req.ip || req.headers['x-forwarded-for']?.split(',')[0]?.trim() || 'unknown';
55
+ const user = extractUserFromToken(req);
56
+ const isAuthenticated = !!user;
57
+
58
+ const rateCheck = await checkRateLimit(ip, isAuthenticated);
59
+ res.setHeader('X-RateLimit-Limit', rateCheck.limit);
60
+ res.setHeader('X-RateLimit-Remaining', Math.max(0, rateCheck.remaining));
61
+
62
+ if (!rateCheck.allowed) {
63
+ return res.status(429).json({ error: 'Too many error reports. Please try again later.' });
64
+ }
65
+
66
+ const config = await getConfig();
67
+ if (!config.errorTrackingEnabled) {
68
+ return res.status(200).json({ ok: true, tracked: false });
69
+ }
70
+
71
+ const body = req.body || {};
72
+
73
+ const event = {
74
+ source: 'frontend',
75
+ severity: body.severity || 'error',
76
+ errorName: body.errorName || body.name || 'Error',
77
+ errorCode: body.errorCode || body.code,
78
+ message: String(body.message || '').slice(0, 2000),
79
+ stack: String(body.stack || '').slice(0, 5000),
80
+ actor: {
81
+ userId: user?.userId,
82
+ role: user?.role,
83
+ ip,
84
+ userAgent: req.headers['user-agent'],
85
+ },
86
+ request: {
87
+ method: body.request?.method,
88
+ path: body.request?.path || body.url,
89
+ statusCode: body.request?.statusCode || body.statusCode,
90
+ requestId: body.request?.requestId || req.headers['x-request-id'],
91
+ },
92
+ runtime: {
93
+ url: String(body.url || body.runtime?.url || '').slice(0, 500),
94
+ referrer: String(body.referrer || body.runtime?.referrer || '').slice(0, 500),
95
+ viewport: body.runtime?.viewport,
96
+ locale: body.runtime?.locale,
97
+ appVersion: body.runtime?.appVersion,
98
+ },
99
+ extra: body.extra,
100
+ };
101
+
102
+ await logError(event);
103
+
104
+ return res.status(200).json({ ok: true, tracked: true });
105
+ } catch (err) {
106
+ console.log('[LogRoutes] Error logging frontend error:', err.message);
107
+ return res.status(500).json({ error: 'Failed to log error' });
108
+ }
109
+ });
110
+
111
+ module.exports = router;
@@ -0,0 +1,9 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const metricsController = require('../controllers/metrics.controller');
4
+ const asyncHandler = require('../utils/asyncHandler');
5
+
6
+ router.post('/track', asyncHandler(metricsController.track));
7
+ router.get('/impact', asyncHandler(metricsController.getImpact));
8
+
9
+ module.exports = router;
@@ -0,0 +1,15 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+
4
+ const { basicAuth } = require('../middleware/auth');
5
+ const notificationAdminController = require('../controllers/notificationAdmin.controller');
6
+ const asyncHandler = require('../utils/asyncHandler');
7
+
8
+ router.get('/stats', basicAuth, asyncHandler(notificationAdminController.getNotificationStats));
9
+ router.get('/', basicAuth, asyncHandler(notificationAdminController.listNotifications));
10
+ router.post('/send', basicAuth, asyncHandler(notificationAdminController.sendNotification));
11
+ router.post('/broadcast', basicAuth, asyncHandler(notificationAdminController.broadcastNotification));
12
+ router.delete('/:id', basicAuth, asyncHandler(notificationAdminController.deleteNotification));
13
+ router.post('/:id/retry-email', basicAuth, asyncHandler(notificationAdminController.retryEmailNotification));
14
+
15
+ module.exports = router;
@@ -0,0 +1,12 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { authenticate } = require('../middleware/auth');
4
+ const notificationsController = require('../controllers/notifications.controller');
5
+ const { auditMiddleware } = require('../services/auditLogger');
6
+
7
+ router.get('/notifications', authenticate, notificationsController.getNotifications);
8
+ router.put('/notifications/:id/read', authenticate, auditMiddleware('user.notification.read', { entityType: 'Notification', getEntityId: (req) => req.params.id }), notificationsController.markNotificationAsRead);
9
+ router.get('/activity-log', authenticate, notificationsController.getActivityLog);
10
+ router.post('/activity-log', authenticate, auditMiddleware('user.activity_log.create', { entityType: 'ActivityLog' }), notificationsController.createActivityLog);
11
+
12
+ module.exports = router;
@@ -0,0 +1,31 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { authenticate } = require('../middleware/auth');
4
+ const { loadOrgContext, requireOrgMember, requireOrgRoleAtLeast, requireOrgRole } = require('../middleware/org');
5
+ const orgController = require('../controllers/org.controller');
6
+ const inviteController = require('../controllers/invite.controller');
7
+ const { auditMiddleware } = require('../services/auditLogger');
8
+
9
+ router.get('/public', orgController.listPublicOrgs);
10
+
11
+ router.get('/', authenticate, auditMiddleware('user.org.list', { entityType: 'Org' }), orgController.listOrgs);
12
+ router.post('/', authenticate, auditMiddleware('user.org.create', { entityType: 'Org' }), orgController.createOrg);
13
+
14
+ router.get('/:orgId/public', orgController.getOrgPublic);
15
+
16
+ router.get('/:orgId', authenticate, loadOrgContext, requireOrgMember, auditMiddleware('user.org.get', { entityType: 'Org', getEntityId: (req) => req.params.orgId }), orgController.getOrg);
17
+ router.put('/:orgId', authenticate, loadOrgContext, requireOrgRoleAtLeast('admin'), auditMiddleware('user.org.update', { entityType: 'Org', getEntityId: (req) => req.params.orgId }), orgController.updateOrg);
18
+ router.delete('/:orgId', authenticate, loadOrgContext, requireOrgRole('owner'), auditMiddleware('user.org.delete', { entityType: 'Org', getEntityId: (req) => req.params.orgId }), orgController.deleteOrg);
19
+
20
+ router.post('/:orgId/join', authenticate, loadOrgContext, auditMiddleware('user.org.join', { entityType: 'Org', getEntityId: (req) => req.params.orgId }), orgController.joinOrg);
21
+
22
+ router.get('/:orgId/members', authenticate, loadOrgContext, requireOrgMember, auditMiddleware('user.org.members.list', { entityType: 'Org', getEntityId: (req) => req.params.orgId }), orgController.listMembers);
23
+ router.post('/:orgId/members', authenticate, loadOrgContext, requireOrgRoleAtLeast('admin'), auditMiddleware('user.org.member.add', { entityType: 'Org', getEntityId: (req) => req.params.orgId }), orgController.addMember);
24
+ router.put('/:orgId/members/:userId/role', authenticate, loadOrgContext, requireOrgRoleAtLeast('admin'), auditMiddleware('user.org.member.role.update', { entityType: 'Org', getEntityId: (req) => req.params.orgId }), orgController.updateMemberRole);
25
+ router.delete('/:orgId/members/:userId', authenticate, loadOrgContext, requireOrgRoleAtLeast('admin'), auditMiddleware('user.org.member.remove', { entityType: 'Org', getEntityId: (req) => req.params.orgId }), orgController.removeMember);
26
+
27
+ router.get('/:orgId/invites', authenticate, loadOrgContext, requireOrgRoleAtLeast('admin'), auditMiddleware('user.org.invites.list', { entityType: 'Org', getEntityId: (req) => req.params.orgId }), inviteController.listInvites);
28
+ router.post('/:orgId/invites', authenticate, loadOrgContext, requireOrgRoleAtLeast('admin'), auditMiddleware('user.org.invite.create', { entityType: 'OrgInvite', getEntityId: (req) => req.params.inviteId || req.params.orgId }), inviteController.createInvite);
29
+ router.delete('/:orgId/invites/:inviteId', authenticate, loadOrgContext, requireOrgRoleAtLeast('admin'), auditMiddleware('user.org.invite.revoke', { entityType: 'OrgInvite', getEntityId: (req) => req.params.inviteId }), inviteController.revokeInvite);
30
+
31
+ module.exports = router;
@@ -0,0 +1,20 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+
4
+ const { basicAuth } = require('../middleware/auth');
5
+ const orgAdminController = require('../controllers/orgAdmin.controller');
6
+ const asyncHandler = require('../utils/asyncHandler');
7
+
8
+ router.get('/', basicAuth, asyncHandler(orgAdminController.listOrgs));
9
+ router.get('/:orgId', basicAuth, asyncHandler(orgAdminController.getOrg));
10
+
11
+ router.get('/:orgId/members', basicAuth, asyncHandler(orgAdminController.listMembers));
12
+ router.patch('/:orgId/members/:memberId', basicAuth, asyncHandler(orgAdminController.updateMember));
13
+ router.delete('/:orgId/members/:memberId', basicAuth, asyncHandler(orgAdminController.removeMember));
14
+
15
+ router.get('/:orgId/invites', basicAuth, asyncHandler(orgAdminController.listInvites));
16
+ router.post('/:orgId/invites', basicAuth, asyncHandler(orgAdminController.createInvite));
17
+ router.delete('/:orgId/invites/:inviteId', basicAuth, asyncHandler(orgAdminController.revokeInvite));
18
+ router.post('/:orgId/invites/:inviteId/resend', basicAuth, asyncHandler(orgAdminController.resendInvite));
19
+
20
+ module.exports = router;
@@ -0,0 +1,7 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const assetsController = require('../controllers/assets.controller');
4
+
5
+ router.get('/*', assetsController.getPublicAsset);
6
+
7
+ module.exports = router;
@@ -0,0 +1,20 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+
4
+ const { basicAuth } = require('../middleware/auth');
5
+ const stripeAdminController = require('../controllers/stripeAdmin.controller');
6
+ const asyncHandler = require('../utils/asyncHandler');
7
+
8
+ router.get('/status', basicAuth, asyncHandler(stripeAdminController.getStripeStatus));
9
+ router.get('/catalog', basicAuth, asyncHandler(stripeAdminController.listCatalog));
10
+ router.get('/catalog/:id', basicAuth, asyncHandler(stripeAdminController.getCatalogItem));
11
+ router.post('/catalog/upsert', basicAuth, asyncHandler(stripeAdminController.upsertCatalogItem));
12
+ router.post('/catalog/import', basicAuth, asyncHandler(stripeAdminController.importStripePrice));
13
+ router.post('/catalog/:id/deactivate', basicAuth, asyncHandler(stripeAdminController.deactivateCatalogItem));
14
+ router.post('/catalog/:id/activate', basicAuth, asyncHandler(stripeAdminController.activateCatalogItem));
15
+ router.delete('/catalog/:id', basicAuth, asyncHandler(stripeAdminController.deleteCatalogItem));
16
+ router.get('/products', basicAuth, asyncHandler(stripeAdminController.listStripeProducts));
17
+ router.get('/prices', basicAuth, asyncHandler(stripeAdminController.listStripePrices));
18
+ router.post('/env/sync', basicAuth, asyncHandler(stripeAdminController.syncEnvFromCatalog));
19
+
20
+ module.exports = router;
@@ -0,0 +1,22 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { authenticate } = require('../middleware/auth');
4
+ const userController = require('../controllers/user.controller');
5
+ const { auditMiddleware } = require('../services/auditLogger');
6
+
7
+ // Profile management
8
+ router.put('/profile', authenticate, auditMiddleware('user.profile.update', { entityType: 'User' }), userController.updateProfile);
9
+
10
+ // Password management
11
+ router.put('/password', authenticate, auditMiddleware('user.password.change', { entityType: 'User' }), userController.changePassword);
12
+ router.post('/password-reset-request', auditMiddleware('user.password_reset.request', { entityType: 'User' }), userController.requestPasswordReset);
13
+ router.post('/password-reset-confirm', auditMiddleware('user.password_reset.confirm', { entityType: 'User' }), userController.confirmPasswordReset);
14
+
15
+ // Account deletion
16
+ router.delete('/account', authenticate, auditMiddleware('user.account.delete', { entityType: 'User' }), userController.deleteAccount);
17
+
18
+ // Settings
19
+ router.get('/settings', authenticate, auditMiddleware('user.settings.get', { entityType: 'User' }), userController.getSettings);
20
+ router.put('/settings', authenticate, auditMiddleware('user.settings.update', { entityType: 'User' }), userController.updateSettings);
21
+
22
+ module.exports = router;
@@ -0,0 +1,15 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+
4
+ const { basicAuth } = require('../middleware/auth');
5
+ const userAdminController = require('../controllers/userAdmin.controller');
6
+ const asyncHandler = require('../utils/asyncHandler');
7
+
8
+ router.get('/stats', basicAuth, asyncHandler(userAdminController.getUserStats));
9
+ router.get('/', basicAuth, asyncHandler(userAdminController.listUsers));
10
+ router.get('/:id', basicAuth, asyncHandler(userAdminController.getUser));
11
+ router.patch('/:id', basicAuth, asyncHandler(userAdminController.updateUser));
12
+ router.post('/:id/disable', basicAuth, asyncHandler(userAdminController.disableUser));
13
+ router.post('/:id/enable', basicAuth, asyncHandler(userAdminController.enableUser));
14
+
15
+ module.exports = router;
@@ -0,0 +1,13 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const waitingListController = require('../controllers/waitingList.controller');
4
+ const asyncHandler = require('../utils/asyncHandler');
5
+ const { auditMiddleware } = require('../services/auditLogger');
6
+
7
+ // POST /api/waiting-list/subscribe - Subscribe to waiting list
8
+ router.post('/subscribe', auditMiddleware('public.waiting_list.subscribe', { entityType: 'WaitingList' }), asyncHandler(waitingListController.subscribe));
9
+
10
+ // GET /api/waiting-list/stats - Get waiting list statistics (public)
11
+ router.get('/stats', asyncHandler(waitingListController.getStats));
12
+
13
+ module.exports = router;
@@ -0,0 +1,9 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { basicAuth } = require('../middleware/auth');
4
+ const waitingListController = require('../controllers/waitingList.controller');
5
+ const asyncHandler = require('../utils/asyncHandler');
6
+
7
+ router.get('/', basicAuth, asyncHandler(waitingListController.adminList));
8
+
9
+ module.exports = router;
@@ -0,0 +1,32 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const webhookController = require('../controllers/webhook.controller');
4
+ const authMiddleware = require('../middleware/auth');
5
+ const orgMiddleware = require('../middleware/org');
6
+
7
+ // Webhook routes support both User (JWT) and SuperAdmin (Basic Auth)
8
+ router.use((req, res, next) => {
9
+ // If already authenticated via Basic Auth (SuperAdmin), skip JWT check
10
+ const authHeader = req.headers.authorization;
11
+ if (authHeader && authHeader.startsWith('Basic ')) {
12
+ return authMiddleware.basicAuth(req, res, next);
13
+ }
14
+ // Otherwise require JWT
15
+ authMiddleware.authenticate(req, res, next);
16
+ });
17
+
18
+ // Optional organization context: required for non-admins
19
+ router.use((req, res, next) => {
20
+ const isBasicAuth = req.headers.authorization?.startsWith('Basic ');
21
+ if (isBasicAuth) return next();
22
+ orgMiddleware.loadOrgContext(req, res, next);
23
+ });
24
+
25
+ router.get('/', webhookController.getAll);
26
+ router.post('/', webhookController.create);
27
+ router.patch('/:id', webhookController.update);
28
+ router.get('/:id/history', webhookController.getHistory);
29
+ router.delete('/:id', webhookController.delete);
30
+ router.post('/:id/test', webhookController.test);
31
+
32
+ module.exports = router;
@@ -0,0 +1,54 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const Workflow = require('../models/Workflow');
4
+ const workflowService = require('../services/workflow.service');
5
+
6
+ // Public Webhook Entrypoint
7
+ router.all('/:webhookId', async (req, res) => {
8
+ const workflow = await Workflow.findOne({
9
+ $or: [{ _id: req.params.webhookId }, { webhookSlug: req.params.webhookId }]
10
+ });
11
+
12
+ if (!workflow) return res.status(404).json({ error: 'Workflow not found' });
13
+
14
+ // Method Restriction
15
+ if (workflow.entrypoint?.allowedMethods?.length > 0 && !workflow.entrypoint.allowedMethods.includes(req.method)) {
16
+ return res.status(405).json({ error: `Method ${req.method} not allowed` });
17
+ }
18
+
19
+ // Auth Checks
20
+ if (workflow.entrypoint?.auth?.type === 'header') {
21
+ const val = req.headers[workflow.entrypoint.auth.headerName?.toLowerCase()];
22
+ if (val !== workflow.entrypoint.auth.headerValue) return res.status(401).json({ error: 'Unauthorized' });
23
+ } else if (workflow.entrypoint?.auth?.type === 'bearer') {
24
+ const authHeader = req.headers['authorization'];
25
+ if (!authHeader || !authHeader.startsWith('Bearer ') || authHeader.split(' ')[1] !== workflow.entrypoint.auth.headerValue) {
26
+ return res.status(401).json({ error: 'Unauthorized' });
27
+ }
28
+ }
29
+
30
+ if (workflow.status !== 'active' && !workflow.entrypoint?.testMode) {
31
+ return res.status(403).json({ error: 'Workflow is inactive' });
32
+ }
33
+
34
+ const initialContext = {
35
+ body: req.body,
36
+ query: req.query,
37
+ headers: req.headers,
38
+ method: req.method
39
+ };
40
+
41
+ if (workflow.entrypoint?.awaitResponse) {
42
+ try {
43
+ const service = await workflowService.execute(workflow._id, initialContext);
44
+ res.status(200).json(service.context.lastNode || { success: true });
45
+ } catch (err) {
46
+ res.status(500).json({ error: 'Execution failed', message: err.message });
47
+ }
48
+ } else {
49
+ workflowService.execute(workflow._id, initialContext).catch(console.error);
50
+ res.status(201).json({ message: 'Triggered', executionId: Date.now().toString() });
51
+ }
52
+ });
53
+
54
+ module.exports = router;