A MERN-stack web application built as part of a bachelor's thesis at the Norwegian University of Science and Technology (NTNU). PAI (Pedagogical Artificial Intelligence) is an AI-powered chatbot designed to support coding students through guided learning, accessibility awareness, and reduced cognitive load, rather than simply providing direct answers.
- Project overview
- Tech stack
- Project structure
- Getting started
- Scripts
- Features
- Models
- API routes
- Authors & credits
PAI is a chatbot prototype built to study the transfer effect of pedagogically tuned AI tools on web development students. It is built around Anthropic's Claude Sonnet 4 model and is designed to act as a pair-programmer and mentor, nudging users towards deeper understanding rather than dependency.
The project was developed as part of a study on AI-assisted learning, accessibility compliance, and the Zone of Proximal Development (ZPD). As part of this the bot is encourage to estimate the users level, and adapt accordingly.
With the newest system prompt it will also leave some accessibility labels blank so the users can fill them in themselves,
helping with hands on learning of accessibility. System prompts can be tweaked in backend/utils/systemPrompt.js.
- React 19 (Vite)
- React Router
- React Markdown + remark-gfm
- SCSS Modules (sass-embedded)
- Node.js + Express 5
- MongoDB + Mongoose
- Anthropic Claude API (
@anthropic-ai/sdk) - bcryptjs
- cors
- dotenv
/
├── frontend/ # React/Vite client
│ ├── src/
│ │ ├── assets/ # Global styles, colors, vectors, contexts
│ │ ├── components/ # React components (Chat, Login, Header, Footer, Buttons, etc.)
│ │ ├── App.jsx
│ │ └── main.jsx
│ ├── eslint.config.js
│ ├── index.html
│ ├── package.json
│ └── vite.config.js
│
├── backend/ # Node/Express server
│ ├── models/ # Mongoose models
│ ├── routes/ # Express routes
│ ├── utils/ # System prompt, prompt suggestions
│ ├── scripts/ # Seed scripts
│ ├── server.js
│ ├── .env # Backend environment variables (see below)
│ └── package.json
│
└── README.md
- Node.js (v18 or higher recommended)
- npm
- A MongoDB Atlas cluster (or local MongoDB instance)
- An Anthropic API key
- Can be obtained from platform.anthropic.com.
The backend requires one's own .env file. These are excluded from version control via .gitignore. Use the env-template.txt-file at the top level of the backend-folder for reference in filling this.
PORT=5000
MONGODB_URI= # Your MongoDB connection string
ANTHROPIC_API_KEY= # Your Anthropic API key (sk-ant-...)
ANTHROPIC_MODEL=claude-sonnet-4-20250514
Install dependencies for both the backend and frontend:
# Backend
cd backend
npm install
# Frontend
cd ../frontend
npm installBoth the backend and frontend need to be running simultaneously in separate terminals.
Note: For the backend to function properly, the MongoDB-connection must be set up and running too.
cd backend
npm run dev # Development mode with nodemon (auto-restart on changes)
# or
npm start # Production modecd frontend
npm run dev # Starts the Vite development serverThe frontend will be available at http://localhost:5173 by default, and the backend at http://localhost:5000.
| Command | Description |
|---|---|
npm start |
Start the server with Node |
npm run dev |
Start the server with nodemon (auto-restart) |
Located in backend/scripts/. Run from the backend folder.
Seeds a predefined set of named accounts (e.g. alice, bob) for development purposes.
node scripts/seed_accounts.jsSeeds numbered test user accounts (test_user_1 through test_user_20) for user testing sessions. Supports seeding, disabling, enabling, and deleting users.
node scripts/seed_test_users.js # Seed 5 users (default)
node scripts/seed_test_users.js 10 # Seed 10 users
node scripts/seed_test_users.js disable 4 # Soft-delete test_user_4
node scripts/seed_test_users.js disable 6-10 # Soft-delete test_user_6 through 10
node scripts/seed_test_users.js enable 4 # Re-enable test_user_4
node scripts/seed_test_users.js delete 4 # Hard-delete test_user_4 (requires confirmation)
node scripts/seed_test_users.js help # Show usage instructionsPassword logic: passwords are deterministic and derivable from the script. Animal cycles through dog, cat, bird, rabbit by user number, number = (userNumber * 5) - 2. Examples:
test_user_1→dog3test_user_2→cat8test_user_3→bird13
- Pedagogically tuned AI responses — custom system prompt designed around ZPD, productive struggle, and accessibility awareness
- Prompt suggestions (prompt chips) — AI-generated follow-up prompts displayed above the input field to reduce cognitive load and interaction cost
- Conversation memory — per-user conversation history stored in MongoDB and loaded on login
- Dark/light mode — theme toggle with system preference fallback for browser icon
- Login/logout — session-based authentication with bcrypt password hashing
- Token usage tracking —
tokenUsage,promptUse, andpresetPromptUsetracked per account - Responsive layout — fixed prompt input, scrollable chat, adaptive footer
Stores user accounts with hashed passwords and usage metrics.
| Field | Type | Description |
|---|---|---|
username |
String | Unique username |
password |
String | Bcrypt-hashed password (stripped from responses) |
isActive |
Boolean | Soft-delete flag |
tokenUsage |
Number | Total tokens used |
promptUse |
Number | Number of typed prompts |
presetPromptUse |
Number | Number of suggestion chip prompts |
Stores per-user conversation history.
| Field | Type | Description |
|---|---|---|
userId |
ObjectId | Reference to accountData |
messages |
Array | Array of { role, content } message objects |
Stores individual prompt/response pairs for analysis.
| Field | Type | Description |
|---|---|---|
prompt |
String | The user's prompt |
response |
String | The AI's response |
suggestions |
[String] | Generated prompt suggestions |
source |
String | typed or suggestion |
conversationId |
ObjectId | Reference to Conversation |
Developed by: Falke Brautaset, Jon Petter Ervik, Marius Sandvik Bjørnstad
Designed by: Martin Bergkvam Rognaldsen
Thanks to NTNU, Sujay Shalawadi and Kjell Are Refsvik for counseling, thanks to those who participated in user testing, thanks to our anonymous prototype interviewees, thanks to our classmates for inspiration, and thanks to all others who helped us.