Skip to content

Architecture Overview

Purpose

A standalone Express + MySQL service that exposes the HTTP API for the Admin Console (admin_console_R). It is not a public-facing API; it is for Someli's internal staff (admin, customer success, account managers, developers, designers — see role taxonomy below).

The repo is a fork of the someli-api skeleton, trimmed and adapted for admin workloads. The shared lineage shows up file-by-file (see code-overlap.md).

Folder layout

Someli-admin-api/
├── conf.js                                # 49 lines — env var passthrough
├── server.js                              # 70 lines — Express boot, Socket.IO, MySQL connect, mount routes
├── methods.js                             # 16 lines — JWT Bearer-token middleware (`ensureToken`)
├── package.json                           # 78 runtime deps + 1 devDep
├── Nova-Pro_KnowledgeBased_Content.py     # batch processor for AWS Bedrock Nova
├── README.md                              # 1 line (placeholder)
├── routes/
│   ├── routes.js                          # 1400 lines — main route surface; 31 endpoints
│   └── auth.js                            # 957 lines — 9 endpoints; mounted at /auth/
├── actions/
│   └── actions.js                         # generic CRUD service layer
├── middlewares/
│   ├── auth.js                            # token-header decryption middleware
│   └── validation.js                      # express-validator chains
├── helper/                                # 10 files (see code-overlap.md for which are shared)
│   ├── aiLogics.js
│   ├── basic.js
│   ├── constants.js
│   ├── helper.js
│   ├── index.js
│   ├── ragProcess.js                      # byte-identical to someli-api's
│   ├── revokeToken.js                     # byte-identical to someli-api's
│   ├── stockImage.js
│   ├── tokenGenerator.js                  # byte-identical to someli-api's
│   └── webScraping.js                     # byte-identical to someli-api's
├── modules/
│   └── dbDriver/lib/mysql.js              # callback-style MySQL pool wrapper
└── conf/
    └── credentials.json                   # likely Google service account or similar

There are no background jobs in this repo — no job_*.js files at the root. All background work lives in someli-api (where its scheduling and PM2 setup is).

Entry point — server.js

const conf = require("./conf");
const express = require("express");
const bodyparser = require("body-parser");
const cors = require("cors");
const expressSession = require('express-session');
const port = process.env.port || conf.port || 5002;
const app = express();
const fileUpload = require('express-fileupload');

app.use(expressSession({
    secret: "3eB(2:\srlI+qa5",    // hardcoded — see security.md
    resave: false,
    saveUninitialized: true
}))

app.use(fileUpload());

app.use((req, res, next) => {
    if (req.originalUrl === '/stripe_webhooks' || req.originalUrl === '/paddle_sandbox_webhooks' || req.originalUrl === '/paddle_production_webhooks') {
      next();   // these need raw body for signature verification
    } else {
      express.json({ limit: '150mb', extended: true, parameterLimit: 50000 })(req, res, next);
    }
});

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 };
module.exports.appData = App;

app.use(cors());

const authRoute = require("./routes/auth");
app.use("/auth/", authRoute);

var { api } = require("./routes/routes");
var Api = new api(App);
Api.init();

The boot sequence mirrors someli-api/server.js almost exactly: bodyparser-ordering for webhook signature verification, the App object exported as appData, the routes/auth.js mounted at /auth/, the main routes/routes.js registered via new api(App).init().

Key drift from someli-api: this repo has no Passport setup (the imports are commented out), no routes/social.js mount, no routes/paddle.js mount, no dashboard/ mount.

Two route surfaces

File Mount Auth Endpoint count Notes
routes/auth.js /auth/* (via app.use("/auth/", authRoute)) router.use(auth) at top — every endpoint requires a decrypted token 9 High-permission admin operations (user/account delete, search across all users)
routes/routes.js (root via api.init()) Mixed — some endpoints have methods.ensureToken (Bearer JWT) per-handler, some are unauthenticated (e.g., /authenticate, /webauthenticate) 31 Login + most CRUD on personnel, roles, accounts, affiliate marketing

The two-layer auth (token-header middleware in one file, Bearer JWT in the other) is unusual. See authentication.md.

Database access

Three patterns coexist (same as someli-api):

  1. Callback-style MySQL pool via modules/dbDriver/lib/mysql.js (used through App.db)
  2. mysql2.createConnection for direct queries
  3. mysql2/promise pool for async/await queries

Plus sync-mysql is pulled in via helpers (helper/helper.js, etc.). All four DB pathways point at the same MySQL instance as someli-api / designer-api (configuration is via the same env vars — see configuration.md).

Socket.IO

Boot includes a Socket.IO server, but no handlers in this codebase consume socket events beyond the standard connect / disconnect / update echo. This is vestigial code from the someli-api fork.

Role taxonomy

Roles are integers stored in tMember.role_type. The admin FE pins the IDs in env vars (admin_console_R/src/config/env.ts):

  • SUPER_ADMIN
  • ADMIN
  • ACCOUNT_MANAGER
  • DEVELOPER
  • DESIGNER
  • (plus customer-facing roles managed elsewhere, e.g., role_type = 11 for "test users")

This API checks role on a per-endpoint basis inside handlers (e.g., routes/auth.js:127getAllOwnerList filters by role == 'test' to scope results). There is no role-based middleware; access is by SQL filter only.