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.sqlunder 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. Theactions/actions.jsCRUD service exists but is bypassed in many handlers in favour of directcon.query(...)(rawsync-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 atsomeli-api/someli-schema.sql— and that file is documentation-only, not committed to any of the source repos. agents/directory exists insomeli-apionly — AI orchestration code is not shared with the two other backends that also need it.designer-apiandSomeli-admin-apihave copy-pastedhelper/aiLogics.jsinstead. (CODE-OVERLAP-MATRIX.md §2 showsaiLogics.jsdiffers by 396 lines betweensomeli-apiandSomeli-admin-api).dashboard/routes/index.js:17-19reaches back into the parent app at runtime:This is the only cross-module re-entry in the repo and it is the reason({ appData } = require("../../server")); ({ con } = require("../../routes/routes")); ({ checkuseraccount, getImageFromS3 } = require("../../helper/helper"));routes/routes.jsexportsconandserver.jsexportsappData. Seesomeli-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:
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.js—WHERE approve = 1 AND id = 185job_disability_insurance.js—WHERE approve = 1 AND id = 196job_auto_garge_ceramic_coating.js,job_auto_garge_painting_body_repairs.js,job_auto_garge_window_tinting.jsjob_change_management.js,job_conflict_management.js,job_emotional_intelligence.jsjob_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)¶
- Convert
apiRoutes.prototype.initin all three backends to use an Express Router (notself.app). This is mechanical: replace everyvar router = self.app;withvar router = express.Router()and mount it at the end ofinit(). Then addrouter.use(authMiddleware)for the authenticated routes. - Per-endpoint audit of what should/should not require auth (most should; webhooks and login should not).
- This single refactor closes ~80% of the unauthenticated-endpoint findings in
code-inspect/.
Phase 2 — Shared library (@someli/server-shared)¶
- Extract the 4 byte-identical helpers (
tokenGenerator.js,revokeToken.js,ragProcess.js,webScraping.js) into a private NPM package. - Replace the three
actions/actions.jscopies with a single import (reconcile the 11-line drift first). - Replace the three
modules/dbDriver/lib/mysql.jscopies with a single import. - Add a single
connection-pool.jsthat all backends and all jobs import (closes A2).
Phase 3 — Decompose the giants¶
- Split
someli-api/routes/routes.jsandroutes/auth.jsby feature area (suggestion:routes/billing.js,routes/social-links.js,routes/content.js, …). Use the existing endpoint inventories insomeli-api/API-inventory.mdas the grouping plan. - Split
someli-platform/pages/_accid/userSetting/index.vue(9 781 LoC) into a directory of components. Same for the other 4k+ LoC pages. Theadmin_console_Rpage sizes are a healthy target. - Delete
someli-platform/pages/userSetting/(unprefixed) once the_accidcopy is verified to handle all callers via theappendUrlmiddleware.
Phase 4 — Parameterize industry jobs in designer-api¶
- Introduce a
tIndustryJobConfigtable withindustry_id,cron_expression,template_ids,category_filter. - Replace ~30 industry-specific jobs with a single
job_industry_dynamic_posts.jsdriven from that table. - Estimated deletion: ~2 800 LoC (40 files × ~72 LoC; verified via
wc -lonjob_*.jsfiles in the 60–90 LoC band — see §5.A4).
Phase 5 — Observability + tests + CI¶
- Replace
console.logwith a structured logger (single shared package across BEs) — provides hooks for PII scrubbing. - Add a smoke-test suite to each repo (the
testing.mdper-repo audits all call this out). Target: 1 test per repo, then grow. - Add a GitHub Actions workflow per repo that runs
npm run build+ the smoke test. (admin_console_Rbenefits 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_*.jsfiles — are they run via external PM2 manifests, run by hand, or dead code? - [VERIFY] Whether
designer-apiandSomeli-admin-apiare deployed with PM2 at all, given the missingecosystem.config.js. Seedesigner-api/build-and-deploy.md. - [VERIFY] Whether
someli-platform/pages/userSetting/(unprefixed) is still reachable in production or shadowed entirely byappendUrlmiddleware. If shadowed, delete. - [VERIFY] Whether
someli-dashboard-beis intended to become the source of truth (in which case the in-processsomeli-api/dashboard/should be retired) or is permanently dev-only. - [VERIFY] Whether the
agents/directory insomeli-apiwill be ported to the other backends or kept as the single home for AI orchestration. - [VERIFY] Whether the
Apptypeheader taxonomy is documented anywhere outside the per-repo notes (it appears not to be).
11. Related documents¶
PLATFORM-OVERVIEW.md— high-level platform tourCODE-OVERLAP-MATRIX.md— file-by-file overlap between reposcode-inspect/— per-repo bug-level inspections (the concrete consequences of A1–A6)- Per-repo
architecture-overview.md— the component-level details cited throughout this document _meta/AUDIT_GUIDE.md— the methodology this document follows