Skip to content

Architecture Overview

Purpose

A standalone Express + MySQL service that:

  1. Exposes 269 HTTP endpoints for the Someli-Designer Nuxt FE (template management, content library, designer tooling, AI text/image generation)
  2. Runs ~57 background workers (job_*.js) on node-cron schedules, generating template-based content per industry vertical
  3. Hosts standalone AI bots (FAQsbot.js, quizbot.js, trendsbot.js, content_generation_bot.js) that fill the content library
  4. 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 }; — exposes con (sync-mysql connection) and s3 for 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:

  1. require("dotenv").config() (implicit via conf.js)
  2. require('node-cron') + cron.schedule("...", handler)
  3. new mysql(...) from sync-mysql — a blocking DB connection per file
  4. Optional aws-sdk for S3 / Bedrock
  5. 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):

  1. Callback driver via modules/dbDriver/lib/mysql.js (used through App.db)
  2. mysql2/promise pool for async/await queries (created in routes/routes.js)
  3. sync-mysql in every job_*.js, *_bot.js, and teamsnotification.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-mysql and async DB patterns
  • Inline handlers with no helper extraction
  • console.log for observability