Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Base URL of the EduNerve backend API (must include /api)
VITE_API_URL=http://localhost:3000/api
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: CI
on:
push:
branches: [main]
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
14 changes: 9 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
.env
.env.example

node_modules
dist
dist-ssr
*.local

# Environment variables (keep .env.example tracked)
.env
.env.*
!.env.example

# Editor directories and files
.vscode/*
!.vscode/extensions.json
Expand All @@ -22,5 +25,6 @@ dist-ssr
*.ntvs*
*.njsproj
*.sln
*.sw?
server/
*.sw?
coverage/
.impeccable
435 changes: 435 additions & 0 deletions DESIGN.md

Large diffs are not rendered by default.

147 changes: 147 additions & 0 deletions PRODUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Product

<!-- impeccable:product-schema 1 -->

## Platform

web

## Users

Early-career candidates preparing for software interviews on their own: students,
freshers, and engineers with up to roughly three years of experience. The user
signs up themselves, practices alone, and is usually working toward a specific
upcoming interview. Access is self-serve — the individual chooses the product and
pays for it; there is no institution or admin between them and the app.

Settings offers a wider experience range (Student / Fresher, 0–1, 1–3, 3–5, 5+
years), so later-career users are supported, but they are not who the product is
designed around.

## Product Purpose

Practice a spoken mock interview with an AI interviewer, then review a scored
report and track improvement across sessions.

One session is a live voice call: the user picks a target role, an interview type
and the technologies they want to be asked about, talks to the interviewer with
live captions, and ends with a report containing scores, strengths, areas to
improve, tips and the full transcript.

Success is a user who comes back — who runs interviews repeatedly and whose
scores rise over time. A single rehearsal is not the outcome; measurable
improvement is.

## Positioning

The interview is generated from the user's actual target role plus the specific
technologies they select, so the questions match the job being applied for rather
than coming from a generic bank. The backend exposes a role → technologies map,
and the user's selection is what configures the voice assistant for that session.

A neighboring product can offer voice practice or scored feedback. What it cannot
truthfully copy is that this interview was built around the stack the user named.

## Operating Context

- Runs in the browser and requires microphone permission. The app requests the
microphone **before** starting an interview, so a denied prompt costs nothing.
- One interview is a live voice call through Vapi, of a fixed length the backend
sets per session, with live captions as the user speaks.
- The flow is: setup (role, interview type, technologies) → live call → report.
Reports are reachable later from History.
- Interview types: `technical`, `behavioral`, `mixed`.
- Interview statuses: `completed`, `in_progress`, `abandoned`.
- Requires the separate EduNerve AI backend. The API shape — endpoints, error
codes and the score scale — is documented in that repository's
`API_CONTRACT.md`, not in this one.
- Deployed on Vercel; every route rewrites to `index.html` for client-side
routing.

## Capabilities and Constraints

**Scoring.** Scores run 0–10 on three axes — technical, communication, problem
solving — plus an overall score. Any of them can be null when AI evaluation did
not run; the UI must show that honestly rather than rendering a zero.

**The report** carries feedback prose, strengths, areas to improve, tips, and the
complete transcript.

**Dashboard** shows token balance, average score, interview counts, skills
tracked, a score trend across scored sessions, and recent interviews.

**History** filters by status and interview type and is cursor-paginated.

**Settings** covers profile (name, target role, experience level, up to 20
skills), token transaction history, password change, and account deletion.

**Auth.** JWT held in `localStorage` with the profile cached alongside it.
Specific session-expiry error codes force a logout.

**Tokens.** An interview costs 10 tokens. New accounts receive a signup grant. An
interview that ends before any answers are recorded is refunded automatically. An
admin adjustment reason exists in the ledger.

Tokens are intended as **paid credits**: users are meant to buy more when they run
out. **No purchase path exists in the product today** — there is no pricing, no
packs, no checkout, and the API exposes only balance and transaction history.
Until that is built, running out of tokens is a hard stop, and the product must
say so plainly rather than directing the user somewhere that cannot help them.
Prices, pack sizes and billing provider are **undecided and must not be
invented.**

**Mark attribution is session-level, and undecided beyond that.** The report
returns `strengths`, `weakAreas` and `aiAnalysis.notes` as flat arrays with no
reference to the transcript turn each one came from. The UI therefore presents
them as marks on the session as a whole, read against the conversation, and says
so on screen. Attaching a mark to the specific answer it refers to would require
the API to return a turn reference with each item — **an open backend contract
decision, not a frontend gap.** Until it is made, no surface may imply per-answer
attribution.

**Degraded AI.** AI feedback can be unavailable. The interview is still saved with
its transcript and no scores; this is a normal state, not an error.

**Error handling.** Failed requests throw `ApiError` with a stable `code`. Branch
on the code, never on message text.

**Terminology.** "Tokens" (not credits, coins or points). "Interview" (not quiz,
test or assessment). "Role" and "technologies" for the setup choices. "Report"
for the result.

## Brand Commitments

The product name is **EduNerve AI**. No other identity constraint, voice
guideline or reference has been confirmed by the user.

## Evidence on Hand

- `README.md` — features, local setup, scripts, backend contract pointer, deploy
notes. Accurate as of this record.
- The backend lives in a separate repository; `API_CONTRACT.md` is there, not
here.
- **No logo or wordmark asset is committed.** `public/logo.png` was removed and
the mark is currently a generic icon. Future work must not claim a brand asset
exists or reference a file that does not.
- The landing page currently states "7+ Job Roles", "40+ Technologies", "AI
Powered" and "24/7". These are UI copy, **not verified figures** — the real
counts come from the backend's options endpoint at runtime. Do not treat them
as confirmed numbers or repeat them as claims elsewhere.
- **No testimonials, customers, case studies, press, pricing, benchmarks or
usage statistics exist.** None may be fabricated.

## Product Principles

1. **The stack the user named is the product.** An interview that could have been
generated without knowing their role and technologies has failed its core
promise.
2. **Measure the same way every time.** One rubric across every session is what
makes progress real rather than anecdotal; changing what is measured breaks
the comparison the product exists to offer.
3. **Never charge for a session the user did not get.** Permission is requested
before tokens are spent, and an interview with no answers is refunded.
4. **The user's words survive the machinery.** A transcript is kept even when
scoring fails, because the recording of what they actually said is theirs.
5. **State the true situation, including when the product cannot help.** A dead
end described honestly is better than a cheerful nudge toward a screen that
resolves nothing.
110 changes: 33 additions & 77 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,92 +1,48 @@
# EduNerve AI Frontend

Welcome to the frontend repository for **EduNerve AI**, an intelligent, AI-powered educational platform designed to enhance the learning experience. This repository contains a modern React application built with Vite, featuring interactive dashboards, quizzes, and mock interview practice.
React 19 + Vite + Tailwind CSS 4 client for EduNerve AI: practice voice mock interviews with an AI interviewer (Vapi), then review scored feedback, transcripts and your progress.

## 🚀 Features
## Features

- **Interactive Dashboard:** Track learning progress with intuitive charts (powered by Recharts).
- **AI-Powered Assessments:**
- **Quiz Hub:** Take dynamic quizzes and review detailed results.
- **Interview Practice:** Participate in mock interviews with AI feedback (powered by Vapi AI).
- **Authentication:** Secure user login and signup, including Google OAuth integration.
- **Responsive UI:** Modern, accessible, and responsive styling built with Tailwind CSS and Radix UI components.
- **Smooth Animations:** Engaging user interfaces using Framer Motion.
- **Voice mock interviews** — pick a role, interview type and technologies; talk to the AI with live captions.
- **Interview report** — scores out of 10, strengths, areas to improve, tips and the full transcript.
- **Dashboard** — token balance, averages, score trend chart and recent interviews.
- **History** — filterable, paginated list of every interview.
- **Settings** — profile (role, experience, skills), token history, password change, account deletion.

## 🛠️ Tech Stack
## Run locally

- **Framework:** [React 19](https://react.dev/) + [Vite](https://vitejs.dev/)
- **Routing:** [React Router](https://reactrouter.com/)
- **Styling:** [Tailwind CSS v4](https://tailwindcss.com/)
- **UI Components:** [Radix UI](https://www.radix-ui.com/), [Lucide React](https://lucide.dev/) (Icons)
- **Animations:** [Framer Motion](https://www.framer.com/motion/)
- **Data Visualization:** [Recharts](https://recharts.org/)
- **Auth:** [React Google OAuth](https://github.com/MomenSherif/react-oauth)

## 📁 Project Structure

```text
src/
├── assets/ # Static assets (images, icons)
├── components/ # Reusable UI components
│ ├── common/ # Generic buttons, inputs, badges, etc.
│ ├── dashboard/ # Dashboard specific widgets (Stats, Cards)
│ ├── layout/ # Navbar, Sidebar, Page Layouts
│ ├── quiz/ # Quiz taking and result views
│ └── ui/ # Core component primitives (shadcn-like)
├── context/ # React Context for state management
├── data/ # Mock data and structural content
├── lib/ # Utility functions and API clients
└── pages/ # Main route components (Home, Login, Dashboard, etc.)
```bash
npm install
cp .env.example .env # VITE_API_URL must point at the backend, including /api
npm run dev
```

## ⚙️ Getting Started

### Prerequisites

- Node.js (v18 or higher recommended)
- npm or yarn

### Installation

1. **Clone the repository:**

```bash
git clone https://github.com/NSTKrishna/EduNerve_AI_Frontend.git
cd EduNerve_AI_Frontend
```

2. **Install dependencies:**
Needs the [backend](https://github.com/khuswant18/EduNerve_AI_Backend) running (default `http://localhost:3000`). Allow microphone access when starting an interview.

```bash
npm install
```
| Script | |
|---|---|
| `npm run dev` | Dev server |
| `npm run build` | Production build into `dist/` |
| `npm run lint` | ESLint |
| `npm test` | Vitest |

3. **Environment Setup:**
Create a `.env` file in the root directory and add your required environment variables (e.g., Google OAuth App ID, Vapi API keys, backend API URLs).
## Project layout

4. **Start the development server:**

```bash
npm run dev
```

5. **Build for production:**

```bash
npm run build
```

## 📜 Scripts

- `npm run dev`: Starts the local development server.
- `npm run build`: Bundles the app for production.
- `npm run preview`: Previews the production build locally.
- `npm run lint`: Runs ESLint to check for code quality issues.
```
src/
├── lib/api.js # the only place that calls the backend (ApiError, typed endpoints)
├── lib/format.js # score / duration / date formatting (scores are 0-10)
├── context/ # auth + token balance (LearnerContext)
├── hooks/ # useVapiInterview (call + transcript + submit), useAsync
├── pages/ # Landing, Login, SignUp, Dashboard, Interview, Report, History, Settings
└── components/ # layout, interview/, dashboard/, common/, ui/
```

## 🤝 Contributing
## Backend contract

Contributions are welcome! Please feel free to submit a Pull Request.
The API shape (endpoints, error codes, score scale) is documented in the backend repo's `API_CONTRACT.md`. Failed requests throw `ApiError` with a stable `code`; switch on that, never on the message text.

## 📄 License
## Deploy

This project is licensed under the MIT License.
Vercel: set `VITE_API_URL` to the deployed backend URL (ending in `/api`). `vercel.json` rewrites every route to `index.html` for client-side routing. Add the deployed origin to the backend's `CORS_ORIGINS` if it isn't `*.vercel.app` for this project.
40 changes: 38 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,47 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<!-- Paper sheet, red margin rule, ink E: the worked example in 48px. -->
<link
rel="icon"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><rect width=%22100%22 height=%22100%22 rx=%2220%22 fill=%22%23fbf7ef%22/><rect x=%2224%22 y=%220%22 width=%222%22 height=%22100%22 fill=%22%23b8311a%22/><text x=%2262%22 y=%2272%22 font-size=%2266%22 font-family=%22Georgia,serif%22 font-weight=%22600%22 text-anchor=%22middle%22 fill=%22%231a1612%22>E</text></svg>"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="Practice a spoken mock interview built from your role and your stack, then read it back marked up."
/>
<meta name="color-scheme" content="light dark" />
<meta http-equiv="Cross-Origin-Opener-Policy" content="same-origin-allow-popups" />
<meta http-equiv="Cross-Origin-Embedder-Policy" content="unsafe-none" />
<title>EduNerve AI - Learn Smarter</title>

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<!-- Bricolage Grotesque carries the display voice; Geist does the UI work;
Geist Mono is reserved for measurement. -->
<link
href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400..800&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap"
rel="stylesheet"
/>

<title>EduNerve AI — mock interviews, marked up</title>

<!-- Applies the saved theme before first paint so a dark-mode user never
sees a flash of paper. Mirrors src/context/ThemeContext.jsx. -->
<script>
(function () {
try {
var saved = localStorage.getItem("edunerve-theme");
var dark =
saved === "dark" ||
(saved !== "light" &&
window.matchMedia("(prefers-color-scheme: dark)").matches);
if (dark) document.documentElement.classList.add("dark");
} catch (e) {
/* blocked storage: fall through to paper */
}
})();
</script>
</head>
<body>
<div id="root"></div>
Expand Down
Loading
Loading