Skip to content

Someli Platform — Architecture Findings

Audit date: 2026-05-17. Scope: cross-repo architecture, module organization, interdependencies, anti-patterns, and code smells. Lens deliberately differs from code-inspect/ — that tree catalogs concrete bugs; this document focuses on the shape of the codebase and the design pressures behind those bugs.

This document follows the methodology of _meta/AUDIT_GUIDE.md — cite sources for every claim, mark uncertainty as [VERIFY], and number findings for downstream traceability. Cross-reference per-repo architecture-overview.md files for component-level detail.


0. How to read this document

Section What you'll find
§1 Topology The two physical tiers (backend forks, frontend stacks) and how they connect at runtime
§2 Backend skeleton The single shared Express skeleton, where it lives, and where it has drifted
§3 Module organization (per repo) What's in each repo's top-level directories, and where the layering breaks
§4 Interdependency graph The five connectors that hold the platform together (DB, helpers, header, S3, Polotno)
§5 Architectural anti-patterns Six recurring shapes that cause the bugs in code-inspect/
§6 Code smells (cross-repo) Smaller-but-systemic issues observed in multiple repos
§7 Per-repo summary table One-row-per-repo cheat sheet
§8 Roadmap implications What an architecture-led cleanup would prioritize

Throughout: file paths are relative to someli-gh/. Line numbers are pinned to the audit-time commit and will drift.


1. Platform topology

1.1 Physical components

The platform is six runtime services + two SPA frontends + one React admin app, all backed by one shared MySQL instance (CODE-OVERLAP-MATRIX.md §1, PLATFORM-OVERVIEW.md §6.1):

                     ┌──────────────────────────────────────────┐
   Customers ────▶   │  someli-platform (Nuxt 2 SPA)            │
                     │   ↓ /auth/* via base64(apptype) header   │
                     │  someli-api (Express + ~108 PM2 jobs)    │
                     └──────────────────────────────────────────┘
                     ┌──────────────────────────────────────────┐
   Internal staff ──▶│  Someli-Designer (Nuxt 2 SPA + Polotno)  │
                     │   ↓ /auth/* via base64(apptype) header   │
                     │  designer-api (Express + ~57 PM2 jobs)   │
                     └──────────────────────────────────────────┘
                     ┌──────────────────────────────────────────┐
   Admin staff ────▶ │  admin_console_R (Vite + React + TS)     │
                     │   ↓ /auth/* via Bearer token             │
                     │  Someli-admin-api (Express, 0 jobs)      │
                     └──────────────────────────────────────────┘

                   ┌──────────────────────────────────────┐
                   │   one MySQL instance — shared by all │
                   │   four backends. No message broker.  │
                   └──────────────────────────────────────┘

A1. Database is the message broker. All four backends and their jobs poll the same MySQL tables (tJobs, tContentPlanner, tIndustries, tCategories, …). There is no queue/topic, no event bus, and no API contract between services — coordination is via shared rows (CODE-OVERLAP-MATRIX.md §5, designer-api/architecture-overview.md "shared MySQL instance"). Effects:

  • Adding a new producer (designer-api job) and a new consumer (someli-api job) is a code change in two repos with no schema contract enforcement.
  • Polling intervals are hardcoded cron.schedule("*/5 * * * *", ...) (e.g., designer-api/job_It_cyber_security.js:14) — under-load behavior depends on cron tick density across ~165 PM2 processes hitting the same DB.
  • Schema migrations are manual and cross-cutting; the only versioning is the live MySQL instance itself (an audit-time snapshot was captured at someli-api/someli-schema.sql under this audit tree — it is not part of any source repo).

1.2 Stack heterogeneity

Tier Stack Repos
Frontends (legacy) Nuxt 2.18 / Vue 2.7 SPA (ssr: false), Vuex, BootstrapVue someli-platform, Someli-Designer
Frontend (modern) Vite 5 / React 18 / TS 5 / shadcn/ui / TanStack Query admin_console_R
Backends Express 4 + CommonJS, no TS, MySQL via three coexisting drivers someli-api, designer-api, Someli-admin-api, someli-dashboard-be
Editor (embedded) React 18 + MobX-State-Tree + Polotno (Parcel bundle) someli-platform/polotno-editor/, Someli-Designer/polotno-editor/

A2. Two parallel frontend stacks with no shared component layer. The modern admin (admin_console_R) and the legacy customer/designer apps share zero UI primitives. Vue 2 reached EOL Dec 2023 (someli-platform/package.json pins vue: 2.7.16, nuxt: 2.18.1; same in Someli-Designer/package.json) — both legacy apps are unpatched against future security advisories. Migration cannot be incremental because nothing is shared.


2. The backend skeleton

2.1 One skeleton, three forks

Every backend except someli-dashboard-be (a trimmed extraction) follows the same shape:

<repo>/
├── conf.js                       # re-exports process.env
├── server.js                     # boot Express + Socket.IO + MySQL, then mount routes
├── modules/dbDriver/lib/mysql.js # callback-based MySQL pool wrapper
├── actions/actions.js            # generic CRUD (getAll, insertData, updateData, ...)
├── routes/routes.js              # ONE giant file with all endpoints
├── helper/                       # flat folder of utility modules
└── job_*.js                      # standalone PM2-runnable scripts (someli-api, designer-api only)

This skeleton was copy-pasted twice — first from someli-api to designer-api, then again to Someli-admin-api. The three forks have drifted independently. See CODE-OVERLAP-MATRIX.md §2 for the file-by-file delta in helper/.

2.2 Concrete drift measurements

Concern someli-api designer-api Someli-admin-api
server.js LoC 217 65 81
routes/routes.js LoC 21 631 13 608 1 400
routes/auth.js LoC 24 432 (none — auth in routes.js) 957
actions/actions.js LoC 302 291 301
helper/ file count 18 (+ functionsForAi/) 1 10
Route count 393 (routes.js) + 291 (auth.js) + 17 elsewhere 269 31 + 9
Standalone job_*.js count 108 57 0
PM2 apps registered in ecosystem.config.js 39 (no file) (no file)

Source: find -name '*.js' -exec wc -l +, grep -cE 'router\.(get\|post\|put\|delete)'. designer-api and Someli-admin-api have no in-repo PM2 manifest — see §5.5.

A3. routes/routes.js is the platform's largest unit of code by an order of magnitude. At 21 631 / 13 608 / 1 400 lines, this single file in each backend holds the bulk of business logic. By comparison, the entire admin_console_R TypeScript surface is 12 536 lines.

A4. helper/ is the layer-of-last-resort, not a designed module. someli-api/helper/ is a flat folder of 18 files; Someli-admin-api/helper/ mirrors 10 of those names with varying drift (4 byte-identical, 6 diverged by hundreds of lines — CODE-OVERLAP-MATRIX.md §2); designer-api/helper/ shrank to a single index.js (88 lines, per designer-api/architecture-overview.md). The natural consequence: when designer-api needs an AI prompt builder or a token generator, it's pasted inline into routes/routes.js instead of imported from a helper.


3. Module organization (per repo)

3.1 Backend modules — what's where, and what's missing

someli-api

routes/
  routes.js     21 631 LoC, 393 endpoints — main API (class-based pattern, raw Express app)
  auth.js       24 432 LoC, 291 endpoints — authenticated routes (Express Router + router.use(auth))
  social.js        429 LoC,  15 endpoints — OAuth callbacks (Passport)
  paddle.js        ~150 LoC,  2 endpoints — billing webhooks
  partnerAuth.js   ~150 LoC,  4 endpoints — partner API (custom JWT)
dashboard/
  routes/index.js  2 590 LoC, 22 endpoints — analytics, re-imports server.js + routes.js at runtime
actions/actions.js   302 LoC — generic CRUD
helper/              18 files + functionsForAi/ subdirectory
middlewares/         auth.js, passport.js, validation.js
modules/dbDriver/    callback-style MySQL pool wrapper
job_*.js root        108 files (only 39 enrolled in ecosystem.config.js)
agents/              AI agents (conversationAgent, researchAgent, profileAgent, inputParserAgent)

Observations:

  • No controllers/ layer. Route handlers contain the full business logic inline. The actions/actions.js CRUD service exists but is bypassed in many handlers in favour of direct con.query(...) (raw sync-mysql) calls — see §5.3.
  • No models/ or schema layer. SQL is hand-written per call-site. Schema knowledge is implicit; the only centralized reference is the audit-tree snapshot at someli-api/someli-schema.sql — and that file is documentation-only, not committed to any of the source repos.
  • agents/ directory exists in someli-api only — AI orchestration code is not shared with the two other backends that also need it. designer-api and Someli-admin-api have copy-pasted helper/aiLogics.js instead. (CODE-OVERLAP-MATRIX.md §2 shows aiLogics.js differs by 396 lines between someli-api and Someli-admin-api).
  • dashboard/routes/index.js:17-19 reaches back into the parent app at runtime:
    ({ appData } = require("../../server"));
    ({ con } = require("../../routes/routes"));
    ({ checkuseraccount, getImageFromS3 } = require("../../helper/helper"));
    
    This is the only cross-module re-entry in the repo and it is the reason routes/routes.js exports con and server.js exports appData. See someli-api/architecture-overview.md §"Standard Response Format" and §5.6 below.

designer-api

routes/routes.js     13 608 LoC, 269 endpoints — single file
actions/actions.js      291 LoC — older fork of someli-api's
helper/index.js          88 LoC — solo file (no helper.js, no aiLogics.js, no constants.js)
modules/dbDriver/        221 LoC — nearly identical to Someli-admin-api's (4-line diff); someli-api's is 322 LoC and ~217 lines diverged
job_*.js root            57 files
*_bot.js root            6 files (content_generation_bot, FAQsbot, quizbot, quotesbot, trendsbot, post_image_generation1_bot)
teamsnotification.js     ad-hoc Slack notifier

No middlewares/ directory. No auth middleware module exists. routes/routes.js registers /webauthenticate (line 171), /me (line 255), and then a sequence of commonDelete / commonPagecount / commonIsDeleted / checkPasswordResetToken (lines 303-431) endpoints without any route-level auth guard (see §5.1).

No ecosystem.config.js. The 57 job_*.js files + 6 *_bot.js files have no in-repo PM2 manifest, despite needing to be supervised processes. Deploy strategy is external to the repo (designer-api/architecture-overview.md §"Background workers" — "presumably 'manually pm2 start each job_*.js'").

Someli-admin-api

routes/
  routes.js    1 400 LoC, 31 endpoints — login + CRUD (mixed auth: per-handler ensureToken)
  auth.js        957 LoC,  9 endpoints — admin operations (router.use(auth) global guard)
actions/actions.js   301 LoC
helper/              10 files — many identical or near-identical to someli-api/helper/ ([§2 of CODE-OVERLAP-MATRIX.md](./CODE-OVERLAP-MATRIX.md))
middlewares/         auth.js, validation.js
modules/dbDriver/    callback-style MySQL pool

No job_*.js files — all background work is in someli-api. One off-pattern Python file: Nova-Pro_KnowledgeBased_Content.py at the repo root (not part of the runtime; appears to be a batch utility for Bedrock Nova). Mention is in Someli-admin-api/architecture-overview.md.

someli-dashboard-be

A trimmed copy of someli-api/dashboard/ plus a mock/ directory used when NODE_ENV === 'development' (CODE-OVERLAP-MATRIX.md §7). Files: conf.js, server.js (15 LoC), routes/index.js, services/job_account_insights.js, services/job_growth_insights.js, services/job_post_insights.js, plus mock/. Drifted from the in-process copy in someli-api/dashboard/: production runs the in-process copy; the standalone exists for local dev. Split-brain risk is real and called out in PLATFORM-OVERVIEW.md §6.6.

3.2 Frontend modules — what's where

someli-platform (Nuxt 2, customer-facing)

15 top-level directories, including a healthy layering:

pages/             84 files, mostly under pages/_accid/* (dynamic account-id segment)
components/        160 .vue files, grouped (Calender/, Charts/, Dashboard/, Sidebars/, Cards/, …)
layouts/           default.vue, error.vue, onBoard.vue, someliNetwork.vue, specialOffer.vue, fourOhOne.vue
store/             Vuex 3, ~10 feature-scoped modules + store/api.js (5-minute TTL caching layer) + store/index.js
middleware/        router middleware: redirect, axios, validUrl, appendUTM, appendUrl
api/               serverMiddleware (Express helpers, OAuth callbacks — mostly commented out per [someli-platform/02-architecture.md](./someli-platform/02-architecture.md))
plugins/           auth, gtm, snowfall, polotno-related, …
helpers/           helper.js (~164 LoC), circleNetworkHelper.js, mixins/, models/
constants/         PROVIDER, PLAN, PATH, INVALID_RESPONSE
data/              sitemap.js, stgmap.js
mixins/            onboardingNavigation.js
services/          circleNetworkService.js
assets/, static/   processed vs verbatim assets
polotno-editor/    independent React 18 + MobX subproject (Parcel build)

Strengths: the store is feature-scoped (chat/, dashboard/, post/, plan/, reach/, common/), and the dedicated store/api.js (516 LoC) acts as a true API client with built-in caching (someli-platform/05-state-management.md). Middleware composition is explicit and ordered.

Smells: - Pages over 5 000 LoC: pages/userSetting/index.vue (10 795), pages/_accid/userSetting/index.vue (9 781), pages/_accid/my_library/index.vue (5 506), pages/_accid/contentplanner/index.vue (4 957) — see §6.1. - Duplicated route trees: pages/userSetting/ and pages/_accid/userSetting/ both exist (10 795 vs 9 781 lines); same for my_library, contentplanner. The route rewriter middleware/appendUrl.js is supposed to normalize bare URLs into /<accountId>/... (someli-platform/04-routing.md), but both copies are maintained. - Static bootstrap.bundle.js (7 013 LoC) and owl.carousel.min.js (3 447 LoC) are checked into both assets/js/ and static/ — duplicated bundled libs in the repo.

Someli-Designer (Nuxt 2, internal designer tool)

pages/             73 files, FLAT (no subdirectories)
components/        4 files only (Navbar, Notification, skeletonCard, ToasterProgress)
layouts/           default.vue, blank.vue
store/index.js     SINGLE Vuex module — no sub-modules, no caching layer
middleware/        axios.js, guest.js (no auth.js!)
plugins/           customCommon.js, common.js, hotjar.js
polotno-editor/    React 18 + MobX subproject (DIVERGED from someli-platform's copy)

A5. The designer FE is structurally weaker than the customer FE despite handling similar workflows. All audited dimensions are worse:

Dimension someli-platform Someli-Designer
Components extracted 160 4
Vuex modularization 10 feature modules single module
API caching store/api.js 5-min TTL none
Page-folder organization grouped under pages/_accid/... flat 73-file pages/
Largest page 10 795 LoC (pages/userSetting/index.vue) 4 904 LoC (pages/carousaltemplates.vue) — relatively smaller, but with only 4 components and no helpers, business logic still lives in pages

The result is that each Someli-Designer page owns most of its logic inline (since components/ is nearly empty). The flat 73-file pages/ includes obvious chaff (pages/dynamicPost - Copy.vue — a literal Ctrl-C/Ctrl-V snapshot). See Someli-Designer/architecture-overview.md.

admin_console_R (Vite + React + TS, admin)

src/
  App.tsx           router + global providers (QueryClientProvider, AuthProvider, TooltipProvider, Toaster)
  main.tsx          React 18 createRoot
  components/
    auth/           LoginForm, ProtectedRoute
    layout/         AppLayout, Sidebar
    shared/         small reusable bits
    ui/             50 shadcn primitives (Radix wrappers)
  config/env.ts     typed env accessor
  context/AuthContext.tsx  user/token state
  hooks/            useAuth, use-mobile, use-toast
  lib/              cn() utility etc.
  pages/            10 pages (Accounts, AffiliateMarketing, CustomerService, Index, Login, MyProfile, NotFound, Personnel, Prompts)
  services/api.ts   184 LoC — fetch wrapper + ~25 named API methods

The healthiest layout in the platform. Routes are explicit (ProtectedRoute → AppLayout → <Page />), state is in TanStack Query for server state and AuthContext for session, the design system is shadcn/ui. Largest page is Accounts.tsx (2 055 LoC) — still high, but on an order-of-magnitude better than the Nuxt FEs.

3.3 The polyglot anomaly

Repo Languages
admin_console_R TypeScript only (76 .ts/.tsx files)
someli-platform, Someli-Designer JavaScript + Vue SFC — 0 .ts/.tsx files
All backends JavaScript only (no .ts)
Someli-admin-api JavaScript + 1 Python file (Nova-Pro_KnowledgeBased_Content.py)
designer-api JavaScript + 1 Python helper (deploy_image.py)

A6. TypeScript adoption is single-component, not platform-wide. A migration plan for the two Nuxt FEs to TS does not exist. The Python utilities are deploy/batch tools that have not been ported into the Node.js runtime — they likely run by hand on a workstation.


4. Interdependency graph

The repos look standalone, but five connectors weave them tightly:

4.1 Shared MySQL schema

All four backends configure connection from the same env-var set (host, user, password, database, dbPort — see someli-api/conf.js:5-9, designer-api/conf.js:4-8, Someli-admin-api/conf.js:5-9). In production, all four point at the same instance (PLATFORM-OVERVIEW.md §6.1, designer-api/architecture-overview.md "All point at the same MySQL instance").

Tables crossed by multiple backends include tMember, tAccount, tContentPlanner, tLibrary, tCategories, tIndustries, tTempalte_Status, tStripe_webhooks, tPaddleWebhook — see data-model.md and the audit-tree schema snapshot at someli-schema.sql.

4.2 The helper/ copy-paste lineage

Per CODE-OVERLAP-MATRIX.md §2, Someli-admin-api/helper/ shares 10 filenames with someli-api/helper/. Four are byte-identical (tokenGenerator.js, revokeToken.js, ragProcess.js, webScraping.js); six are forked with 49 to 856 lines of drift. designer-api/helper/index.js is a separate, much-smaller fork that uses none of the byte-identical helpers.

Implication for cross-cutting bugs: a fix to tokenGenerator.js (e.g., adding token expiry) must be applied to two repos with the same patch and to designer-api with a re-port from the inlined version. A fix to aiLogics.js cannot be propagated mechanically — the 396-line drift means a manual reconciliation is required (CODE-OVERLAP-MATRIX.md §2).

4.3 The apptype header convention

All three frontends send a base64-encoded Apptype header on every backend call so the receiving backend can distinguish callers (PLATFORM-OVERVIEW.md §6.3, Someli-Designer/middleware/axios.js, someli-platform/middleware/axios.js). Some endpoints branch on Apptype. This is the platform's soft service-discovery layer — it has no schema, no documentation, and the magic strings are duplicated across all three FEs and all three BEs.

4.4 S3 bucket sharing

All four backends accept S3_Bucket_Name, S3_Bucket_Name2, S3_Region, S3_Region2 env vars (someli-api/conf.js:15-22, designer-api/conf.js:15-19). Designer-generated assets land in the same buckets as customer assets. This means a buggy designer job can overwrite a customer asset — there is no logical separation at the storage layer.

4.5 The Polotno bundle

Both someli-platform and Someli-Designer consume an editor built from polotno-editor/ subprojects via polotno-bundle.js at the repo root. The two subprojects are diverged (CODE-OVERLAP-MATRIX.md §6) — files have been renamed (brandkitpanel.js vs brandkitPanel.js), entirely new panels exist in one but not the other, and the customer copy is ~221 KB while the designer copy is ~50 KB. Treating these as one project is incorrect; treating them as fully independent forgoes the obvious shared base.

4.6 The dashboard re-entry hack

someli-api/dashboard/routes/index.js:17-19 requires back into someli-api/server.js and someli-api/routes/routes.js at runtime, pulling appData and con out of those modules:

({ appData } = require("../../server"));
({ con } = require("../../routes/routes"));

This is the only place in someli-api where a sub-module re-enters the host. It's the reason routes.js exports con (line 21 631 of the file: module.exports = { api: apiRoutes, con }) and server.js exports appData. A clean modularization would invert this — dashboard/ should receive its db and appData via constructor, not require-cycle. Currently it cannot be extracted without rewriting this contract.


5. Architectural anti-patterns

A1. Routes registered on the raw Express app — auth middleware unattachable

Where: someli-api/routes/routes.js:240 var router = self.app; (re-assigned again at lines 20 749, 20 797, 21 014); designer-api/routes/routes.js:93 var router = self.app;; Someli-admin-api/routes/routes.js:125 var router = self.app;.

What: Inside the apiRoutes.prototype.init function, the code assigns router = self.app — meaning all router.get/post/put/delete calls in init() bind directly to the raw Express app, not to an Express Router. There is no router.use(authMiddleware) because that would attach the middleware to the entire app retroactively (and would affect routes registered outside init too).

This is the root cause of the platform-wide "endpoints without auth" finding (code-inspect/someli-api.md C1). It is not a forgotten middleware — it is structurally impossible to add a route-level guard to these routes given the current shape. The pattern has been propagated to all three backends.

By contrast, sibling files use a real Express Router with router.use(auth): - someli-api/routes/auth.js — 253 router-level registrations under a router.use(auth) guard - someli-api/routes/social.js — 15 routes via Router - someli-api/routes/paddle.js — 3 routes via Router (router.use(auth)) - Someli-admin-api/routes/auth.js — 7 routes via Router (router.use(auth))

Effect: 393 endpoints in someli-api/routes/routes.js, 269 in designer-api/routes/routes.js, and 31 in Someli-admin-api/routes/routes.js lack route-level authentication and cannot be retrofitted without first refactoring init() to use a sub-Router.

A2. Three coexisting MySQL drivers per process

Where: every backend instantiates three distinct MySQL connection styles, plus the dbDriver/lib/mysql.js callback pool, in every route file and every job file.

someli-api/routes/routes.js: - Line 14: const mysql2 = require('mysql2'); - Line 40: const connection = mysql2.createConnection({...}); - Line 47: const mysql2Promise = require('mysql2/promise'); - Line 48: const connectionPromise = mysql2Promise.createPool({...}); - Line 85: const mysql = require("sync-mysql"); const con = new mysql({...});

someli-api/routes/auth.js does the same (lines 58-68); someli-api/routes/paddle.js adds a fourth pool (line 10). Same pattern in designer-api/routes/routes.js (lines 22-67) and Someli-admin-api/routes/routes.js (lines 13-34, plus auth.js:54-64).

Background jobs each open their own sync-mysql connection at module load: 100 of 108 someli-api/job_*.js files use sync-mysql; 57 of 57 designer-api/job_*.js files do.

Effects (code-inspect/someli-api.md cross-cutting #1): - No shared pool limit. A PM2-deploy with 39 jobs + the main server has on the order of 60+ independent MySQL connections at idle, climbing under load. - Mixing async/promise and sync drivers in the same handler creates subtle ordering bugs (bcrypt.compare awaited but callback-based, etc.). - sync-mysql blocks the event loop for the duration of the query — every job using it cannot process anything else (sockets, signals, health checks) while a query is in flight.

A3. actions/actions.js exists but is bypassed

Where: someli-api/actions/actions.js defines a generic CRUD service (getAll, insertData, updateData, deleteData, fetchAll, customQuery) — and route handlers actively use it (652 references in routes/routes.js, 284 in auth.js). Yet 493 direct con.query(...) calls also appear in routes/routes.js and 999 in auth.js (raw sync-mysql and mysql2 calls, bypassing the CRUD service).

designer-api/routes/routes.js has 449 direct query calls. Someli-admin-api has the cleanest ratio but still mixes.

Why this is an anti-pattern: the CRUD layer was clearly intended to be the single sanitization point, but it was never enforced. The injection vulnerabilities in code-inspect/someli-api.md (M5, M6, H3 SQL injection findings) all land on direct con.query paths that bypass actions.js. The two coexisting access styles mean every handler is a judgment call.

A4. Industry-cloned jobs in designer-api

Where: ~30 of the 57 designer-api/job_*.js files are near-byte-identical clones of a template parameterized only by industry_id and a couple of magic SQL strings. Examples (LoC mostly within 5% of each other):

  • job_It_cyber_security.jsWHERE approve = 1 AND id = 185
  • job_disability_insurance.jsWHERE approve = 1 AND id = 196
  • job_auto_garge_ceramic_coating.js, job_auto_garge_painting_body_repairs.js, job_auto_garge_window_tinting.js
  • job_change_management.js, job_conflict_management.js, job_emotional_intelligence.js
  • job_disability_insurance.js, job_motor_insurance.js, job_cyber_insurance.js, job_common_life_insurance.js
  • … and ~20 more

Side-by-side head -50 of job_It_cyber_security.js and job_disability_insurance.js shows the only differences are the industry id (185 vs 196), a couple of SQL constants, and a hand-curated id IN (...) template-id list in the disability variant.

A single parameterized job (driven from a config row, or even a JSON file checked into the repo) would delete ~2 800 lines of code — 40 industry-clone files at 60–90 LoC each, totaling 2 961 LoC (wc -l designer-api/job_*.js | awk '$1 >= 60 && $1 <= 90'). For perspective, this is ~43% of the 6 825 total LoC across all 57 designer-api/job_*.js files. This is still the largest single mechanical cleanup available on the platform.

Each clone also has the same isOnProcess lock bug as job_facebook_publish.js (code-inspect/someli-api.md H4) — see designer-api/job_It_cyber_security.js:11,18-19. Fixing the bug in one place is impossible while the clones remain.

A5. Skeleton-fork divergence with no resync mechanism

Where: the three Express backends started from the same skeleton (§2) and have drifted in actions/actions.js, modules/dbDriver/lib/mysql.js, server.js, the whole helper/ tree, and all of routes/routes.js. Nothing in the platform reconciles them. There is no shared NPM package, no monorepo build, no documented sync cadence.

CODE-OVERLAP-MATRIX.md §10 is the only operational guidance: "treat identical files as candidates for extraction; treat lightly-forked files as needing dual fixes; treat heavily-forked files as separate codebases." This is risk-management, not architecture. Without a shared library, the platform pays the cost of every fix three times and accepts that some fixes will silently land in only one of the three.

Two mono-repo experiments exist (someli-mono-repo, someli-project) but they are read-only snapshots that have drifted by 333 file diffs (FE) and 49 file diffs (BE) from canonical (CODE-OVERLAP-MATRIX.md §8). They are not the mechanism the platform needs.

A6. The Apptype header as service routing

Where: every frontend axios interceptor sets Apptype to a base64-encoded magic string (someli-platform/middleware/axios.js, Someli-Designer/middleware/axios.js, admin_console_R/src/services/api.ts). Backends inspect this header to branch behaviour.

Why this is an anti-pattern: the header is a one-bit RPC version-and-multitenancy combo with no schema. Adding a new caller requires editing a backend if/else chain. There is no central registry of valid Apptype values; they are duplicated across all three FE codebases and all three BE codebases.

A versioned API gateway, or simply distinct routes per consumer (/customer/, /designer/, /admin/), would replace this. Today the convention is undocumented outside the per-repo notes — see PLATFORM-OVERVIEW.md §6.3.


6. Code smells (cross-repo)

S1. Single files in the 5 000–20 000 LoC range

File LoC Notes
someli-api/routes/auth.js 24 432 One file = 291 endpoints
someli-api/routes/routes.js 21 631 One file = 393 endpoints, plus the con cross-import
designer-api/routes/routes.js 13 608 One file = 269 endpoints
someli-platform/pages/userSetting/index.vue 10 795 Single Vue page
someli-platform/pages/_accid/userSetting/index.vue 9 781 Duplicate of the above under the account-scoped route
someli-api/dashboard/routes/index.js 2 590 Dashboard analytics in one file
someli-platform/pages/_accid/my_library/index.vue 5 506 Duplicate of pages/my_library/index.vue (3 928 LoC)
someli-platform/pages/_accid/contentplanner/index.vue 4 957 Duplicate of pages/contentplanner/index.vue (4 069 LoC)
Someli-Designer/pages/carousaltemplates.vue 4 904 Single designer page
Someli-Designer/pages/tempsets.vue 4 896 Single designer page
admin_console_R/src/pages/Accounts.tsx 2 055 Single admin page (best of the FE pages)

A file over 5 000 LoC cannot be loaded into working memory by a reviewer. The 21k/24k backend files defy any normal code-review process.

S2. Duplicated pages/X/ and pages/_accid/X/ route trees in someli-platform

Per the route rewriter, appendUrl middleware injects accountId into unprefixed URLs — but pages/userSetting/, pages/contentplanner/, pages/my_library/, pages/billing/ all also exist alongside their pages/_accid/... counterparts, each with thousands of duplicated LoC. Either the legacy unprefixed copies are dead (delete) or both are maintained (merge). See someli-platform/04-routing.md.

S3. PM2-managed jobs without an in-repo manifest

someli-api has 108 job_*.js files; ecosystem.config.js registers only 39 of them. So either ~69 jobs are not run in production, or they are run via PM2 commands maintained outside the repo. designer-api and Someli-admin-api have no ecosystem.config.js at all despite 57 and 6 jobs/bots respectively. Operational truth is detached from the repo. See designer-api/jobs-inventory.md and PLATFORM-OVERVIEW.md §6.5.

S4. console.log as observability layer

Repo console.log count
someli-api 3 378
designer-api 609
Someli-admin-api 96
admin_console_R 32

No structured logger (winston/pino) is used. PII (password, mfa_code) appears in some of these — see code-inspect/someli-api.md M3.

S5. Zero test files across all seven product repos

someli-api:        0 *.test.* / *.spec.* files
designer-api:      0
Someli-admin-api:  0
someli-dashboard-be: 0
someli-platform:   0
Someli-Designer:   0
admin_console_R:   0

Source: find <repo> -name '*.test.*' -o -name '*.spec.*'. Every package.json "test" script is exit 1 or absent. This is platform-wide — see per-repo testing.md files.

S6. helper/index.js as a barrel-export anti-pattern

someli-api/helper/index.js re-exports symbols from sibling files. Callers (routes, jobs) commonly do const helper = require('../helper'); and pull dozens of symbols off the namespace. This defeats tree-shaking, blurs the contract between helper files, and means renaming one symbol requires grepping the entire repo. Someli-admin-api/helper/index.js does the same (drifted by 63 lines per CODE-OVERLAP-MATRIX.md §2).

S7. Per-page jQuery in Nuxt frontends

16 .vue pages in someli-platform/pages/ and Someli-Designer/pages/ directly call jQuery or $(...). Bootstrap-Vue + jQuery via CDN coexist with Vue's own data model. This re-creates an entire class of imperative-DOM bugs in a reactive framework. See Someli-Designer/architecture-overview.md §"Coding conventions" — "Direct DOM access via jQuery (loaded via Bootstrap CDN bundle)".

S8. Duplicate JS asset bundles checked in

someli-platform/assets/js/bootstrap.bundle.js (7 013 LoC) and someli-platform/static/owl.carousel.min.js (3 447 LoC) are checked into the repo, in two locations each (assets/ for build pipeline, static/ for verbatim serving). These bundles are vendored, not installed via npm — security patches require manual download-and-replace.

S9. The pages/dynamicPost - Copy.vue smell

Someli-Designer/pages/dynamicPost - Copy.vue (956 LoC) sits next to pages/dynamicPost.vue (1 265 LoC) in a flat pages/ directory. A filesystem Ctrl-C/Ctrl-V artifact has shipped to production. This is a strong signal that no linter, no PR-time review, and no archive/branch discipline exists in Someli-Designer.

S10. No CI on most repos

someli-api has Jenkinsfile + a single GitHub Actions workflow (.github/workflows/dev-api-deploy.yml). someli-platform has Jenkinsfile only. designer-api, Someli-Designer, Someli-admin-api, admin_console_R, someli-dashboard-be have no in-repo CI at all (CLAUDE.md "Deployment"). All assertion of build/typecheck health is manual.


7. Per-repo summary table

Repo Stack Main entry size Auth model Major architectural risks
someli-api Express + MySQL + Socket.IO routes/routes.js = 21 631 LoC, routes/auth.js = 24 432 LoC Custom JWT-in-AES (Bearer header), middleware lives on routes/auth.js only; routes/routes.js registers on raw Express app A1 raw-app routes, A2 three drivers, A3 CRUD bypass, A6 Apptype header; 108 jobs only 39 enrolled in PM2 manifest
designer-api Express + MySQL + Socket.IO routes/routes.js = 13 608 LoC None at the framework level — auth is per-handler ad-hoc; no middlewares/ dir A1 raw-app routes, A4 industry-clone jobs, A5 skeleton drift; no ecosystem.config.js for 57+6 jobs/bots
Someli-admin-api Express + MySQL routes/routes.js = 1 400 LoC, routes/auth.js = 957 LoC Mixed: routes/auth.js has router.use(auth); routes/routes.js has per-handler ensureToken A1 raw-app routes (smaller blast radius), A5 skeleton drift; helper/ has 4 byte-identical and 6 forked files
someli-dashboard-be Express + MySQL server.js = 15 LoC, routes/index.js Mode-switched: dev uses mock middleware, prod has none in the standalone Split-brain with someli-api/dashboard/ (CODE-OVERLAP-MATRIX.md §7) — not currently the source of truth
someli-platform Nuxt 2 / Vue 2.7 SPA 84 pages, 160 components, ~10 Vuex modules @nuxtjs/auth v4 local strategy; cookie source-of-truth S1 pages over 10k LoC, S2 duplicated route trees, Vue 2 EOL
Someli-Designer Nuxt 2 / Vue 2.7 SPA 73 flat pages, 4 components @nuxtjs/auth v4 local; no auth middleware declared A5 weakest of the three FEs, S9 copy-pasted page, S7 jQuery in pages
admin_console_R Vite + React 18 + TS + shadcn/ui 10 pages, 50 ui primitives, ~25 API methods Hand-rolled AuthContext + localStorage token Largest page = Accounts.tsx (2 055 LoC) — manageable; index.html loads gpteng.co runtime (code-inspect/admin_console_R.md)

8. Roadmap implications

Sequencing follows blast radius — A1 unblocks security work, A2 unblocks reliability work, A4 deletes the most LoC, A5 sets up everything else:

Phase 1 — Auth retrofitting (unblocks security audit)

  1. Convert apiRoutes.prototype.init in all three backends to use an Express Router (not self.app). This is mechanical: replace every var router = self.app; with var router = express.Router() and mount it at the end of init(). Then add router.use(authMiddleware) for the authenticated routes.
  2. Per-endpoint audit of what should/should not require auth (most should; webhooks and login should not).
  3. This single refactor closes ~80% of the unauthenticated-endpoint findings in code-inspect/.

Phase 2 — Shared library (@someli/server-shared)

  1. Extract the 4 byte-identical helpers (tokenGenerator.js, revokeToken.js, ragProcess.js, webScraping.js) into a private NPM package.
  2. Replace the three actions/actions.js copies with a single import (reconcile the 11-line drift first).
  3. Replace the three modules/dbDriver/lib/mysql.js copies with a single import.
  4. Add a single connection-pool.js that all backends and all jobs import (closes A2).

Phase 3 — Decompose the giants

  1. Split someli-api/routes/routes.js and routes/auth.js by feature area (suggestion: routes/billing.js, routes/social-links.js, routes/content.js, …). Use the existing endpoint inventories in someli-api/API-inventory.md as the grouping plan.
  2. Split someli-platform/pages/_accid/userSetting/index.vue (9 781 LoC) into a directory of components. Same for the other 4k+ LoC pages. The admin_console_R page sizes are a healthy target.
  3. Delete someli-platform/pages/userSetting/ (unprefixed) once the _accid copy is verified to handle all callers via the appendUrl middleware.

Phase 4 — Parameterize industry jobs in designer-api

  1. Introduce a tIndustryJobConfig table with industry_id, cron_expression, template_ids, category_filter.
  2. Replace ~30 industry-specific jobs with a single job_industry_dynamic_posts.js driven from that table.
  3. Estimated deletion: ~2 800 LoC (40 files × ~72 LoC; verified via wc -l on job_*.js files in the 60–90 LoC band — see §5.A4).

Phase 5 — Observability + tests + CI

  1. Replace console.log with a structured logger (single shared package across BEs) — provides hooks for PII scrubbing.
  2. Add a smoke-test suite to each repo (the testing.md per-repo audits all call this out). Target: 1 test per repo, then grow.
  3. Add a GitHub Actions workflow per repo that runs npm run build + the smoke test. (admin_console_R benefits the most because TS+ESLint will catch real regressions.)

Phase 6 — Stack convergence

The medium-term arc is the admin_console_R stack (Vite + React + TS + shadcn/ui) replacing the two Nuxt 2 / Vue 2 FEs (PLATFORM-OVERVIEW.md §7). This is a multi-quarter project. The Phase 3 page decomposition is the prerequisite — porting a 10 000-LoC Vue page to React is intractable; porting 30 well-scoped 300-LoC components is feasible.


9. Findings index (numbered for traceability)

ID Title Section Severity
A1 Routes registered on raw Express app — auth middleware unattachable §5.A1 Critical
A2 Three coexisting MySQL drivers per process §5.A2 High
A3 actions/actions.js exists but is bypassed by direct con.query §5.A3 High
A4 Industry-cloned jobs in designer-api (~30 copies) §5.A4 High
A5 Skeleton-fork divergence with no resync mechanism §5.A5 High
A6 Apptype header as ad-hoc service routing §5.A6 Medium
S1 Single files in the 5k–24k LoC range §6.S1 High
S2 Duplicated pages/X/ and pages/_accid/X/ route trees §6.S2 Medium
S3 PM2 jobs without in-repo manifest §6.S3 Medium
S4 console.log as observability §6.S4 Medium
S5 Zero test files across all seven product repos §6.S5 High
S6 helper/index.js barrel-export §6.S6 Low
S7 jQuery in Vue pages §6.S7 Medium
S8 Duplicate JS asset bundles checked in §6.S8 Low
S9 pages/dynamicPost - Copy.vue filesystem artifact §6.S9 Low
S10 No CI on five of seven repos §6.S10 Medium

10. Open questions / [VERIFY] markers

  • [VERIFY] Operational status of the ~69 unregistered someli-api/job_*.js files — are they run via external PM2 manifests, run by hand, or dead code?
  • [VERIFY] Whether designer-api and Someli-admin-api are deployed with PM2 at all, given the missing ecosystem.config.js. See designer-api/build-and-deploy.md.
  • [VERIFY] Whether someli-platform/pages/userSetting/ (unprefixed) is still reachable in production or shadowed entirely by appendUrl middleware. If shadowed, delete.
  • [VERIFY] Whether someli-dashboard-be is intended to become the source of truth (in which case the in-process someli-api/dashboard/ should be retired) or is permanently dev-only.
  • [VERIFY] Whether the agents/ directory in someli-api will be ported to the other backends or kept as the single home for AI orchestration.
  • [VERIFY] Whether the Apptype header taxonomy is documented anywhere outside the per-repo notes (it appears not to be).