Skip to content

Architecture Overview

Technology Stack

  • Runtime: Node.js (v20.18.1) with Express 4.x
  • Module System: CommonJS (require/module.exports)
  • Database: MySQL/MariaDB
  • Process Manager: PM2 (production), Nodemon (development)
  • Container: Docker (Node 20.18.1-slim + nginx), port 80/8080

Entry Point & Startup Sequence

File: server.js

  1. Load environment variables via dotenv from conf.js
  2. Create Express app with middleware stack (verified order):
  3. express-session (with hardcoded secret — see security.md)
  4. express-fileupload (multipart uploads)
  5. express.json({ limit: '150mb', parameterLimit: 50000 }) — applied except on webhook routes
  6. Static routes (/favicon.ico, /uploads)
  7. Healthcheck endpoints (/health, /db-health)
  8. passport.initialize() + passport.session()
  9. cors() (default options — accepts all origins; see security.md)

Earlier versions of this doc claimed helmet is part of the middleware stack and that body-parser is set to a 50 MB limit. Both are wrong: helmet is not loaded at all, and the body limit is 150 MB (set via express.json, not body-parser). The mismatch with nginx's 100 MB limit (nginx.conf) is itself a finding — see deployment.md §6.6. 3. Connect to MySQL using modules/dbDriver/lib/mysql.js (async pool, mysql package) 4. Initialize Socket.IO on the HTTP server 5. Build the shared App object: { db, server: app, socket: io } 6. Export appData = { db, server: app, socket: io } for use across modules 7. Mount route modules in order: - /auth/ -> routes/auth.js (authenticated user routes) - /social/ -> routes/social.js (OAuth flows) - /paddle/ -> routes/paddle.js (Paddle billing) - /partnerAuth/ -> routes/partnerAuth.js (partner API) - /auth -> dashboard/routes/index.js (analytics/insights, shares prefix with auth) - / (root) -> routes/routes.js (main API, class-based pattern) 8. Start HTTP server on conf.PORT

Route Architecture

Route Files & Mount Points

File Mount Point Pattern Auth Route Count
routes/routes.js / Class-based (apiRoutes.prototype.init()) 1 route uses methods.ensureToken; rest have no route-level auth 394
routes/auth.js /auth/ Express Router router.use(auth) on all routes 291
routes/social.js /social/ Express Router None (Passport session-based OAuth) 15
routes/paddle.js /paddle/ Express Router router.use(auth) on all routes 2
routes/partnerAuth.js /partnerAuth/ Express Router Custom JWT per-route 4
dashboard/routes/index.js /auth Express Router router.use(auth) only in dev mode 22

The routes/routes.js Pattern

This file exports { api: apiRoutes, con } where: - apiRoutes is a constructor that receives the App object - Routes are defined inside apiRoutes.prototype.init(), binding directly to App.server (the Express app) - con is a sync-mysql connection used throughout for synchronous queries - Routes are bound at the root path, so /uploadImage is accessible at http://host/uploadImage

The routes/auth.js Pattern

  • Standard Express Router exported as module.exports = router
  • router.use(auth) applied globally at line 78, protecting all routes
  • Auth middleware sets userId, accountId, role, isPersonnel on the res object (not req)
  • Handlers destructure { userId, accountId } from res

Webhook Routes

Four routes in routes/routes.js use express.raw() body parser for signature verification: - POST /stripe_webhooks - POST /paddle_sandbox_webhooks - POST /paddle_production_webhooks - POST /paddle_Admin_webhooks

Authentication & Authorization

Token Flow

  1. Login (routes/routes.js): User credentials verified against tMember table
  2. Token Generation (helper/tokenGenerator.js): JWT payload ({ userId, role, accountId, isPersonnel }) is signed with jsonwebtoken, then AES-encrypted with crypto-js
  3. Token Verification (middlewares/auth.js): Bearer token is AES-decrypted, then JWT-verified. Extracted fields are set on res (not req)
  4. Account Check: Many handlers call checkuseraccount(userId, accountId) to validate the user belongs to the specified account

OAuth (Passport.js)

  • File: middlewares/passport.js
  • Strategies: Google, GitHub, Facebook, LinkedIn, TikTok, Twitter
  • Flow: routes/social.js initiates OAuth -> callback encrypts user data with tokenGenerator -> redirects to client with token in query string

Alternative Auth

  • methods.js exports ensureToken middleware (Bearer token extraction) used by GET / in routes/routes.js
  • routes/partnerAuth.js uses its own JWT signing/verification for partner API authentication

Database Access Layer

Three MySQL access patterns coexist:

Package Type Where Used Connection
mysql Async (callbacks) modules/dbDriver/lib/mysql.js -> actions/actions.js Connection pool via App.db
sync-mysql Synchronous/blocking routes/routes.js (con), routes/auth.js (con), most job_*.js files Direct connection, created at module load
mysql2/promise Async (promises) Some newer job files, dashboard services mysql.createPool() with await

Generic CRUD Layer

File: actions/actions.js

Provides table-agnostic operations via the dbDriver: - getAll(tableName, conditions, fields, limit, offset) - insertData(tableName, fields) - updateData(tableName, fields, conditions) - deleteData(tableName, conditions) - customQuery(rawSQL)

Used by route handlers: actions.getAll(...), actions.insertData(...), etc.

Direct SQL

Most route handlers and all background jobs execute SQL directly via con.query() (sync-mysql) or pool queries, bypassing the CRUD layer.

Background Jobs

Configuration: ecosystem.config.js defines ~37 PM2-managed processes.

Jobs are standalone Node.js scripts in the project root (e.g., job_facebook_publish.js, job_content_generation.js). Each job:

  1. Creates its own database connection (sync-mysql or mysql2)
  2. Registers a node-cron schedule (intervals range from every second to daily)
  3. Polls a database table (usually tJobs or tContentPlanner) for pending work
  4. Processes items and updates status

Job Categories

  • Social Publishing: Post images/videos/carousels to Facebook, Instagram, LinkedIn, TikTok
  • Content Generation: AI-powered content creation using OpenAI, Gemini, Bedrock (Llama/Claude/Nova)
  • Media Generation: Render Polotno templates into images, generate thumbnails
  • Token Management: Refresh OAuth tokens for Facebook, LinkedIn, TikTok, Vertex AI
  • Analytics: Fetch post/account insights from social platforms
  • Billing: Process Paddle/Stripe webhooks, invoice handling
  • Notifications: Send emails (SendGrid) and Slack alerts

Configuration

File: conf.js

Loads all environment variables via dotenv and exports them. Key config groups: - Database: host, user, password, database, dbPort - AWS: AWS_ACCESS_KEY, AWS_SECRET_ACCESS_KEY, S3_BUCKET, S3_Region - AI: OPENAI_API_KEY, GOOGLE_API_KEY, AWS_BEDROCK_* - Payments: PADDLE_API_KEY, PADDLE_WEBHOOK_KEY - Social: FACEBOOK_APP_ID, LINKEDIN_CLIENT_ID, TWITTER_CLIENT_ID, TIKTOK_CLIENT_ID - Email: SENDGRID_API_KEY

Helper Module Structure

Entry point: helper/index.js (re-exports from submodules)

Module Purpose
helper/helper.js Core utilities: response formatting, S3 operations, image processing, Paddle config
helper/aiLogics.js AI provider wrappers: openAiLogic, geminiLogic, LlamaFunction, claudeFunction, novaFunction
helper/tokenGenerator.js JWT + AES token encryption/decryption
helper/constants.js Provider IDs, plan constants, template mail IDs
helper/basic.js Generic utilities: shuffleArray, downloadVideoToBuffer, extractAndParseJSON
helper/stockImage.js Pexels/Pixabay stock image fetching
helper/webScraping.js Website content extraction via axios + Cheerio
helper/webscrapeHomePage.js Website scraping via Puppeteer (JavaScript-rendered pages)
helper/ragProcess.js RAG pipeline: document chunking, TF-IDF, embeddings
helper/getRagData.js RAG query answering via Bedrock
helper/social.js Social media helpers: addSPosts, tiktokRefresh
helper/files_upload.js S3 and GCS file upload functions
helper/functionsForAi/gemini.js Gemini API wrappers with Google Search grounding
helper/functionsForAi/cloudRag.js Vertex AI RAG corpus queries
helper/postValidation.js Post image color/content validation

Standard Response Format

All API responses follow this structure:

{
  "status": true,        // boolean success/failure
  "errorMsg": "",        // error message if status is false
  "response": {}         // payload data
}

Constructed via getSuccessResponse(data) and getErrorResponse(message) from helper/helper.js.

Real-time Communication

Socket.IO is initialized in server.js and passed through the App object. Used for broadcasting updates to connected clients (e.g., content generation status, scheduling updates).

File Storage

  • Primary: AWS S3 (two buckets/regions configured via S3_BUCKET, S3_Region, S3_BUCKET2, S3_Region2)
  • Secondary: Google Cloud Storage (for RAG/knowledge base files, configured via CLOUD_BUCKET_NAME)
  • Upload functions: s3UploadFunction and gcsUploadFunction in helper/files_upload.js

Deployment

  • Dockerfile: Node 20.18.1-slim base, runs nginx reverse proxy + Node app
  • Jenkinsfile: CI/CD pipeline deploying dev_api branch via SSH + PM2
  • Branches: dev_api (development), uat_api (staging), main (production)