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):
- REST API — Express app (
src/app.ts), all routes mounted under/api(plus/admin/queuesfor the Bull Board UI), viasrc/routes/index.ts. - Socket.IO — real-time WebRTC signalling, presence, chat, recording control (
src/socket.ts, path/socket.io). - Raw WebSocket relay — the terminal-mirror relay for the in-browser shell/editor
(
src/services/TerminalRelayWsServer.ts, attached innoServermode 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-platformheader. Requests carry anX-Platformheader (e.g.mr-mentor/my-analytics-school); it is allow-listed in CORS (src/app.ts) and routed byMasGatewayService(src/services/MasGatewayService.ts). See the Mr.-Mentor-as-gateway notion inmasGateway.controller.ts. - TypeORM auto-sync.
synchronize: trueinsrc/config/database.ts— entity classes are the schema. 51+ entities registered in the DataSource. Pool: min 5 / max 20 connections (extraconfig). - Singletons.
DatabaseService,RedisService,QueueServiceare singletons constructed once inApp(src/app.ts). - Idempotent boot seeders.
src/index.tsruns 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 asMRLEARN_NEW_STUDENT_SYNC_ENABLEDand 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.tsverifies the JWT with HS256 and setsreq.userId;admin.middleware.ts,expert.middleware.ts,finance.middleware.ts,hrRole.middleware.ts,salesHeadPage.middleware.ts,batchLead.middleware.ts,isEnrolled.middleware.ts,vendorAuth.middleware.tsadd 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: truein 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 onCORS_ALLOWED_ORIGINS(a JSON array) plus a small hard-coded default list. Requests with noOrigin(curl, mobile) andOrigin: 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.
authMiddlewareverifies HS256 access tokens and setsreq.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-platformmulti-tenancy. Cross-product behaviour can vary by theX-Platformheader; the header is explicitly allow-listed in CORS and consumed byMasGatewayService. 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).
Related docs¶
- System Design & Architecture — deeper layering, scaling, security notes
- Architecture index
- Identity & access: identity-and-access
- Mentorship & meetings: mentorship-and-meetings
- Token economy: token-economy · mentor-earnings-and-payouts
- LMS: education-lms-courses · assessments-quizzes-assignments · student-portal-and-profile · student-engagement-gamification
- Mr. Hire: jobs-and-applications · ai-resume-screening · voice-interviews-and-ai-calling · talent-pool-and-salary
- Sales CRM: sales-crm-leads · assignment-workflow-targets · workflow-automation-engine
- Comms: telephony-exotel · whatsapp
- Finance: payments-finance-gst
- Integrations: integration-mr-learn
- Deployment: deployment guide
- API reference: endpoints
- Data model: database schema