03 — designer-api architecture¶
A guided tour of the folder structure, the entry point, and how a request flows.
Folder map¶
designer-api/
├── conf.js ← 27 lines — env var passthrough (smaller than someli-api's)
├── server.js ← 70 lines — Express boot, MySQL connect, mount routes
├── package.json ← 30 runtime deps, 0 dev deps
├── Dockerfile ← multi-stage; runs nginx + node behind it
├── .dockerignore
├── nginx.conf
├── push.sh ← manual SSH-deploy helper
├── favicon.ico
│
├── routes/
│ └── routes.js ← 13608 lines, 269 endpoints, one Api class
│
├── actions/
│ └── actions.js ← generic CRUD (older fork of someli-api's)
│
├── 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
│
├── conf/
│ └── credentials.json ← likely Google service-account JSON
│
├── content_generation_bot.js ← standalone AI worker (OpenAI)
├── post_image_generation1_bot.js
├── FAQsbot.js
├── quizbot.js
├── quotesbot.js
├── trendsbot.js
├── teamsnotification.js ← Slack notifier on missing content
├── generateTextContent.js
├── pdfToExtractData.js
├── polotno_image_uploader.js
├── post_approve_job.js
├── s3_Image_upload.js
├── test.js ← ad-hoc test script
├── deploy_image.py ← Python helper (not part of runtime)
│
└── job_*.js ← ~57 background workers
├── 30+ industry-clones (job_auto_garge_*, job_disability_insurance, …)
└── several misc workers
Entry point — server.js¶
The boot sequence (70 lines):
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()); // 1. CORS middleware
app.use((req, res, next) => { // 2. Manual CORS header (redundant)
res.header('Access-Control-Allow-Origin', '*');
res.header('"Access-Control-Allow-Credentials" : true'); // BUG — this string is the header NAME
next();
});
app.use(fileUpload()); // 3. File upload
app.use(bodyparser.json({ limit: '50MB' })); // 4. JSON parsing
app.use(bodyparser.urlencoded({ extended: true })); // 5. URL-encoded forms
app.use('/favicon.ico', express.static('./favicon.ico')); // 6. Static
app.use('/uploads', express.static('uploads'));
var db = require('./modules/dbDriver/lib/mysql'); // 7. MySQL pool
db.connect(conf, (res) => {
if (!res && !res.status) console.log("\n Something Went Wrong!");
});
var server = app.listen(port, ...); // 8. Listen
const io = require('socket.io')(server); // 9. Socket.IO
io.on('connection', function (socket) { ... });
var App = { db, server: app, socket: socketConnection }; // 10. Shared App
var { api } = require("./routes/routes"); // 11. Mount routes
var Api = new api(App);
Api.init();
Differences from someli-api/server.js (very important)¶
- No
routes/auth.jsmount. Auth endpoints are insideroutes/routes.js. - No webhook body-parser exemption. No Paddle / Stripe handlers.
- No
module.exports.appData = App.dashboard/-style runtime cross-requires don't work here. Each file connects to MySQL directly. - Double CORS headers. The
cors()middleware AND a manualres.header(...). The manual line's second header is malformed (the entire"Access-Control-Allow-Credentials" : truestring is the header name with no value). - 50 MB body limit (vs
someli-api's 150 MB). - No
/health, no/db-healthendpoints.
Route file — routes/routes.js¶
A single 13608-line file containing:
- ~25 lines of
require()s (AWS, Polotno, OpenAI, Unsplash,mysql2, …) - Module export at line 84:
module.exports = { api: apiRoutes, con, s3 }— exposescon(sync-mysql) ands3for other files apiRoutes.prototype.init = function() { ... }at line 91 — registers all 269 endpoints inline- All handlers inline; no per-file extraction
// Typical endpoint (illustrative)
App.server.post('/myEndpoint', async (req, res) => {
// ... auth check (hand-rolled, not Passport / not Bearer JWT) ...
const rows = con.query("SELECT ... FROM ... WHERE ?", [req.body.id]);
res.json({ status: 200, data: rows });
});
Junior gotcha: everything is in this one file. When you grep, expect noisy results. Use line numbers from the audit's
../../audit/designer-api/API-inventory.mdto navigate.
Request lifecycle¶
HTTP request
│
▼
nginx (production) or Express directly (dev)
│
▼
[middleware: CORS → fileupload → bodyparser → static]
│
▼
routes/routes.js handler (matched by path)
│
▼
hand-rolled auth check (looks at request header, validates)
│
▼
SQL query (sync-mysql `con.query(...)` is the common pattern)
│
▼
JSON response
No Passport, no JWT, no AES decryption. Auth is much simpler than someli-api.
Background workers¶
Each job_*.js is independent:
// Typical job file
require('dotenv').config();
const cron = require('node-cron');
const mysql = require('sync-mysql');
const con = new mysql({ host, user, password, database });
cron.schedule("0 */2 * * *", async () => {
// every 2 hours, do something
const rows = con.query("SELECT ...");
for (const row of rows) {
// OpenAI call, S3 upload, etc.
}
});
Industry-clone pattern¶
30+ of these files are near-duplicates. Example shape (illustrative):
// job_auto_garge_post_generation.js
const INDUSTRY_ID = 42; // hardcoded
// ... otherwise identical to job_disability_insurance_post_generation.js (INDUSTRY_ID = 17)
This is a known refactor target. See ../../audit/designer-api/jobs-inventory.md.
Bots vs jobs¶
- Jobs (
job_*.js) follow thenode-cronpattern: schedule + handler. - Bots (
FAQsbot.js,quizbot.js, etc.) are standalone runnable processes that interact with OpenAI in larger batches. Some are scheduled, some run on demand.
Connection count¶
57 jobs × 1 MySQL connection each + 6 bots × ~1 each + the main server pool = ~70 idle MySQL connections. Within limits but not free.
Helpers¶
helper/index.js is 88 lines — much smaller than someli-api/helper/. Contains:
- Auth-token helpers
- A few utility functions
There is no helper/helper.js, no helper/aiLogics.js, no helper/constants.js etc. — the patterns from someli-api were not copied across.
Consequence: when you need a utility, don't assume it exists here. Either it's in
helper/index.js, inlined inroutes/routes.js, or simply absent.
Notifications — teamsnotification.js¶
A standalone Slack / Teams notifier scheduled to ping a channel when content is missing.
// teamsnotification.js (illustrative — actual values are different but hardcoded)
const token = 'xoxb-...'; // HARDCODED Slack bot token (known finding)
const channel = 'C...';
Don't add new hardcoded credentials. Use env vars. The existing hardcoded ones are flagged for cleanup.
Code-overlap with someli-api¶
| File | Status |
|---|---|
routes/routes.js |
Same skeleton, completely different content |
actions/actions.js |
Old fork of someli-api/actions/actions.js; drifted |
helper/index.js |
Drifted; different content from someli-api/helper/index.js |
modules/dbDriver/lib/mysql.js |
Drifted from someli-api's version |
Zero filename overlap between someli-api/job_*.js and designer-api/job_*.js. The job inventories are completely disjoint. See ../../audit/CODE-OVERLAP-MATRIX.md.
Where to put a new file¶
| Adding | Put it in |
|---|---|
| A new REST endpoint | routes/routes.js (the only routes file) inside apiRoutes.prototype.init() |
| A new background job | New file job_<name>.js at repo root + tell ops how to add it to PM2 |
| A new bot | New file <name>bot.js at repo root |
| A new helper function | helper/index.js (or a new file helper/<topic>.js and require it) |
| A new notification target | Extend teamsnotification.js or create a new module — use env vars, never hardcode |