Skip to content

02 — someli-api stack

What someli-api actually is, library by library.


Runtime and language

Runtime Node.js 20.18.x (production image: node:20.18.3-slim)
Module system CommonJSrequire() / module.exports. There is no TypeScript in this repo.
Process manager (production) PM2 via ecosystem.config.js
Process manager (development) nodemon (auto-restarts on file change; invoked by yarn start)
Container DockerDockerfile exists; production runs Docker + nginx fronting node

Note: no TypeScript means no compile-time type safety. The codebase relies on convention and grep. A common bug is passing fields with the wrong name (accountID vs accountId) — these only surface at runtime.


HTTP framework

Framework Express 4.x
Body parsing express.json({ limit: '150mb', parameterLimit: 50000 }) — large because the platform uploads media
File uploads express-fileupload (multipart)
Sessions express-session (used by Passport OAuth flows; secret is hardcoded — known finding)
CORS cors() with default options (wildcard origin — known finding)
WebSockets Socket.IO (legacy v2 / 4 — verify in package.json) — used for realtime UI updates

The middleware ordering in server.js is important: webhook routes (/stripe_webhooks, /paddle_*) are exempted from JSON parsing so they can verify signatures against the raw body. Do not change the order unless you understand why.


Auth

Internal auth Custom: JWT (jsonwebtoken) signed, then AES-encrypted with crypto-js. Lives in helper/tokenGenerator.js.
Token transport HTTP header named by TOKEN_HEADER_KEY env var (typically Token). Decrypted+verified in middlewares/auth.js.
Identity propagation Middleware sets res.userId, res.accountId, res.role, res.isPersonnel (yes, on res, not req — read ../../audit/someli-api/authentication.md before being surprised).
OAuth Passport.js in middlewares/passport.js. Strategies: Google, GitHub, Facebook, LinkedIn, TikTok, Twitter v2.
Sessions Used only for the Passport OAuth handshake; not for the regular API.
Token revocation In-memory map in helper/revokeToken.js. Clears on process restart → tokens are effectively long-lived.
Partner API auth A different JWT in routes/partnerAuth.js (custom signing/verification).

Junior gotcha: when reading a route handler, you'll often see code like const { userId, accountId } = res;. That destructures from res, which is unusual. Don't "fix" it — auth middleware writes there, and rewriting it touches the whole codebase.


Database

Engine MySQL (one shared instance across all four backends in production)
Schema Reference snapshot at ../../audit/someli-api/someli-schema.sql
Migrations None. Schema changes are applied to dev / UAT / prod manually.

Three coexisting MySQL access patterns

Library Style Where it's used
mysql Async (callbacks) modules/dbDriver/lib/mysql.jsactions/actions.js (pool via App.db)
sync-mysql Synchronous / blocking routes/routes.js (con), routes/auth.js (con), most job_*.js files
mysql2/promise Async (promises) newer job files, dashboard services

Junior gotcha: sync-mysql blocks the entire event loop on every query. It's used pervasively. Don't be surprised when you see const rows = con.query(...) with no await. Do not introduce new sync-mysql usage; prefer mysql2/promise for any new code.

CRUD layer

actions/actions.js exposes a generic, table-agnostic CRUD:

actions.getAll(tableName, conditions, fields, limit, offset)
actions.insertData(tableName, fields)
actions.updateData(tableName, fields, conditions)
actions.deleteData(tableName, conditions)
actions.customQuery(rawSQL)

Most route handlers and all background jobs bypass this layer and run direct SQL via con.query(...). The CRUD helper is convenient but not universally used.


AI providers

Provider Purpose Where
AWS Bedrock Claude / Llama / Nova for text generation helper/aiLogics.js
Google Vertex / Gemini RAG retrieval and Gemini text helper/ragProcess.js, agents
OpenAI image and text generation scattered in routes and jobs
Polotno SDK (polotno-node) server-side image rendering image generation jobs

The RAG pipeline uses Google Cloud RAG (Vertex) with a corpus per account — see ../../audit/someli-api/rag-pipeline.md.

The agents (agents/conversationAgent.js, researchAgent.js, profileAgent.js, inputParserAgent.js) wrap multi-step LLM workflows — see ../../audit/someli-api/agents-and-ai.md.


Background workers

Pattern Standalone job_*.js files at the repo root
Scheduling PM2 + node-cron inside the script
Process manifest ecosystem.config.js
Number of jobs ~108
Brokers / queues None — jobs poll the DB directly

Each job file is self-contained: requires dotenv (via conf.js), opens its own MySQL connection (typically sync-mysql), registers a cron.schedule(...), and runs.

Consequence: 108 jobs × 1 MySQL connection each = 108 idle DB connections plus the main server pool. Stays manageable in prod, but be aware.

See ../../audit/someli-api/jobs-inventory.md for the full list.


External integrations

Service Used for Library
AWS S3 Media + template storage (two buckets, two regions) aws-sdk
SendGrid Transactional email @sendgrid/mail
Paddle Billing (sandbox + prod) Paddle REST API
Stripe Legacy billing stripe
Facebook / Instagram Publishing + OAuth passport-facebook, FB Graph API
LinkedIn Publishing + OAuth passport-linkedin-oauth2
TikTok Publishing + OAuth TikTok API direct
X / Twitter v2 Publishing + OAuth Twitter v2 API direct
Slack Internal notifications Slack Web API
Google Cloud RAG Knowledge-base retrieval Google Cloud SDK
Polotno (cloud + node) Image rendering polotno-node, Polotno Cloud REST
Impact (affiliate) Affiliate tracking direct REST

The full integration inventory: ../../audit/someli-api/Integration-inventory.md.


Logging and observability

Logger console.log (no structured logger)
Format Plain string
Sinks stdout → PM2 log files in production
Error tracking None (no Sentry / Rollbar / etc.)
Healthchecks GET /health, GET /db-health
Tracing None

Junior gotcha: there is no central logger. Logs are ad-hoc console.logs scattered throughout the codebase. This means: (1) PII can be logged inadvertently (a known finding); (2) you cannot adjust log levels without code edits. Don't add console.log of user data when debugging.

See ../../audit/someli-api/logging-observability.md.


Build, test, deploy

Build None — Node runs source directly
Lint No ESLint configured
Tests No test suite. package.json's test script just exit 1.
CI Jenkins (operational) + GitHub Actions (.github/workflows/dev-api-deploy.yml)
Deploy Jenkins SSH-deploys to AWS Lightsail; pulls the branch, builds, restarts PM2
Branches dev_api (dev), uat_api (uat), main (prod)

Consequence for you: if you change a function in helper/helper.js, nothing automated will catch a regression. You must manually exercise the code paths that use it. There is no safety net.


Next

03-architecture.md — folder map, entry point, request lifecycle.