Skip to content

03 — Someli-admin-api architecture

A guided tour.


Folder map

Someli-admin-api/
├── conf.js                            ← 49 lines — env-var passthrough
├── server.js                          ← 70 lines — Express boot, MySQL, mount routes
├── methods.js                         ← 16 lines — `ensureToken` Bearer-JWT middleware
├── package.json                       ← 78 runtime deps + 1 devDep
├── Nova-Pro_KnowledgeBased_Content.py ← batch processor for AWS Bedrock Nova (Python, separate runtime)
├── README.md                          ← 1 line placeholder
├── routes/
│   ├── routes.js                      ← 1400 lines — 31 endpoints; class-based pattern
│   └── auth.js                        ← 957 lines — 9 endpoints; Express Router, auth-gated
├── actions/
│   └── actions.js                     ← generic CRUD service layer
├── middlewares/
│   ├── auth.js                        ← token-header decryption (encrypted Bearer pattern)
│   └── validation.js                  ← express-validator chains
├── helper/                            ← 10 files (see 02-stack.md for what's byte-identical vs drifted)
│   ├── aiLogics.js
│   ├── basic.js
│   ├── constants.js
│   ├── helper.js
│   ├── index.js
│   ├── ragProcess.js                  ← byte-identical to someli-api/
│   ├── revokeToken.js                 ← byte-identical
│   ├── stockImage.js
│   ├── tokenGenerator.js              ← byte-identical
│   └── webScraping.js                 ← byte-identical
├── modules/
│   └── dbDriver/lib/mysql.js          ← callback-style MySQL pool wrapper
└── conf/
    └── credentials.json               ← likely Google service-account JSON

Entry point — server.js

70 lines. Reads almost like someli-api/server.js with three differences (Passport / Paddle / dashboard absent).

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 — known finding
    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 would need raw body for signature verification — but no handlers exist
    } 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;        // re-exported (same as someli-api)

app.use(cors());

const authRoute = require("./routes/auth");
app.use("/auth/", authRoute);                    // Mount A: Express Router

var { api } = require("./routes/routes");
var Api = new api(App);
Api.init();                                      // Mount B: class-based, on App.server

Differences from someli-api/server.js

  • No routes/social.js mount (no OAuth)
  • No routes/paddle.js mount (Paddle is hardcoded inside routes/routes.js, not as a separate router)
  • No routes/partnerAuth.js mount
  • No dashboard/routes/index.js mount
  • Passport imports are commented out
  • Webhook exemption paths exist but no handlers for them in routes/routes.js

Two route surfaces

File Mount Auth pattern Endpoints 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, cross-user search
routes/routes.js root, via api.init() registering on App.server Mixed — some endpoints use methods.ensureToken per-handler, some are unauthenticated (/authenticate, /webauthenticate) 31 Login + most CRUD on personnel, roles, accounts, affiliate marketing

The two-layer auth is a real source of confusion. When adding a new endpoint, decide upfront: encrypted-Bearer route (goes in routes/auth.js) or plain JWT (goes in routes/routes.js with methods.ensureToken). The two are not interchangeable.


Request lifecycle

For a /auth/* request:

HTTP request
Express middleware (session → fileupload → bodyparser → cors)
app.use("/auth/", authRoute)
router.use(auth)  ← middlewares/auth.js — token-header decryption
handler (sets res.userId, res.accountId from decrypted token)

For a root-mounted request (routes/routes.js):

HTTP request
Express middleware
api.init() registers each path on App.server
handler  (with optional methods.ensureToken Bearer-JWT check inline)

Validation

middlewares/validation.js exposes express-validator chains. Use them on routes that accept request body:

const { check, validationResult } = require('express-validator');
const { validateRequest } = require('../middlewares/validation');

router.post('/createPersonnel',
  [check('email').isEmail(), check('role').isInt()],
  validateRequest,
  async (req, res) => { ... }
);

This is rare in someli-api (validation is inline / absent) but present in Someli-admin-api. Use it for new endpoints.


The Python file

Nova-Pro_KnowledgeBased_Content.py is a one-off Python batch processor for AWS Bedrock Nova. It is not invoked from Node — runs separately. If you need to use or modify it, you need a Python environment with the Bedrock SDK.

Don't try to integrate it into the Node runtime. Either rewrite the logic in Node or invoke it as a subprocess if needed.


Code-overlap caveats (the most important section)

Every change to a helper/*.js file needs you to check whether the same file exists (byte-identical or drifted) in:

  • someli-api/helper/
  • designer-api/helper/ (helper/index.js only)

See the summary table in 02-stack.md and the full matrix in ../../audit/CODE-OVERLAP-MATRIX.md.

Byte-identical helpers (tokenGenerator.js, revokeToken.js, ragProcess.js, webScraping.js) must be kept in sync between someli-api and Someli-admin-api. A PR that updates one without the other will produce drift you don't want.


Where to put a new file

Adding Put it in
A new authenticated admin endpoint routes/auth.js (Express Router; encrypted Bearer auth)
A new admin endpoint that should use plain JWT routes/routes.js (class-based; add methods.ensureToken to the handler)
A new unauthenticated endpoint routes/routes.js (no auth middleware in the handler)
A new helper function An existing helper/*.js file if it fits topically, OR a new helper/<name>.js. Check whether the same helper exists in someli-api/helper/.
A new validator chain Extend middlewares/validation.js
A new Paddle webhook handler Add the handler to routes/routes.js; the server.js exemption already covers the path

Next

04-getting-started.md.