Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Nandini-13/PsycheIT/llms.txt

Use this file to discover all available pages before exploring further.

PsycheIT is intentionally minimal in its infrastructure footprint — two Node.js processes, no database, and a single-file backend — so that any college can self-host the platform without cloud vendor dependencies or operational complexity. Understanding the architecture helps you extend the classifier, add new routes, or replace the flat-file storage with a proper database when you are ready to scale.

High-Level Overview

PsycheIT runs as two independent processes that communicate over HTTP:
ProcessTechnologyDefault Port
FrontendVite dev server (development) / static build (production)5173
BackendExpress 5 on Node.js5000
The React frontend fetches data from the Express backend using standard fetch calls. CORS is enabled globally on the backend (cors() middleware), so both processes can run on different origins during development. In production you would typically serve the Vite build as static files from the same Express server or a CDN, and remove the open CORS policy.
Browser (http://localhost:5173)

        │  HTTP POST /classify
        │  HTTP POST /signup
        │  HTTP POST /login

Express Server (http://localhost:5000)

        ├─ natural.BayesClassifier  (in-memory, trained at startup)
        └─ users.json               (user credentials on disk)

Frontend Structure

The frontend is a React 19 single-page application bundled by Vite 7, styled with Tailwind CSS 4, and navigated with React Router v7.

Routes

All routes are declared in src/App.jsx. Two routes are public; every other route is wrapped in a ProtectedRoute component that checks for a valid JWT in localStorage before rendering.
PathComponentAccess
/HomePagePublic
/authAuthPublic
/dashboardStudentDashboardProtected
/chatbotChatbotProtected
/resourcesResourcesProtected
/blogs/:idBlogPageProtected
/forumPeerForumProtected
/bookBookingPageProtected
/screeningScreeningTestProtected

Authentication Guard

ProtectedRoute is a wrapper component that reads the token key from localStorage. If no token is present, the user is redirected to /auth. On successful login the backend returns a JWT which the frontend stores in localStorage under the key token.
// Simplified ProtectedRoute logic
const token = localStorage.getItem("token");
if (!token) return <Navigate to="/auth" />;
return children;
The StudentDashboard component decodes the JWT payload client-side (base64 decode of the middle segment) to extract and display the userId — no additional API call is required.

Backend Structure

The entire backend lives in a single file: server/server.js. It uses Express 5 with the body-parser and cors middleware, and exposes exactly three API endpoints.
server/
├── server.js        ← single entry point; all routes and classifier training
├── users.json       ← auto-created on first login; stores hashed credentials
└── package.json     ← ESM module, Express 5, natural, bcryptjs, jsonwebtoken

Endpoints

MethodPathAuth RequiredPurpose
POST/signupNoGenerate a userId and random password
POST/loginNoVerify credentials; issue JWT
POST/classifyNoRun NLP intent classification on a message
The /classify endpoint is currently unauthenticated, which is intentional for the chatbot’s first-contact use case. If you deploy publicly, consider adding rate-limiting middleware (e.g., express-rate-limit) to prevent abuse.

NLP Classifier

The chatbot’s intelligence comes from natural.BayesClassifier, a Naive Bayes text classifier from the natural.js library. The classifier is instantiated, trained with labelled documents, and kept in memory for the lifetime of the server process.

Training

Training happens once at server startup — synchronously, before any request is served. Approximately 20 labelled example documents are added per intent class:
const classifier = new natural.BayesClassifier();

// Anxiety intent
classifier.addDocument("I feel anxious and panic", "anxiety");
classifier.addDocument("I can't sleep at night", "sleep");
classifier.addDocument("I want to die", "highrisk");
classifier.addDocument("I feel sad all the time", "depression");
classifier.addDocument("I am stressed about exams", "academic");
// ... ~20 documents per intent

classifier.train();

Recognised Intents

The classifier recognises ten intent labels:
IntentExample trigger phrase
greeting”hi”, “hello”, “good morning”
academic”I am stressed about exams”
family”My parents keep fighting”
social”I feel lonely and left out”
sleep”I can’t sleep at night”
anxiety”I feel anxious and panic”
highrisk”I want to die”, “I don’t want to live”
depression”I feel sad all the time”
general”I feel okay”, “I’m doing good”
counselor”I need a counselor”, “I want therapy”

Classification Response

The /classify endpoint returns the top intent and the full sorted classification scores:
{
  "intent": "anxiety",
  "classifications": [
    { "label": "anxiety", "value": 0.18 },
    { "label": "academic", "value": 0.14 },
    { "label": "general", "value": 0.11 }
  ]
}
Only the top three scores are returned (.slice(0, 3)). The frontend chatbot uses the intent field to decide which canned response or follow-up action to show the student.

Authentication Flow

PsycheIT uses a deliberate two-step auth model to preserve anonymity — students never provide a username or email.

Step 1 — Sign Up

POST /signup accepts a collegeCode string and returns a generated userId and a random 8-character alphanumeric password. Nothing is persisted at this stage.
collegeCode: "SRMIST"

userId  = `${collegeCode}_${Date.now()}`   →  "SRMIST_1712345678901"
password = Math.random().toString(36).slice(-8)  →  "ab3xk9zq"

Step 2 — Log In

POST /login accepts { userId, password }. On first login the password is hashed with bcryptjs (salt rounds: 10) and the record { userId, hashedPassword } is written to users.json. On subsequent logins, bcrypt.compareSync is used to verify the plaintext password against the stored hash. If verification passes, a JWT is signed and returned:
const token = jwt.sign({ userId }, "secretKey", { expiresIn: "1h" });
The token payload contains only { userId, iat, exp }. The frontend stores it in localStorage and decodes the payload locally to display the user’s ID on the dashboard.
The JWT signing key is hardcoded as "secretKey" in the current source. Replace this with a strong, randomly generated secret stored in an environment variable (e.g., process.env.JWT_SECRET) before any public deployment. A leaked signing key allows anyone to forge valid tokens.

Data Storage

PsycheIT uses flat JSON files on disk instead of a database, keeping the setup to a single npm install. The backend manages one file for user credentials; the frontend bundles two additional JSON files for content.
FileLocationContentsCreated By
users.jsonserver/Array of { userId, password } objects (password is bcrypt hash)Auto-created on first /login call
PeerForum.jsonfrontend/src/PeerForum/Array of forum post objectsPre-seeded in the frontend bundle; read at runtime by the React app
resources.jsonfrontend/src/resourceHub/Array of resource/article objectsPre-seeded in the frontend bundle; read-only at runtime
Flat-file storage is suitable for a single-server development or pilot deployment. For a production environment serving multiple concurrent users, replace the loadUsers / saveUsers helpers in server.js with calls to a database (PostgreSQL, MongoDB, or similar) to avoid race conditions during concurrent writes.

Build docs developers (and LLMs) love