Mr Hunter — your workplace climate interviewer. An AI that talks to employees about their day-to-day work, uncovers the obstacles that slow them down (tools, processes, workload, communication), and rewards them with points and trophies for participating.
- Overview
- Features
- Architecture
- Tech Stack
- Project Structure
- Getting Started
- Gamification
- Database Structure (Firebase Realtime Database)
- Roles & Super Users
- How the AI Interview Works
- Real-world Use Cases
- Current Limitations
- Roadmap
- Deployment
- Environment Variables
- Troubleshooting
- License
PainHunter is a workplace-climate platform. An employee creates an account, has an interview with Mr Hunter, and after every conversation the AI:
- Detects concrete obstacles: slow processes, missing tools or licenses, workload, friction between teams.
- Documents the employee's role: position, main tasks, tools they use and the areas they interact with, so leaders know what each person actually does.
- Extracts improvement notes (internal, visible only to the admin panel).
- Generates a conclusion and an actionable recommendation for the team lead.
Employees earn points and trophies per message and per conversation, keeping them engaged with the interview process.
An admin panel lets the leaders of each organization inspect the users, conversations, and AI-generated diagnoses from their own company.
The chat runs in the cloud through OpenRouter with free models. No local model is required.
- Workplace interview with Mr Hunter — an empathetic interviewer that asks one open question at a time about tools, processes, workload, communication and the employee's own role.
- Role documentation — Mr Hunter also asks about the position, main tasks, tools and areas each employee interacts with; the leader panel shows this per employee.
- Cloud AI (OpenRouter) — free models with automatic fallback if the primary model is unavailable.
- Voice transcription — audio messages transcribed in-browser with
transformers.js(Whisper), with a local FastAPI server as fallback. - Automatic improvement notes — the model emits structured notes (
###NOTAS###), hidden from the streaming chat and stored for the panel. - Obstacle detection —
es_dolorflag from AI decision plus keyword matching. - AI conclusion & recommendation — generated at the end of every conversation for the admin panel.
- Gamification — XP, footprints, levels, streaks and 12 trophies per conversation.
- Authentication — Firebase Auth (email/password) with registration.
- Realtime Database — users, organizations, conversations, gamification and roles in Firebase RTDB.
- Leader panel — the Líder role accesses the panel with stats and conversation inspection for its organization.
- Toast notifications with sound — reward notifications play
coins.mp3. - Landing page — official marketing page with hero, features, steps, testimonials and FAQ.
┌──────────────────────────┐ ┌───────────────────────────────┐
│ React + Vite (Netlify) │ HTTP │ OpenRouter API (cloud) │
│ │ ──────► │ /api/v1/chat/completions │
│ - Chat UI (SSE stream) │ SSE │ free models + fallback │
│ - Landing page │ ◄────── │ - chat stream │
│ - Admin panel │ │ - title │
└──────────────────────────┘ │ - conclusion (JSON) │
│ └───────────────────────────────┘
│ Firebase Auth + Realtime Database
▼
┌──────────────────────────┐
│ Firebase (cloud) │ Local (optional, fallback):
│ users / conversations / │ Python FastAPI on :8000
│ users / organizaciones /│ Python FastAPI on :8000
│ conversations / │ - /api/transcribe (Whisper)
│ notes │
└──────────────────────────┘
- The frontend talks to Firebase for auth and persistence.
- Chat, titles and conclusions are generated by OpenRouter in the cloud.
- Voice transcription runs in the browser first; if unavailable, it falls back to the local FastAPI server.
- Streaming responses carry structured notes parsed in real time and hidden from the user.
| Layer | Technology |
|---|---|
| Frontend | React 18, Vite 5, Tailwind CSS 3, React Router 6, Lucide icons |
| AI (cloud) | OpenRouter API, free models (google/gemma-4-31b-it:free) with fallback list |
| AI (local, fallback) | Python, FastAPI, faster-whisper |
| Voice (browser) | transformers.js + whisper-tiny |
| Data & Auth | Firebase Auth, Firebase Realtime Database |
| Deployment | Vite static build → Netlify (frontend only) |
PainHunter/
├── index.html # Metadata + social/OG tags
├── package.json
├── tailwind.config.js
├── vite.config.js
├── netlify.toml
├── favicon.ico # Project icon (local, not served)
├── LICENSE # MIT
├── .env # Frontend env vars (not committed)
├── public/
│ ├── favicon.png
│ ├── sounds/coins.mp3 # Reward notification sound
│ └── img/ # Logos and images
├── server/ # Optional local Whisper fallback
│ ├── app.py # FastAPI backend (transcribe)
│ ├── requirements.txt
│ ├── start-ai.bat
│ └── venv/ # Local virtual environment
└── src/
├── main.jsx # Routes and providers
├── firebase.js # Firebase initialization
├── index.css # Tailwind + custom animations
├── contexts/ # AuthContext, ToastContext
├── hooks/ # useChat, useGamification, usePageTitle, useReveal
├── services/ # openRouterService, chatService, adminService,
│ # gamificationService, whisperService, chatStorage
├── components/ # Chat, Sidebar, GamificationBar, Messages, ...
├── pages/ # LandingPage, AuthPage, AdminPanel
└── App.jsx # Main chat application
- Node.js 18+ and npm
- A Firebase project with Auth (email/password) and Realtime Database enabled
- An OpenRouter API key (free) at https://openrouter.ai/keys
git clone <your-repo-url>
cd PainHunterCreate a .env file in the project root:
VITE_FIREBASE_API_KEY=AIza...
VITE_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
VITE_FIREBASE_DATABASE_URL=https://your-project-default-rtdb.firebaseio.com
VITE_FIREBASE_PROJECT_ID=your-project
VITE_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=...
VITE_FIREBASE_APP_ID=1:...
# OpenRouter — used for chat, titles and conclusions.
VITE_OPENROUTER_API_KEY=sk-or-...
VITE_OPENROUTER_MODEL=google/gemma-4-31b-it:freenpm install
npm run devOpen http://localhost:5173 and you are ready to interview with Mr Hunter.
npm run buildThe static site is generated in the dist/ folder.
Progress is tracked per conversation under gamification/{uid}/{conversationId}:
| Action | XP | Footprints |
|---|---|---|
| Send a message | 10 | 1 |
| Share an obstacle (pain keyword) | +15 | +3 |
| Complete a conversation | +25 | — |
- Levels grow every
level * 100XP (level 1 = 100 XP, level 2 = 200, ...). - Trophies (12 total) unlock on milestones: first message, 10/50 messages, first/5 conversations, obstacles shared, levels, streaks and finishing your first interview.
- Reward notifications show a toast and play
public/sounds/coins.mp3.
pain-hunter-default-rtdb (europe-west1)
├── users/
│ └── {uid}/
│ ├── name: string
│ ├── gender: string
│ ├── organizacion: string # company the user belongs to
│ ├── cargo: string # job title / position (optional)
│ └── role: "empleado" | "lider" # role within the organization
├── organizaciones/
│ └── {orgKey}/
│ └── lideres: number # 0-2 leaders per organization
├── conversations/
│ └── {uid}/
│ └── {chatId}/
│ ├── title: string
│ ├── messages: [...]
│ ├── notas: [...] # improvement notes (panel only)
│ ├── conclusion: string
│ ├── resumenRol: string # summary of the employee's role (panel only)
│ ├── tareasPrincipales: [...] # main tasks (panel only)
│ ├── herramientas: [...] # tools / software used (panel only)
│ ├── interacciones: [...] # areas / roles they collaborate with (panel only)
│ ├── es_dolor: boolean
│ ├── recomendacion: string
│ ├── createdAt / updatedAt
└── gamification/
└── {uid}/
└── {conversationId}/
├── xp, huellas, messages, conversations, painNotes
├── trophies: { ... }
├── lastActiveDay, streak, bestStreak, conclusionDone
Security rules (summary)
- Regular users can only read/write their own
conversations/{uid}andgamification/{uid}nodes. - Users with
role: "lider"inusers/{uid}can readusers,conversationsandgamification. - Each leader only monitors employees from their own organization: the panel filters
usersandconversationsbyorganizacion. organizaciones/{orgKey}/liderescan only hold a value between 0 and 2 (DB validation rule).
| Role | Permissions |
|---|---|
| empleado (employee) | Accesses the Mr Hunter chat and their own gamification. |
| lider (leader) | Accesses the admin panel and monitors users from their same organization. |
- Registration asks you to choose a role: employee or leader.
- Each organization must have at least 1 leader and at most 2. Registering a third leader is rejected with "This organization already has 2 registered leaders."
- There is no separate access route: leaders and employees use the same login (
/login), and the app redirects according to the account role.
- The user starts an interview with Mr Hunter.
- Mr Hunter follows a structured method: opening → exploration → deepening (5 Whys) → motivation → closing, always in Spanish, 1–3 sentences, one question at a time. During the exploration he also asks about the employee's role (position, main tasks, tools, areas they interact with).
- When the user shares important details, the model appends
###NOTAS###followed by a JSON list. The stream parser hides everything after the marker from the chat and saves the notes for the panel. - The conclusion endpoint analyzes the messages and returns:
- conclusion — a short summary of the employee's situation,
- resumen_rol, tareas_principales, herramientas, interacciones — the role documentation extracted from the conversation,
- es_dolor —
trueif a real work obstacle was described (AI decision or keyword match), - recomendacion — an actionable recommendation.
- The AI is instructed to never mention internal notes, observations or registries to the employee — it only talks about the interview and the points earned.
┌─────────┐ ┌──────────────┐ ┌─────────┐ ┌──────────────┐ ┌─────────┐
│ Usuario │ ───► │ Mr Hunter │ ───► │ Notas │ ───► │ Conclusión │ ───► │ Panel │
│ │ chat│ (entrevista) │ │ (interna)│ │ y reco. │ │ (líder) │
└─────────┘ └──────────────┘ └─────────┘ └──────────────┘ └─────────┘
An employee talks to Mr Hunter → the AI detects obstacles and saves improvement notes → a conclusion and recommendation are generated → the organization's leader reviews everything in the panel.
PainHunter helps leadership detect early warnings in the team:
- Missing tools — employees who can't do their job because they lack software, licenses or access.
- Slow processes — bottlenecks in approvals, handoffs or communication between areas.
- Cross-team friction — recurring friction between departments that blocks delivery.
- Work overload — employees silently taking on more than they can handle.
With these signals, managers can act before small issues become turnover or burnout.
Be aware of the current constraints:
- Spanish only — the interview is designed and tested in Spanish.
- Depends on OpenRouter — chat quality and availability rely on the free models of the OpenRouter API.
- No dedicated backend — there is no owned backend service; persistence and auth live on Firebase and the AI on OpenRouter.
- No advanced dashboards yet — the panel offers stats and inspection, but no charts or trend analysis (see Roadmap).
Where PainHunter is heading:
- Dashboards with charts — visual metrics of obstacles per area.
- Trend analysis — evolution of pain points over time.
- Report export — PDF/CSV reports of diagnoses.
- Per-team metrics panel — KPIs by team or department.
- Automatic alerts — notify a leader when a serious obstacle is detected.
The frontend is a static Vite site and deploys to Netlify:
- Build command:
npm run build - Publish directory:
dist
Set the same VITE_* variables above as Netlify environment variables.
The optional local Whisper server (server/) is not deployed; browser transcription covers speech-to-text in production.
| Variable | Description |
|---|---|
VITE_FIREBASE_API_KEY |
Firebase Web API key |
VITE_FIREBASE_AUTH_DOMAIN |
Firebase Auth domain |
VITE_FIREBASE_DATABASE_URL |
Realtime Database URL |
VITE_FIREBASE_PROJECT_ID |
Firebase project ID |
VITE_FIREBASE_STORAGE_BUCKET |
Storage bucket |
VITE_FIREBASE_MESSAGING_SENDER_ID |
Sender ID |
VITE_FIREBASE_APP_ID |
App ID |
VITE_OPENROUTER_API_KEY |
OpenRouter API key for chat, titles and conclusions |
VITE_OPENROUTER_MODEL |
Free model to use (with automatic fallback list) |
All credentials are read from
.env(gitignored). Never commit real keys.
| Problem | Solution |
|---|---|
npm.ps1 is blocked on Windows PowerShell |
Use npm.cmd run dev instead of npm run dev |
| Chat says OpenRouter key is missing | Add VITE_OPENROUTER_API_KEY to .env and restart the dev server |
| Model answers slowly or errors | Switch VITE_OPENROUTER_MODEL to another free model; the app auto-falls-back |
Permission denied on database writes |
Check that the Firebase rules allow users to write their own conversations/{uid} node |
| Voice transcription fails in browser | Start the fallback server: cd server && python app.py (Whisper via FastAPI) |
Released under the MIT License.
