@intranefr/superbackend 1.5.2 → 1.5.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 (41) hide show
  1. package/index.js +2 -0
  2. package/manage.js +745 -0
  3. package/package.json +4 -2
  4. package/src/controllers/admin.controller.js +11 -5
  5. package/src/controllers/adminAgents.controller.js +37 -0
  6. package/src/controllers/adminLlm.controller.js +19 -0
  7. package/src/controllers/adminMarkdowns.controller.js +157 -0
  8. package/src/controllers/adminScripts.controller.js +138 -0
  9. package/src/controllers/adminTelegram.controller.js +72 -0
  10. package/src/controllers/markdowns.controller.js +42 -0
  11. package/src/helpers/mongooseHelper.js +6 -6
  12. package/src/helpers/scriptBase.js +2 -2
  13. package/src/middleware.js +136 -29
  14. package/src/models/Agent.js +105 -0
  15. package/src/models/AgentMessage.js +82 -0
  16. package/src/models/Markdown.js +75 -0
  17. package/src/models/ScriptRun.js +8 -0
  18. package/src/models/TelegramBot.js +42 -0
  19. package/src/routes/adminAgents.routes.js +13 -0
  20. package/src/routes/adminLlm.routes.js +1 -0
  21. package/src/routes/adminMarkdowns.routes.js +16 -0
  22. package/src/routes/adminScripts.routes.js +4 -1
  23. package/src/routes/adminTelegram.routes.js +14 -0
  24. package/src/routes/markdowns.routes.js +16 -0
  25. package/src/services/agent.service.js +546 -0
  26. package/src/services/agentHistory.service.js +345 -0
  27. package/src/services/agentTools.service.js +578 -0
  28. package/src/services/jsonConfigs.service.js +22 -10
  29. package/src/services/llm.service.js +219 -6
  30. package/src/services/markdowns.service.js +522 -0
  31. package/src/services/scriptsRunner.service.js +328 -37
  32. package/src/services/telegram.service.js +130 -0
  33. package/views/admin-agents.ejs +273 -0
  34. package/views/admin-coolify-deploy.ejs +8 -8
  35. package/views/admin-dashboard.ejs +36 -5
  36. package/views/admin-experiments.ejs +1 -1
  37. package/views/admin-markdowns.ejs +905 -0
  38. package/views/admin-scripts.ejs +221 -4
  39. package/views/admin-telegram.ejs +269 -0
  40. package/views/partials/dashboard/nav-items.ejs +3 -0
  41. package/analysis-only.skill +0 -0
package/src/middleware.js CHANGED
@@ -161,6 +161,8 @@ function createMiddleware(options = {}) {
161
161
  maxPoolSize: 10,
162
162
  };
163
163
 
164
+ const telegramService = require("./services/telegram.service");
165
+
164
166
  // Return a promise that resolves when connection is established
165
167
  const connectionPromise = mongoose
166
168
  .connect(mongoUri, connectionOptions)
@@ -173,6 +175,9 @@ function createMiddleware(options = {}) {
173
175
  await blogCronsBootstrap.bootstrap();
174
176
  await require("./services/experimentsCronsBootstrap.service").bootstrap();
175
177
 
178
+ // Initialize Telegram bots
179
+ await telegramService.init();
180
+
176
181
  // Console manager is already initialized early in the middleware
177
182
  console.log("[Console Manager] MongoDB connection established");
178
183
 
@@ -658,36 +663,98 @@ function createMiddleware(options = {}) {
658
663
  });
659
664
  });
660
665
 
661
- router.get(`${adminPath}/db-browser`, basicAuth, (req, res) => {
662
- const templatePath = path.join(
663
- __dirname,
664
- "..",
665
- "views",
666
- "admin-db-browser.ejs",
667
- );
668
- fs.readFile(templatePath, "utf8", (err, template) => {
669
- if (err) {
670
- console.error("Error reading template:", err);
671
- return res.status(500).send("Error loading page");
672
- }
673
- try {
674
- const html = ejs.render(
675
- template,
676
- {
677
- baseUrl: req.baseUrl,
678
- adminPath,
679
- },
680
- {
681
- filename: templatePath,
682
- },
683
- );
684
- res.send(html);
685
- } catch (renderErr) {
686
- console.error("Error rendering template:", renderErr);
687
- res.status(500).send("Error rendering page");
688
- }
666
+ router.get(`${adminPath}/db-browser`, basicAuth, (req, res) => {
667
+ const templatePath = path.join(
668
+ __dirname,
669
+ "..",
670
+ "views",
671
+ "admin-db-browser.ejs",
672
+ );
673
+ fs.readFile(templatePath, "utf8", (err, template) => {
674
+ if (err) {
675
+ console.error("Error reading template:", err);
676
+ return res.status(500).send("Error loading page");
677
+ }
678
+ try {
679
+ const html = ejs.render(
680
+ template,
681
+ {
682
+ baseUrl: req.baseUrl,
683
+ adminPath,
684
+ },
685
+ {
686
+ filename: templatePath,
687
+ },
688
+ );
689
+ res.send(html);
690
+ } catch (renderErr) {
691
+ console.error("Error rendering template:", renderErr);
692
+ res.status(500).send("Error rendering page");
693
+ }
694
+ });
695
+ });
696
+
697
+ router.get(`${adminPath}/telegram`, basicAuth, (req, res) => {
698
+ const templatePath = path.join(
699
+ __dirname,
700
+ "..",
701
+ "views",
702
+ "admin-telegram.ejs",
703
+ );
704
+ fs.readFile(templatePath, "utf8", (err, template) => {
705
+ if (err) {
706
+ console.error("Error reading template:", err);
707
+ return res.status(500).send("Error loading page");
708
+ }
709
+ try {
710
+ const html = ejs.render(
711
+ template,
712
+ {
713
+ baseUrl: req.baseUrl,
714
+ adminPath,
715
+ },
716
+ {
717
+ filename: templatePath,
718
+ },
719
+ );
720
+ res.send(html);
721
+ } catch (renderErr) {
722
+ console.error("Error rendering template:", renderErr);
723
+ res.status(500).send("Error rendering page");
724
+ }
725
+ });
726
+ });
727
+
728
+ router.get(`${adminPath}/agents`, basicAuth, (req, res) => {
729
+ const templatePath = path.join(
730
+ __dirname,
731
+ "..",
732
+ "views",
733
+ "admin-agents.ejs",
734
+ );
735
+ fs.readFile(templatePath, "utf8", (err, template) => {
736
+ if (err) {
737
+ console.error("Error reading template:", err);
738
+ return res.status(500).send("Error loading page");
739
+ }
740
+ try {
741
+ const html = ejs.render(
742
+ template,
743
+ {
744
+ baseUrl: req.baseUrl,
745
+ adminPath,
746
+ },
747
+ {
748
+ filename: templatePath,
749
+ },
750
+ );
751
+ res.send(html);
752
+ } catch (renderErr) {
753
+ console.error("Error rendering template:", renderErr);
754
+ res.status(500).send("Error rendering page");
755
+ }
756
+ });
689
757
  });
690
- });
691
758
 
692
759
  router.use("/api/admin", require("./routes/admin.routes"));
693
760
  router.use("/api/admin/settings", require("./routes/globalSettings.routes"));
@@ -699,6 +766,10 @@ function createMiddleware(options = {}) {
699
766
  "/api/admin/json-configs",
700
767
  require("./routes/adminJsonConfigs.routes"),
701
768
  );
769
+ router.use(
770
+ "/api/admin/markdowns",
771
+ require("./routes/adminMarkdowns.routes"),
772
+ );
702
773
  router.use(
703
774
  "/api/admin/rate-limits",
704
775
  require("./routes/adminRateLimits.routes"),
@@ -748,6 +819,8 @@ function createMiddleware(options = {}) {
748
819
  require("./routes/adminAudit.routes"),
749
820
  );
750
821
  router.use("/api/admin/llm", require("./routes/adminLlm.routes"));
822
+ router.use("/api/admin/telegram", require("./routes/adminTelegram.routes"));
823
+ router.use("/api/admin/agents", require("./routes/adminAgents.routes"));
751
824
  router.use(
752
825
  "/api/admin/ejs-virtual",
753
826
  require("./routes/adminEjsVirtual.routes"),
@@ -762,6 +835,7 @@ function createMiddleware(options = {}) {
762
835
  router.use("/api/settings", require("./routes/globalSettings.routes"));
763
836
  router.use("/api/feature-flags", require("./routes/featureFlags.routes"));
764
837
  router.use("/api/json-configs", require("./routes/jsonConfigs.routes"));
838
+ router.use("/api/markdowns", require("./routes/markdowns.routes"));
765
839
  router.use("/api/assets", require("./routes/assets.routes"));
766
840
  router.use("/api/i18n", require("./routes/i18n.routes"));
767
841
  router.use("/api/headless", require("./routes/headless.routes"));
@@ -1365,6 +1439,39 @@ function createMiddleware(options = {}) {
1365
1439
  });
1366
1440
  });
1367
1441
 
1442
+ // Admin markdowns page (protected by basic auth)
1443
+ router.get(`${adminPath}/markdowns`, basicAuth, (req, res) => {
1444
+ const templatePath = path.join(
1445
+ __dirname,
1446
+ "..",
1447
+ "views",
1448
+ "admin-markdowns.ejs",
1449
+ );
1450
+ fs.readFile(templatePath, "utf8", (err, template) => {
1451
+ if (err) {
1452
+ console.error("Error reading template:", err);
1453
+ return res.status(500).send("Error loading page");
1454
+ }
1455
+ try {
1456
+ const html = ejs.render(
1457
+ template,
1458
+ {
1459
+ baseUrl: req.baseUrl,
1460
+ adminPath,
1461
+ endpointRegistry,
1462
+ },
1463
+ {
1464
+ filename: templatePath,
1465
+ },
1466
+ );
1467
+ res.send(html);
1468
+ } catch (renderErr) {
1469
+ console.error("Error rendering template:", renderErr);
1470
+ res.status(500).send("Error rendering page");
1471
+ }
1472
+ });
1473
+ });
1474
+
1368
1475
  // Admin assets page (protected by basic auth)
1369
1476
  router.get(`${adminPath}/assets`, basicAuth, (req, res) => {
1370
1477
  const templatePath = path.join(
@@ -0,0 +1,105 @@
1
+ const mongoose = require('mongoose');
2
+
3
+ const agentSchema = new mongoose.Schema({
4
+ name: {
5
+ type: String,
6
+ required: true,
7
+ trim: true
8
+ },
9
+ systemPrompt: {
10
+ type: String,
11
+ default: `You are a helpful assistant with access to specific tools for querying data.
12
+
13
+ AVAILABLE TOOLS:
14
+
15
+ 1. query_database: Query the MongoDB database for insights.
16
+ - Parameters:
17
+ - modelName (required): The name of the Mongoose model (e.g., User, Markdown, AuditEvent)
18
+ - query (required): The MongoDB query object
19
+ - limit (optional): Limit the number of results (default: 5)
20
+ - Usage: Use this when you need to fetch specific data from the database.
21
+
22
+ 2. get_system_stats: Get general statistics about the system.
23
+ - Parameters: None
24
+ - Usage: Use this when you need overall counts of users, markdowns, and other system entities.
25
+
26
+ 3. raw_db_query: Execute raw MongoDB queries for database exploration.
27
+ - Parameters:
28
+ - queryType (required): The type of raw query to execute
29
+ • listDatabases: List all databases (requires admin access)
30
+ • listCollections: List all collections in a database
31
+ • countDocuments: Count documents in a collection
32
+ • findOne: Find a single document in a collection
33
+ • aggregate: Run aggregation pipeline
34
+ • adminCommand: Execute admin commands
35
+ - database (optional): Database name (defaults to current database)
36
+ - collection (required for collection queries): Collection name
37
+ - filter (optional): MongoDB filter/query object. Can be:
38
+ • A JSON object: { createdAt: { $gte: new Date() } }
39
+ • A JSON string: '{"createdAt": {"$gte": {"$date": "2024-01-01"}}}'
40
+ • For aggregate: an array of pipeline stages as object or JSON string
41
+ - limit (optional): Limit results (default: 10)
42
+ - adminCommand (optional): Admin command for adminCommand queryType (as object or JSON string)
43
+ - Usage: Use this to discover collection names, databases, or run admin commands.
44
+ - IMPORTANT: For complex queries, use JSON string format to avoid parsing issues
45
+
46
+ IMPORTANT ERROR HANDLING INSTRUCTIONS:
47
+ - When a tool returns an error, it will be in structured JSON format with error details
48
+ - ALWAYS provide a friendly, conversational response to the user about tool errors
49
+ - NEVER show raw error JSON to users
50
+ - DO: "I had trouble accessing the database. Let me try a different approach..."
51
+ - DO NOT: Show the actual error JSON to users
52
+ - Extract the error message and provide helpful suggestions based on the error context
53
+ - If an error is not recoverable, explain why and suggest alternatives
54
+ - If an error is recoverable, explain what you'll try next
55
+ - Use the error suggestions provided in the tool response to inform your response
56
+
57
+ INSTRUCTIONS:
58
+ - Always use tools when you need actual data from the database
59
+ - Never make up data or statistics
60
+ - For database queries, use exact model names as they appear in the system
61
+ - When using query_database, construct appropriate MongoDB query objects based on the user's request
62
+ - If you don't have enough information for a query, ask clarifying questions
63
+ - Use get_system_stats for high-level overview requests
64
+ - Use raw_db_query for:
65
+ * Discovering what collections exist: queryType: "listCollections"
66
+ * Finding database names: queryType: "listDatabases" (may require admin)
67
+ * Counting documents: queryType: "countDocuments" with collection and filter
68
+ * Exploring collection structure: queryType: "findOne" or "aggregate"
69
+ - For specific records, use query_database with appropriate filters
70
+
71
+ Respond helpfully and only use the tools when necessary for accurate information. Always provide friendly error messages to users when tools fail.`
72
+ },
73
+ providerKey: {
74
+ type: String,
75
+ required: true
76
+ },
77
+ model: {
78
+ type: String,
79
+ required: true
80
+ },
81
+ tools: {
82
+ type: [String],
83
+ default: []
84
+ },
85
+ temperature: {
86
+ type: Number,
87
+ default: 0.7
88
+ },
89
+ maxIterations: {
90
+ type: Number,
91
+ default: 10
92
+ },
93
+ orgId: {
94
+ type: mongoose.Schema.Types.ObjectId,
95
+ ref: 'Organization'
96
+ },
97
+ ownerUserId: {
98
+ type: mongoose.Schema.Types.ObjectId,
99
+ ref: 'User'
100
+ }
101
+ }, {
102
+ timestamps: true
103
+ });
104
+
105
+ module.exports = mongoose.model('Agent', agentSchema);
@@ -0,0 +1,82 @@
1
+ const mongoose = require('mongoose');
2
+ const { ObjectId } = mongoose.Schema.Types;
3
+
4
+ const agentMessageSchema = new mongoose.Schema({
5
+ agentId: {
6
+ type: ObjectId,
7
+ ref: 'Agent',
8
+ required: true,
9
+ index: true
10
+ },
11
+ chatId: {
12
+ type: String,
13
+ required: true,
14
+ index: true
15
+ },
16
+ role: {
17
+ type: String,
18
+ enum: ['user', 'assistant', 'system', 'tool'],
19
+ required: true
20
+ },
21
+ content: {
22
+ type: String,
23
+ required: function() {
24
+ // Content is not required if:
25
+ // 1. Role is 'tool' (content might be in metadata or implied) - though usually tool has content
26
+ // 2. Role is 'assistant' AND it has toolCalls (OpenAI often returns null content with tool calls)
27
+ if (this.role === 'tool') return false;
28
+ if (this.role === 'assistant' && this.toolCalls && this.toolCalls.length > 0) return false;
29
+ return true;
30
+ }
31
+ },
32
+ toolCalls: [{
33
+ name: String,
34
+ arguments: mongoose.Schema.Types.Mixed,
35
+ toolCallId: String
36
+ }],
37
+ toolCallId: {
38
+ type: String,
39
+ index: true
40
+ },
41
+ metadata: {
42
+ tokens: Number,
43
+ processingTime: Number,
44
+ model: String,
45
+ provider: String,
46
+ timestamp: Date,
47
+ temperature: Number
48
+ },
49
+ createdAt: {
50
+ type: Date,
51
+ default: Date.now,
52
+ index: true
53
+ },
54
+ updatedAt: {
55
+ type: Date,
56
+ default: Date.now
57
+ }
58
+ }, {
59
+ timestamps: true,
60
+ toJSON: { virtuals: true },
61
+ toObject: { virtuals: true }
62
+ });
63
+
64
+ // Compound index for efficient session history retrieval
65
+ agentMessageSchema.index(
66
+ { agentId: 1, chatId: 1, createdAt: 1 },
67
+ { name: 'session_history_idx' }
68
+ );
69
+
70
+ // Index for tool call lookup
71
+ agentMessageSchema.index(
72
+ { toolCallId: 1 },
73
+ { name: 'tool_call_idx' }
74
+ );
75
+
76
+ // Index for searching content
77
+ agentMessageSchema.index(
78
+ { content: 'text' },
79
+ { name: 'content_search_idx' }
80
+ );
81
+
82
+ module.exports = mongoose.model('AgentMessage', agentMessageSchema);
@@ -0,0 +1,75 @@
1
+ const mongoose = require('mongoose');
2
+
3
+ const markdownSchema = new mongoose.Schema(
4
+ {
5
+ title: {
6
+ type: String,
7
+ required: true,
8
+ trim: true,
9
+ },
10
+ slug: {
11
+ type: String,
12
+ required: true,
13
+ index: true,
14
+ trim: true,
15
+ },
16
+ category: {
17
+ type: String,
18
+ required: true,
19
+ index: true,
20
+ trim: true,
21
+ default: 'general',
22
+ },
23
+ group_code: {
24
+ type: String,
25
+ required: false,
26
+ index: true,
27
+ trim: true,
28
+ default: '',
29
+ },
30
+ markdownRaw: {
31
+ type: String,
32
+ required: true,
33
+ default: '',
34
+ },
35
+ publicEnabled: {
36
+ type: Boolean,
37
+ default: false,
38
+ index: true,
39
+ },
40
+ cacheTtlSeconds: {
41
+ type: Number,
42
+ default: 0,
43
+ },
44
+ status: {
45
+ type: String,
46
+ enum: ['draft', 'published', 'archived'],
47
+ default: 'draft',
48
+ index: true,
49
+ },
50
+ ownerUserId: {
51
+ type: mongoose.Schema.Types.ObjectId,
52
+ ref: 'User',
53
+ index: true,
54
+ default: null,
55
+ },
56
+ orgId: {
57
+ type: mongoose.Schema.Types.ObjectId,
58
+ ref: 'Organization',
59
+ index: true,
60
+ default: null,
61
+ },
62
+ },
63
+ { timestamps: true },
64
+ );
65
+
66
+ // Compound unique index for fast lookups
67
+ markdownSchema.index({ category: 1, group_code: 1, slug: 1 }, { unique: true });
68
+
69
+ // Additional indexes for common queries
70
+ markdownSchema.index({ status: 1, publicEnabled: 1 });
71
+ markdownSchema.index({ category: 1, status: 1 });
72
+ markdownSchema.index({ ownerUserId: 1, createdAt: -1 });
73
+ markdownSchema.index({ orgId: 1, createdAt: -1 });
74
+
75
+ module.exports = mongoose.model('Markdown', markdownSchema);
@@ -14,6 +14,14 @@ const scriptRunSchema = new mongoose.Schema(
14
14
  finishedAt: { type: Date, default: null },
15
15
  exitCode: { type: Number, default: null },
16
16
  outputTail: { type: String, default: '' },
17
+ fullOutput: { type: String, default: '' },
18
+ programmaticOutput: { type: String, default: '' },
19
+ returnResult: { type: String, default: '' },
20
+ lastConsoleLog: { type: String, default: '' },
21
+ outputType: { type: String, enum: ['return', 'console', 'none'], default: 'none' },
22
+ outputSize: { type: Number, default: 0 },
23
+ lineCount: { type: Number, default: 0 },
24
+ lastOutputUpdate: { type: Date, default: null },
17
25
  meta: { type: mongoose.Schema.Types.Mixed, default: null },
18
26
  },
19
27
  { timestamps: true, collection: 'script_runs' },
@@ -0,0 +1,42 @@
1
+ const mongoose = require('mongoose');
2
+
3
+ const telegramBotSchema = new mongoose.Schema({
4
+ name: {
5
+ type: String,
6
+ required: true,
7
+ trim: true
8
+ },
9
+ token: {
10
+ type: String,
11
+ required: true,
12
+ trim: true
13
+ },
14
+ isActive: {
15
+ type: Boolean,
16
+ default: false
17
+ },
18
+ allowedUserIds: {
19
+ type: [String],
20
+ default: []
21
+ },
22
+ defaultAgentId: {
23
+ type: mongoose.Schema.Types.ObjectId,
24
+ ref: 'Agent'
25
+ },
26
+ orgId: {
27
+ type: mongoose.Schema.Types.ObjectId,
28
+ ref: 'Organization'
29
+ },
30
+ status: {
31
+ type: String,
32
+ enum: ['stopped', 'running', 'error'],
33
+ default: 'stopped'
34
+ },
35
+ lastError: {
36
+ type: String
37
+ }
38
+ }, {
39
+ timestamps: true
40
+ });
41
+
42
+ module.exports = mongoose.model('TelegramBot', telegramBotSchema);
@@ -0,0 +1,13 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const adminAgentsController = require('../controllers/adminAgents.controller');
4
+ const { basicAuth } = require('../middleware/auth');
5
+
6
+ router.use(basicAuth);
7
+
8
+ router.get('/', adminAgentsController.listAgents);
9
+ router.post('/', adminAgentsController.createAgent);
10
+ router.put('/:id', adminAgentsController.updateAgent);
11
+ router.delete('/:id', adminAgentsController.deleteAgent);
12
+
13
+ module.exports = router;
@@ -5,6 +5,7 @@ const adminLlmController = require("../controllers/adminLlm.controller");
5
5
  const rateLimiter = require("../services/rateLimiter.service");
6
6
 
7
7
  router.get("/config", basicAuth, adminLlmController.getConfig);
8
+ router.get("/providers", basicAuth, adminLlmController.listProviders);
8
9
  router.post("/config", basicAuth, rateLimiter.limit("llmConfigLimiter"), adminLlmController.saveConfig);
9
10
  router.get("/openrouter/models", basicAuth, adminLlmController.listOpenRouterModels);
10
11
  router.post("/prompts/:key/test", basicAuth, rateLimiter.limit("llmConfigLimiter"), adminLlmController.testPrompt);
@@ -0,0 +1,16 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { basicAuth } = require('../middleware/auth');
4
+
5
+ const adminMarkdownsController = require('../controllers/adminMarkdowns.controller');
6
+
7
+ router.get('/', basicAuth, adminMarkdownsController.list);
8
+ router.get('/group-codes/:category', basicAuth, adminMarkdownsController.getGroupCodes);
9
+ router.get('/folder/:category/:group_code?', basicAuth, adminMarkdownsController.getFolderContents);
10
+ router.get('/:id', basicAuth, adminMarkdownsController.get);
11
+ router.post('/', basicAuth, adminMarkdownsController.create);
12
+ router.put('/:id', basicAuth, adminMarkdownsController.update);
13
+ router.delete('/:id', basicAuth, adminMarkdownsController.remove);
14
+ router.post('/validate-path', basicAuth, adminMarkdownsController.validatePath);
15
+
16
+ module.exports = router;
@@ -10,7 +10,10 @@ router.get('/', controller.listScripts);
10
10
  router.post('/', controller.createScript);
11
11
  router.get('/runs', controller.listRuns);
12
12
  router.get('/runs/:runId', controller.getRun);
13
- router.get('/runs/:runId/stream', controller.streamRun);
13
+ router.get('/runs/:runId/stream', controller.streamRunLogs);
14
+ router.get('/runs/:runId/programmatic-output', controller.getProgrammaticOutput);
15
+ router.get('/runs/:runId/full-output', controller.getFullOutput);
16
+ router.get('/runs/:runId/download', controller.downloadOutput);
14
17
 
15
18
  router.get('/:id', controller.getScript);
16
19
  router.put('/:id', controller.updateScript);
@@ -0,0 +1,14 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const adminTelegramController = require('../controllers/adminTelegram.controller');
4
+ const { basicAuth } = require('../middleware/auth');
5
+
6
+ router.use(basicAuth);
7
+
8
+ router.get('/', adminTelegramController.listBots);
9
+ router.post('/', adminTelegramController.createBot);
10
+ router.put('/:id', adminTelegramController.updateBot);
11
+ router.delete('/:id', adminTelegramController.deleteBot);
12
+ router.post('/:id/toggle', adminTelegramController.toggleBot);
13
+
14
+ module.exports = router;
@@ -0,0 +1,16 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+
4
+ const markdownsController = require('../controllers/markdowns.controller');
5
+
6
+ // JSON versions (more specific first)
7
+ router.get('/:category/:group_code/:slug/json', markdownsController.getByPath);
8
+ router.get('/:category/:slug/json', markdownsController.getByPath);
9
+
10
+ // Raw versions
11
+ router.get('/:category/:group_code/:slug', markdownsController.getByPath);
12
+ router.get('/:category/:slug', markdownsController.getByPath); // No group_code
13
+
14
+ router.get('/search', markdownsController.search);
15
+
16
+ module.exports = router;