Architecture Overview¶
Purpose¶
A standalone Express + MySQL service that:
- Exposes 269 HTTP endpoints for the
Someli-DesignerNuxt FE (template management, content library, designer tooling, AI text/image generation) - Runs ~57 background workers (
job_*.js) onnode-cronschedules, generating template-based content per industry vertical - Hosts standalone AI bots (
FAQsbot.js,quizbot.js,trendsbot.js,content_generation_bot.js) that fill the content library - Pushes Slack notifications when content is missing (via
teamsnotification.js)
The repo is a fork of the someli-api skeleton, with the same conf.js / server.js / routes/routes.js / actions/ / helper/ / modules/dbDriver/ shape, drifted independently.
Folder layout¶
designer-api/
├── conf.js # 27 lines — env var passthrough
├── server.js # 70 lines — Express boot, Socket.IO, MySQL connect, mount routes
├── package.json # 30 runtime deps + 0 devDeps
├── Dockerfile # multi-stage; runs nginx + node behind it
├── .dockerignore
├── nginx.conf # nginx config inside the container
├── push.sh # manual SSH-deploy script
├── favicon.ico
├── routes/
│ └── routes.js # 13608 lines — 269 endpoints, one Api class
├── actions/
│ └── actions.js # generic CRUD (older fork of someli-api/actions/actions.js)
├── helper/
│ └── index.js # 88 lines — small helper set; no helper.js / aiLogics.js / constants.js / etc.
├── modules/
│ └── dbDriver/lib/mysql.js # callback MySQL pool wrapper (drifted from someli-api copy)
├── conf/
│ └── credentials.json # likely Google service account; verify .gitignore status
├── content_generation_bot.js # standalone AI worker (OpenAI)
├── post_image_generation1_bot.js # standalone image-gen worker
├── FAQsbot.js # standalone AI worker (FAQs generation)
├── quizbot.js # standalone AI worker (quizzes)
├── quotesbot.js # standalone AI worker (quotes)
├── trendsbot.js # standalone AI worker (trends)
├── teamsnotification.js # Slack notifier scheduled to ping channel on missing content
├── generateTextContent.js # text generation utility
├── pdfToExtractData.js # PDF text extraction utility
├── polotno_image_uploader.js # Polotno image uploader
├── post_approve_job.js # post-approval workflow
├── s3_Image_upload.js # S3 upload utility
├── test.js # ad-hoc test script
├── deploy_image.py # Python deploy helper (not in this repo's runtime)
└── job_*.js # 57 background jobs (see jobs-inventory.md)
Entry point — server.js¶
const conf = require("./conf");
const express = require("express");
const bodyparser = require("body-parser");
const cors = require("cors");
const port = process.env.port || conf.port || 5002;
const app = express();
const fileUpload = require('express-fileupload');
app.use(cors());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('"Access-Control-Allow-Credentials" : true');
next();
});
app.use(fileUpload());
app.use(bodyparser.json({ limit: '50MB' }));
app.use(bodyparser.urlencoded({ extended: true }));
app.use('/favicon.ico', express.static('./favicon.ico'));
app.use('/uploads', express.static('uploads'));
var db = require('./modules/dbDriver/lib/mysql');
db.connect(conf, (res) => {
if (!res && !res.status) console.log("\n Something Went Wrong!");
});
var server = app.listen(port, ...);
const io = require('socket.io')(server);
io.on('connection', function (socket) { ... });
var App = { db, server: app, socket: socketConnection };
var { api } = require("./routes/routes");
var Api = new api(App);
Api.init();
Differences from someli-api/server.js:
- No routes/auth.js mount — auth endpoints live inside routes/routes.js
- No webhook body-parser exemption — designer-api doesn't handle payment webhooks
- No module.exports.appData = App re-export — this means dashboard/ style runtime cross-requiring (used by someli-api's dashboard module) doesn't work here. Each file connects to MySQL directly.
- Double CORS headers: both cors() middleware AND a manual res.header('Access-Control-Allow-Origin', '*'). The manual line is redundant; the "Access-Control-Allow-Credentials" : true is syntactically wrong — the entire string "Access-Control-Allow-Credentials" : true is the header name, with no value being set. The browser sees a malformed header and ignores it.
- 50 MB body limit (vs someli-api's 150 MB) — sensible for a designer tool
Route file — routes/routes.js¶
A single 13 608-line file containing:
- ~25 lines of
require()s for AWS, Polotno, OpenAI, Unsplash, mysql2, etc. - A module export at line 84:
module.exports = { api: apiRoutes, con, s3 };— exposescon(sync-mysql connection) ands3for other files to import apiRoutes.prototype.init = function() { ... }at line 91 — registers all 269 endpoints- All handlers inline; no helper extraction; no per-handler files
This pattern is the same as someli-api/routes/routes.js, just smaller.
Background workers (job_*.js)¶
57 files at the repo root, each:
require("dotenv").config()(implicit viaconf.js)require('node-cron')+cron.schedule("...", handler)new mysql(...)fromsync-mysql— a blocking DB connection per file- Optional
aws-sdkfor S3 / Bedrock - A handler function that runs SQL queries and writes back results
Each file owns its own MySQL connection. In a deploy with 57 workers running, that's 57 idle MySQL connections plus the main server's pool. Manageable but not free.
There is no PM2 ecosystem file (ecosystem.config.js) in this repo, unlike someli-api. The deploy strategy is presumably "manually pm2 start each job_*.js" or "everything goes through server.js" — see build-and-deploy.md.
Standalone bots¶
The 6 files content_generation_bot.js, post_image_generation1_bot.js, FAQsbot.js, quizbot.js, quotesbot.js, trendsbot.js are not job_*.js (no node-cron at the top). They are libraries that expose functions (getmodels, getmodelcopies, etc.) require'd by routes/routes.js to delegate AI work. Some of them also expose functions that may be called by cron jobs elsewhere.
See bots-inventory.md.
Database access¶
Three patterns coexist (same as siblings):
- Callback driver via
modules/dbDriver/lib/mysql.js(used throughApp.db) mysql2/promisepool for async/await queries (created inroutes/routes.js)sync-mysqlin everyjob_*.js,*_bot.js, andteamsnotification.js
All point at the same MySQL instance as someli-api, Someli-admin-api, and someli-dashboard-be. The shared DB is the platform's coordination mechanism — there is no message broker.
Helper layer¶
helper/index.js is 88 lines — much thinner than someli-api's helper/ directory (10+ files, thousands of lines). The bulk of business logic lives inline in routes/routes.js or in the standalone *_bot.js files. This is a maintainability concern.
Largest files¶
| File | Lines |
|---|---|
routes/routes.js |
13608 |
job_schedule_template.js |
20736 — wait, this is 20K? No — verify. From ls -la, job_schedule_template.js is 20736 bytes, not lines. (wc -l would be needed for true line counts; not all ls numbers correspond to LoC.) |
actions/actions.js |
(unknown — verify) |
For accurate line counts: find . -name "*.js" -not -path "./node_modules/*" -exec wc -l {} + | sort -rn | head -10. Deferred to verify pass.
Coding conventions¶
- CommonJS (
require/module.exports) - No TypeScript
- No linter / formatter configured
- Mix of
sync-mysqland async DB patterns - Inline handlers with no helper extraction
console.logfor observability