Skip to content

System Context & Container Architecture (C4)

This is the entry-point architecture document for the MAS / Mr. Mentor backend. It explains, at a glance, what the system is, who uses it, which external services it depends on, how the containers fit together, what runs at boot, and how a request travels through the stack. Every feature doc hangs off the product-suite map at the bottom — start here, then drill into the relevant feature doc.

Status: documented from source on this branch. Primary sources: src/index.ts (startup), src/app.ts (Express bootstrap + middleware), src/routes/index.ts (route mounting), src/services/QueueService.ts (queues), src/config/database.ts, src/config/redis.ts, package.json, docker-compose*.yml.


Overview

The backend is a single Express + TypeScript monolith (deployed as one container, scaled with PM2 / multiple Docker replicas) that began life as the "Mr. Mentor" 1:1 mentorship API and has grown into the shared API for a multi-product EdTech + recruitment suite operated by My Analytics School (MAS).

A single process serves three transport surfaces on one HTTP server (src/index.ts):

  1. REST API — Express app (src/app.ts), all routes mounted under /api (plus /admin/queues for the Bull Board UI), via src/routes/index.ts.
  2. Socket.IO — real-time WebRTC signalling, presence, chat, recording control (src/socket.ts, path /socket.io).
  3. Raw WebSocket relay — the terminal-mirror relay for the in-browser shell/editor (src/services/TerminalRelayWsServer.ts, attached in noServer mode to the same HTTP server).

It is backed by one PostgreSQL database (TypeORM, synchronize: true — entities auto-create/update tables, no migrations in dev), Redis (cache + BullMQ queues), AWS S3 (recordings, documents, banners, signed agreements), and a long list of third-party APIs (Razorpay, Google, Exotel, ElevenLabs, Leegality, Judge0, LLM gateway, Graphy, EzExam, WhatsApp).

Personas / roles

Application roles live on the User entity (USER | ADMIN | SUPERADMIN | EXPERT | SALES, plus finance/HR/CM/sales-head/batch-lead capability flags checked by dedicated middleware). The human personas the system serves:

Persona Uses Primary product
Student / mentee Books mentors, attends meetings, takes courses, quizzes Mr. Mentor + MAS LMS
Mentor / EXPERT Manages slots, runs meetings, tracks earnings/payouts Mr. Mentor
Sales agent / SALES Works leads, follow-ups, click-to-call, WhatsApp Sales CRM
Sales head Oversees agents, lead ownership, targets (data isolation) Sales CRM
Community manager (CM) Manages community-sourced students/leads Sales CRM
Batch lead (BL) Runs a batch, tracks at-risk students MAS LMS
Recruiter / HR Posts jobs, screens resumes, runs AI interviews Mr. Hire
Candidate / applicant Applies, takes screening quizzes + voice interviews Mr. Hire
Finance / FINANCE GST invoices, reports, refunds, ledger Finance
Admin / SUPERADMIN Everything: config, banners, workflows, analytics All
External vendor (machine) Pushes leads via API key (/api/v1/vendor) Vendor API

Key concepts & entities

  • Monolith, many bounded contexts. All products share one Express app, one DB, one Redis. Separation is by route prefix + service + entity grouping, not by deployment unit.
  • Multi-tenant via x-platform header. Requests carry an X-Platform header (e.g. mr-mentor / my-analytics-school); it is allow-listed in CORS (src/app.ts) and routed by MasGatewayService (src/services/MasGatewayService.ts). See the Mr.-Mentor-as-gateway notion in masGateway.controller.ts.
  • TypeORM auto-sync. synchronize: true in src/config/database.ts — entity classes are the schema. 51+ entities registered in the DataSource. Pool: min 5 / max 20 connections (extra config).
  • Singletons. DatabaseService, RedisService, QueueService are singletons constructed once in App (src/app.ts).
  • Idempotent boot seeders. src/index.ts runs a chain of safe-to-rerun seeders (colleges, job templates, admin/sales users, screening config, workflow defaults, lead backfills) on every startup.

The most architecturally significant cross-cutting entities (full per-domain models live in the feature docs):

Entity File Role
User src/entities/User.ts Identity + role; FK target for almost everything
Platform src/entities/ (see MasGatewayService) Multi-tenant platform routing
SystemConfig src/entities/SystemConfig.ts Runtime feature flags / cron toggles read at boot
Mentor, Slots, MeetingLogs, MeetingRecording src/entities/ Mr. Mentor core
Token, TokenUsage, TokenPurchase, MentorEarnings src/entities/ Token economy + payouts
Course, Enrollment, Module, Class, Quiz src/entities/ MAS LMS
JobPost, JobApplication, ResumeAnalysis, VoiceInterview src/entities/ Mr. Hire
RawLead, CampaignLead, lead/workflow entities src/entities/ Sales CRM + automation
MrLearnSyncConfig, MrTestSyncConfig src/entities/mrlearn/, src/entities/mtest/ External LMS sync schedules

Architecture

Level 1 — System Context (C4)

Who and what touches the system, and the external services it calls out to.

flowchart TB
    subgraph Personas["People"]
        STU["Student / Mentee"]
        MEN["Mentor (EXPERT)"]
        SALES["Sales agent / head / CM"]
        REC["Recruiter / HR"]
        CAND["Candidate / Applicant"]
        FIN["Finance"]
        ADM["Admin / Superadmin"]
    end

    subgraph MAS["MAS Platform (this system)"]
        BE["mr-mentor-backend<br/>Express + Socket.IO API"]
    end

    subgraph Vendor["Machine clients"]
        VEND["External lead vendors<br/>via API key"]
    end

    STU --> BE
    MEN --> BE
    SALES --> BE
    REC --> BE
    CAND --> BE
    FIN --> BE
    ADM --> BE
    VEND --> BE

    subgraph Ext["External systems"]
        RZP["Razorpay<br/>payments"]
        GOO["Google<br/>OAuth + Calendar + Drive"]
        S3["AWS S3<br/>object storage"]
        EXO["Exotel<br/>click-to-call + SMS"]
        WA["WhatsApp<br/>Cloud API"]
        EL["ElevenLabs / Aarya / Miss Ozone<br/>AI voice calling"]
        LEG["Leegality<br/>e-signing (PAP/MOU)"]
        J0["Judge0<br/>code execution"]
        LLM["LLM gateway / providers<br/>OpenAI, Groq, Anthropic, Gemini"]
        GRA["Graphy (Mr. Learn)<br/>external LMS"]
        EZ["EzExam (Mr. Test)<br/>online exams"]
        SMTP["Gmail SMTP<br/>transactional email"]
    end

    BE --> RZP
    BE --> GOO
    BE --> S3
    BE --> EXO
    BE --> WA
    BE --> EL
    BE --> LEG
    BE --> J0
    BE --> LLM
    BE --> GRA
    BE --> EZ
    BE --> SMTP

Level 2 — Container diagram

The runtime containers and the data stores / external dependencies they talk to.

flowchart TB
    subgraph FE["Frontends"]
        MMF["mr-mentor-frontend<br/>Next.js 15 (admin, tokens, meetings)"]
        WEB["mas-website-live<br/>Next.js 14 (public, student, company)"]
        HF["mr-hire-frontend<br/>React 18 + Vite (recruitment UI)"]
    end

    subgraph Proc["mr-mentor-backend process (port 8000)"]
        EXP["Express REST API<br/>src/app.ts + src/routes/index.ts"]
        SIO["Socket.IO server<br/>src/socket.ts (path /socket.io)"]
        TERM["Terminal WS relay<br/>TerminalRelayWsServer (noServer)"]
        WORK["BullMQ workers (20+)<br/>src/workers/*"]
    end

    subgraph Data["Data stores"]
        PG["PostgreSQL<br/>TypeORM, pool 5-20, synchronize on"]
        RDS["Redis<br/>cache + BullMQ queues"]
        S3B["AWS S3 buckets<br/>recordings / docs / banners"]
    end

    subgraph ExtAPI["External APIs"]
        EXTS["Razorpay, Google, Exotel, WhatsApp,<br/>ElevenLabs, Leegality, Judge0, LLM,<br/>Graphy, EzExam, Gmail SMTP"]
    end

    MMF -->|HTTP + WebSocket| EXP
    MMF -->|Socket.IO| SIO
    WEB -->|HTTP| EXP
    WEB -->|WS terminal| TERM
    HF -->|HTTP| EXP

    EXP --> PG
    EXP --> RDS
    EXP --> S3B
    SIO --> PG
    SIO --> RDS
    WORK --> PG
    WORK --> RDS
    WORK --> S3B
    EXP --> EXTS
    WORK --> EXTS

    RDS -. job queues .-> WORK

Level 3 — Request layering (inside the API container)

flowchart LR
    REQ["HTTP request"] --> CORS["CORS + Helmet<br/>+ json/urlencoded 20mb"]
    CORS --> ROUTER["Routes (src/routes/*)<br/>mounted under /api"]
    ROUTER --> MW["Middleware<br/>auth / admin / role / vendor"]
    MW --> CTRL["Controllers<br/>src/controllers/*"]
    CTRL --> SVC["Services<br/>src/services/*"]
    SVC --> ENT["TypeORM entities<br/>src/entities/*"]
    ENT --> PG[("PostgreSQL")]
    SVC --> Q["QueueService<br/>BullMQ enqueue"]
    Q --> RDS[("Redis")]
    SVC --> EXT["External API clients"]
    CTRL --> RESP["JSON response"]

Data model

This document does not own a domain; it stitches together the per-domain models. The diagram below is a high-level map of bounded contexts and their anchor entities — see each feature doc for the detailed erDiagram.

erDiagram
    USER ||--o{ MENTOR : "may be"
    USER ||--o{ ENROLLMENT : "has"
    USER ||--o{ TOKEN : "owns"
    USER ||--o{ JOB_APPLICATION : "submits"
    USER ||--o{ RAW_LEAD : "owns as agent"
    MENTOR ||--o{ SLOTS : "offers"
    SLOTS ||--o{ MEETING_LOGS : "produces"
    MEETING_LOGS ||--o| MEETING_RECORDING : "may have"
    COURSE ||--o{ ENROLLMENT : "has"
    COURSE ||--o{ MODULE : "has"
    MODULE ||--o{ CLASS_SESSION : "has"
    JOB_POST ||--o{ JOB_APPLICATION : "receives"
    JOB_APPLICATION ||--o| RESUME_ANALYSIS : "scored by"
    JOB_APPLICATION ||--o{ VOICE_INTERVIEW : "screened by"
    PLATFORM ||--o{ USER : "tenants"

    USER {
        uuid id PK
        string email UK
        string role
        string fullName
    }
    PLATFORM {
        uuid id PK
        string slug UK
    }
    SYSTEM_CONFIG {
        string key PK
        string value
    }

SystemConfig (src/entities/SystemConfig.ts) is a key/value table read at boot to toggle crons such as MRLEARN_NEW_STUDENT_SYNC_ENABLED and its interval.


API surface

Routes are assembled in src/routes/index.ts. Most route files are mounted at the bare /api prefix and declare their own sub-paths internally; a subset are mounted at a specific prefix. The table lists the mount prefixes (the authoritative entry points) — drill into the linked feature doc for the exact endpoints under each.

Method Mount prefix Auth/role Purpose Feature doc
ALL /api/health public Health check
GET /api/test-data public DB connectivity debug probe
ALL /api/auth/* public + JWT Login, signup, Google OAuth, OTP identity-and-access
GET /auth/google/callback public OAuth redirect → /api/google-calendar/callback identity-and-access
ALL /api (users, profile) JWT User + profile CRUD student-portal-and-profile
ALL /api (mentors, slots) JWT / EXPERT Mentor profiles, availability mentorship-and-meetings
ALL /api (tokens, governance) JWT Token balance, purchase, usage token-economy
ALL /api (slot-completion, recordings, meeting-logs, meeting-actions) JWT / email-token Meeting lifecycle + recordings mentorship-and-meetings
ALL /api (mentor-earnings) EXPERT / ADMIN Earnings + payouts mentor-earnings-and-payouts
ALL /api/admin/* ADMIN / SUPERADMIN Admin operations
ALL /api/student/* JWT (enrolled) Student dashboard, profile, quizzes student-engagement-gamification
ALL /api/courses, /api (courses) mixed (public listing) Course catalogue + management education-lms-courses
ALL /api/admin/new-courses ADMIN New course format education-lms-courses
ALL /api (course-enrollment) JWT Enrollment education-lms-courses
ALL /api/sales/* SALES / head Sales dashboard, discounts, PAP MOU sales-crm-leads
ALL /api (raw leads, campaign leads) SALES / public capture Lead ingestion sales-crm-leads
ALL /api (sales workflow) ADMIN Automation builder + engine workflow-automation-engine
ALL /api/cm, /api/batchlead, /api/supermentor role-scoped CM / batch-lead / super-mentor consoles sales-crm-assignment-workflow-targets
ALL /api/v1/vendor X-API-Key (vendorAuth) External vendor lead ingestion sales-crm-leads
POST /api/exotel/* shared-secret token Exotel status callbacks (webhook) comms-telephony-exotel
ALL /api (whatsapp) JWT / webhook WhatsApp messaging comms-whatsapp
ALL /api/finance/* FINANCE / ADMIN Finance portal, GST, reports payments-finance-gst
ALL /api (pipeline-cost) finance/admin Pipeline cost ledger payments-finance-gst
ALL /api (job-posts, job-templates, mr-hire apply) mixed Mr. Hire jobs + applications mr-hire-jobs-and-applications
ALL /api/admin/job-applications, /api/admin/resume-analysis, /api/admin/all-responses ADMIN/HR Applications + AI screening mr-hire-ai-resume-screening
ALL /api/admin (ai-screening-config) ADMIN Screening config mr-hire-ai-resume-screening
ALL /api/voice-interviews, /api/miss-ozone mixed / webhook AI voice interviews + voice mentor mr-hire-voice-interviews-and-ai-calling
ALL /api/question-bank, /api/candidate-quiz ADMIN / public-token Quiz banks + candidate quizzes assessments-quizzes-assignments
ALL /api/judge0 public (from quiz pages) Code execution proxy assessments-quizzes-assignments
ALL /api (talent-pool), /api (salary-benchmark) ADMIN/HR Talent pool + salary benchmarking mr-hire-talent-pool-and-salary
ALL /api/placement-score role-scoped Placement scoring mr-hire-talent-pool-and-salary
ALL /api/graphy ADMIN proxy Graphy / Mr. Learn integration integration-mr-learn
ALL /api/ezexam ADMIN proxy EzExam / Mr. Test integration
ALL /api/ai JWT Consolidated AI-facing student-profile endpoint
ALL /api (agent-config, credential-proxy, system-config, terminal-session) ADMIN / JWT AI platform + config + terminal relay control
ALL /api (sticky-banners, popup-banners, ai-for-everyone, course-interest, event-config, league-registration) mixed Marketing + events
ALL /api/upload, /api/bulk-upload JWT / ADMIN S3 uploads + Excel imports
ALL /api/google-calendar, /api/google-drive-connector JWT + OAuth Google integrations
ALL /api/cleanup, /api/redis ADMIN Ops/maintenance
GET /admin/queues (Bull Board) BullMQ queue monitoring UI

Authentication is enforced by middleware in src/middleware/ (auth.middleware.ts verifies the JWT with HS256 and sets req.userId; admin.middleware.ts, expert.middleware.ts, finance.middleware.ts, hrRole.middleware.ts, salesHeadPage.middleware.ts, batchLead.middleware.ts, isEnrolled.middleware.ts, vendorAuth.middleware.ts add role/capability checks). Several routes are deliberately public (Judge0 proxy, candidate quiz where the token is the auth, Exotel webhook guarded by a shared secret, public course listing, lead-capture forms). See identity-and-access.


User journeys

The headline journeys that exercise multiple containers end-to-end. Each feature doc owns the deep journeys for its domain; these show how the whole system hangs together.

Journey 1 — Cold start: API process boot

How the single process comes up: DB, seeders, Redis, all workers, schedules, then the combined HTTP server.

sequenceDiagram
    participant PM as PM2 or Docker
    participant IDX as index.ts startServer
    participant APP as App
    participant PG as PostgreSQL
    participant SEED as Seeders
    participant RDS as Redis
    participant WK as Worker modules
    participant Q as QueueService
    participant HTTP as HTTP server

    PM->>IDX: launch process
    IDX->>APP: new App constructs middleware and routes
    IDX->>APP: initializeDatabase
    APP->>PG: connect TypeORM and auto-sync entities
    IDX->>SEED: seed colleges then job templates then admin then sales users
    IDX->>SEED: seed screening config workflow defaults and lead backfills
    Note over SEED: all seeders are idempotent and safe to re-run
    IDX->>APP: initializeRedis
    APP->>RDS: connect ioredis
    IDX->>WK: dynamic import of 20-plus worker modules
    Note over WK: email whatsapp database cleanup kpi aarya workflow resume etc
    IDX->>Q: schedule repeatable jobs
    Q->>RDS: register cron-style repeatable jobs
    IDX->>PG: read MrLearn and MrTest sync configs and SystemConfig flags
    IDX->>Q: re-register enabled sync and reminder schedules
    IDX->>HTTP: createServer then attach Socket.IO and terminal relay
    HTTP-->>PM: listening on PORT 8000

Journey 2 — Authenticated REST request lifecycle

The path every protected JSON call takes.

sequenceDiagram
    participant FE as Frontend
    participant CORS as CORS and Helmet
    participant RT as Router
    participant AUTH as authMiddleware
    participant CTRL as Controller
    participant SVC as Service
    participant PG as PostgreSQL
    participant Q as BullMQ via Redis

    FE->>CORS: HTTP request with Authorization Bearer token and X-Platform header
    CORS->>CORS: validate origin against allow-list
    alt origin not allowed and not development
        CORS-->>FE: CORS error
    else allowed
        CORS->>RT: forward to matched route
        RT->>AUTH: run auth middleware
        AUTH->>AUTH: verify JWT with HS256
        alt token missing or invalid
            AUTH-->>FE: 401 Authorization token missing
        else valid
            AUTH->>CTRL: set req.userId then call controller
            CTRL->>SVC: invoke business logic
            SVC->>PG: read or write via TypeORM
            PG-->>SVC: rows
            opt side effect needed
                SVC->>Q: enqueue email or whatsapp or db job
            end
            SVC-->>CTRL: result
            CTRL-->>FE: JSON response
        end
    end
    Note over RT: unmatched route returns 404 and thrown errors hit the global 500 handler

Journey 3 — Real-time meeting (WebRTC signalling)

The Socket.IO surface brokers signalling so two browsers can establish a peer connection; the server never carries media.

sequenceDiagram
    participant A as Mentor browser
    participant SIO as Socket.IO server
    participant B as Student browser
    participant PG as PostgreSQL

    A->>SIO: connect then initialize-meeting
    A->>SIO: join-room with meeting id
    SIO->>PG: log meeting start
    B->>SIO: join-room with same meeting id
    SIO-->>A: room-users-updated with new peer
    A->>SIO: offer to B socketId
    SIO-->>B: forward offer
    B->>SIO: answer to A socketId
    SIO-->>A: forward answer
    A->>SIO: ice-candidate
    SIO-->>B: forward ice-candidate
    Note over A,B: peer connection established and media flows directly
    A->>SIO: start-recording
    SIO-->>B: recording-started
    A->>SIO: end-meeting
    SIO->>PG: log meeting end and persist recording metadata

Journey 4 — Async side effect: queued transactional email

Controllers do not send email inline; they enqueue and return immediately.

sequenceDiagram
    participant FE as Frontend
    participant CTRL as Controller
    participant Q as QueueService
    participant RDS as Redis emailQueue
    participant WK as email.worker
    participant SMTP as Gmail SMTP

    FE->>CTRL: action that triggers a notification
    CTRL->>Q: addEmailJob with type and recipient and data
    Q->>RDS: persist job on emailQueue
    CTRL-->>FE: 200 response without waiting
    RDS-->>WK: deliver job to worker
    WK->>SMTP: send templated email
    alt SMTP rejects credentials
        SMTP-->>WK: 535 bad credentials
        WK->>RDS: job marked failed for retry
    else sent
        SMTP-->>WK: accepted
        WK->>RDS: job completed
    end

Journey 5 — External lead ingestion via Vendor API

Machine clients authenticate with an API key, not a JWT.

sequenceDiagram
    participant VEND as Vendor system
    participant RT as Router at api v1 vendor
    participant VA as vendorAuth middleware
    participant SVC as Lead service
    participant PG as PostgreSQL
    participant Q as workflowQueue

    VEND->>RT: POST lead payload with X-API-Key header
    RT->>VA: validate API key
    alt key invalid
        VA-->>VEND: 401 unauthorized
    else key valid
        VA->>SVC: create raw lead scoped to vendor
        SVC->>PG: insert raw lead with source attribution
        SVC->>Q: enqueue workflow enrolment scan
        SVC-->>VEND: 200 with lead id
    end

Journey 6 — Scheduled external sync (Mr. Learn / Mr. Test)

Persisted sync configs are re-registered into BullMQ on every boot, so config changes survive a Redis flush.

sequenceDiagram
    participant CRON as BullMQ repeatable job
    participant WK as mrlearnSync.worker
    participant CFG as MrLearnSyncConfig in PG
    participant GRA as Graphy API
    participant PG as PostgreSQL

    CRON->>WK: fire on interval for config id
    WK->>CFG: load sync config
    WK->>GRA: fetch enrolments and progress
    GRA-->>WK: data
    WK->>PG: upsert student progress
    Note over WK: MrTest follows the same pattern against EzExam

Background jobs & async

All async work runs through BullMQ on Redis, with queues created in src/services/QueueService.ts and workers imported during boot in src/index.ts. The Bull Board UI is mounted at /admin/queues.

Queue Worker Schedule Purpose
emailQueue email.worker on demand OTP, password reset, meeting + transactional email
notificationQueue (notification handling) on demand In-app / push notifications
whatsappQueue whatsapp.worker on demand WhatsApp messages
databaseQueue database.worker on demand Heavy DB operations
cleanupQueue cleanup.worker every 15 min (slot cleanup) Expired slot cleanup
kpiQueue kpi.worker every 15 min Dashboard KPI calculations
aaryaSyncQueue aaryaSync.worker every 15 min Poll ElevenLabs for Aarya call status
workflowQueue workflow.worker trigger-scan every 5 min Sales automation enrolment + step advance
resumeAnalysisQueue resumeAnalysis.worker on demand AI resume processing
salaryBenchmarkQueue salaryBenchmark.worker every 15 days Salary benchmark refresh
warningQueue warning.worker daily 23:59 Student warning automation
leadAssignmentQueue (worker disabled) every 15 min (scheduled) Lead auto-assignment
dailyCardsQueue daily-cards.worker midnight IST Daily engagement cards
assignmentReminderQueue assignmentReminder.worker 19:00 IST daily Assignment-due reminders
coursePlanQueue course-plan.worker on demand Course plan generation
missOzoneQueue missOzone.worker reconciler 60s + prune 03:30 AI voice mentor calling
mrlearnSyncQueue mrlearnSync.worker per-config interval Graphy (Mr. Learn) sync
mrlearnReminderQueue mrlearnReminder.worker per-config interval WhatsApp progress nudges
mrlearnNewStudentSyncQueue mrlearnNewStudentSync.worker SystemConfig interval New-student fast sync
mrtestSyncQueue mrtestSync.worker per-config interval EzExam (Mr. Test) sync
badgeEvaluationQueue badgeEvaluation.worker every 24h Gamification badge safety-net
studentRiskComputationQueue studentRiskComputation.worker every 24h Students-at-risk scoring

Additional scheduled jobs registered at boot but not 1:1 with the list above include the application backfill (daily 02:00 IST). Several initial-on-startup runs (cleanup, KPI) are intentionally commented out in src/index.ts.

Socket.IO events (src/socket.ts): meeting lifecycle (initialize-meeting, join-room, leave-room, meeting-started, meeting-ended, end-meeting), WebRTC signalling (offer, answer, ice-candidate), media (audio-toggle, video-toggle), recording (start-recording, recording-started, stop-recording, …), presence (get-online-users, room-users-updated, takeover-connection), chat (chat-message), and timer events.

Webhooks (inbound): Exotel status callbacks (/api/exotel/*, shared-secret guarded), WhatsApp delivery/inbound, AI-calling completion callbacks (Aarya/Miss Ozone), and the OAuth redirect at /auth/google/callback.


External integrations

Service Used for Key env vars Failure / fallback
Razorpay Token + course payments, order/verify RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET Payment fails closed; order not created
Google OAuth + Calendar + Drive Login, meeting calendar events, Drive connector GOOGLE_CLIENT_ID/SECRET, GOOGLE_REDIRECT_URI Calendar event creation is best-effort
AWS S3 Recordings, student docs, banner assets, signed PDFs AWS_ACCESS_KEY_ID/SECRET, AWS_REGION, AWS_S3_*BUCKET* Presigned-URL direct upload (USE_DIRECT_S3_UPLOAD)
Gmail SMTP (Nodemailer) Transactional email EMAIL_USER, EMAIL_PASS Job retried; 535 needs app-password rotation
Exotel Click-to-call + SMS in CRM EXOTEL_SID, EXOTEL_API_KEY/TOKEN, EXOTEL_CALLER_ID, EXOTEL_SUBDOMAIN, EXOTEL_WEBHOOK_TOKEN Feature self-disables (CRM falls back to tel: links) when unset
WhatsApp Cloud API Lead + student messaging, reminders WhatsApp env vars Queued; failures retried
ElevenLabs / Aarya / Miss Ozone AI voice interviews + mentor calling provider keys + HrCallConfig Aarya sync poller reconciles dispatched calls every 15 min
Leegality e-signing for PAP / MOU agreements Leegality env vars Stuck workflows recovered manually (see PAP recovery skill)
Judge0 Code execution in quizzes Judge0 base URL/key Proxy route public; failures surface to quiz UI
LLM gateway / providers AI screening, agents, Ask MAS, classroom gateway URL + per-user keys Per-user key fallback; gateway routes providers
Graphy (Mr. Learn) External LMS sync MrLearnSyncConfig rows Per-config schedule recreated each boot
EzExam (Mr. Test) External exam sync MrTestSyncConfig rows Per-config schedule recreated each boot
Mr. Hire backend AI resume analysis (separate FastAPI service) MR_HIRE_BACKEND_URL In Docker, container DNS name

Feature flags / runtime config: ENABLE_SEEDING (gates batch/course seeding), USE_DIRECT_S3_UPLOAD, ALLOW_EARLY_MEETING_JOIN + MEETING_JOIN_BUFFER_MINUTES, and SystemConfig keys such as MRLEARN_NEW_STUDENT_SYNC_ENABLED / MRLEARN_NEW_STUDENT_SYNC_INTERVAL_HOURS read at boot. Token Governance v1 is shipped feature-flagged OFF.


Status lifecycles

This doc owns one lifecycle worth stating explicitly: the process lifecycle of the API container.

stateDiagram-v2
    [*] --> Booting
    Booting --> DbConnected : initializeDatabase
    DbConnected --> Seeded : idempotent seeders run
    Seeded --> RedisConnected : initializeRedis
    RedisConnected --> WorkersUp : import 20-plus workers
    WorkersUp --> Scheduled : register repeatable jobs
    Scheduled --> Listening : HTTP plus Socket.IO plus terminal relay bound
    Listening --> Draining : SIGINT or SIGTERM
    Draining --> [*] : close io then http then datasource then redis
    Booting --> Failed : startup error
    DbConnected --> Failed : startup error
    Failed --> [*] : process exit 1

Domain entity lifecycles (meeting status, lead status, application/screening status, invoice status, PAP workflow status) are documented in their respective feature docs.


Edge cases, limits & gotchas

  • synchronize: true in production-shaped DB. Entity changes auto-apply (src/config/database.ts). A schema-affecting entity edit hot-modifies tables on the next boot — review carefully. Non-default Postgres schemas are not created by sync (see the comment block around line 269) and need explicit setup.
  • CORS is permissive in development. When NODE_ENV === 'development', any origin is allowed (src/app.ts). Production relies on CORS_ALLOWED_ORIGINS (a JSON array) plus a small hard-coded default list. Requests with no Origin (curl, mobile) and Origin: null (file://) are always allowed.
  • Two CORS configs must agree. Express CORS and the Socket.IO CORS both read CORS_ALLOWED_ORIGINS (src/index.ts); a missing/empty var means Socket.IO allows no browser origins.
  • JWT only, no refresh tokens. authMiddleware verifies HS256 access tokens and sets req.userId; there is no refresh-token flow in code.
  • Public-by-design routes. Judge0 proxy, candidate quiz (token is the auth), public course listing, lead capture, and the Exotel webhook (shared-secret) bypass authMiddleware — do not assume /api/* is authenticated.
  • x-platform multi-tenancy. Cross-product behaviour can vary by the X-Platform header; the header is explicitly allow-listed in CORS and consumed by MasGatewayService. Missing/wrong values can change routing.
  • Body limit 20 MB. JSON and urlencoded bodies are capped at 20mb (src/app.ts); large uploads should go through S3 presigned-URL direct upload, not the JSON body.
  • Email/WhatsApp are fire-and-forget. Controllers enqueue and return; a failed SMTP credential will not fail the request but will pile up failed jobs (rotate the Gmail app password, then retry).
  • Boot is heavy and serial. ~20 worker imports + ~15 schedule registrations + several DB-backed config re-registrations run before the server listens; a slow DB/Redis lengthens cold start. Several seeders run on every boot (idempotent but they do hit the DB).
  • Disabled features. The lead-assignment worker is commented out (its schedule still registers); some initial-startup cleanup/KPI runs are commented out.
  • Single process, three transports. Socket.IO (/socket.io) and the terminal WS relay share the same HTTP server as the REST API; a crash takes down all three. Graceful shutdown closes them in order (io → http → datasource → redis).