Skip to main content

Student App Guide

This guide covers the navigation, auth, and shell of the student app — feature behavior lives in Feature Flows.

App overview

The student app is a React + Vite + Capacitor build (dev port 5173) that ships as Android, iOS, and a web app from the same source. It serves two cohorts:

  • School students linked to a section — they get the full school surface (homework, attendance, diary, results, live class, bus, notice board, PTM).
  • Independent students — self-signups with no section; they get the AI tutor, syllabus browsing, prep tests, leaderboard, and the marketing surface, but school-specific tabs are empty or hidden.

Stack: Radix + Tailwind, Zustand for client state, TanStack React Query for server state, Markdown-it for rich content, Capacitor for native APIs (push, status bar, preferences). Like the other apps, layout is mobile-shaped (max-w-xl) even on desktop.

Three top-level zones: the public shell (/, /login/*, /register/*, /forgot-password/*), the authenticated app (everything under /dashboard/*), and utility pages (/404, /500, /maintenance, /blocked).

Bottom bar

Visible on most authenticated screens, with four tabs and a floating AI Tutor button:

TabPathState
Home/dashboardAlways active
School/dashboard/schoolSchool Hub — gateway to attendance, results, PTM, projects
My Plan/dashboard/plansDisabled in current build (greyed out, no nav)
More/dashboard/othersDisabled in current build
AI Tutor (FAB)/dashboard/ai-tutorFloating circular button centered above the bar

Active state matches the /dashboard Home only on exact /dashboard; everything else uses prefix-match.

School Hub (/dashboard/school)

A second-level hub for school features so the bottom bar can stay short. From here a student reaches /dashboard/school/attendance, /dashboard/school/results, /dashboard/school/ptm, and /dashboard/school/projects. Independent students should see this hub with most cards disabled or empty.

Dashboard landing (/dashboard)

Sticky header with a time-based greeting ("Good morning / afternoon / evening") + first name + 👋 emoji, a notifications bell with a small dot indicator, and a profile avatar shortcut. Below: a WelcomeBanner and an ExploreSection of feature cards (syllabus, prep test, group study, live class, leaderboard, etc).

Other authenticated routes

/dashboard/{notifications,profile,profile/edit,doubt,req-coin,req-credits,exams,notice-board,diary,bus,asignment,asignment-detail/:id,select-asignment/*,learning-journey/*,syllabus/*,my-plan,groupstudy/*,liveclass/*,prep-test/*,quick-test/*,class-test/*,chapter-test/*,results-detail/:examId,leaderboard,student-analytics,voice-interaction}. All gated by ProtectedRoute.

Public landing (/)

5-slide auto-playing marketing carousel (3.5s interval) with two CTAs: Login and Register. Unlike the teacher app, this page does not currently auto-redirect signed-in users — they have to tap "Login" to bounce through to /dashboard (worth verifying — see edge cases).

Authentication

Login (/login/*)

Single email + password form. Role is set to student in the request. On success: access + refresh token persisted, user identified to PostHog (id, email, role, name), navigate to /dashboard.

The password field has eye/eye-off toggle; "Forgot password?" sits inline with the password label and links to /forgot-password/request.

Register (/register/*)

Multi-step flow with an extra step versus the teacher app:

  1. /register/method — choose independent student vs school student (the index route renders this MethodSelectionStep).
  2. /register/email — email entry.
  3. /register/otp — OTP verification.
  4. /register/password — set password.
  5. /register/success — confirmation.

Independent students complete here; school students get linked to a section by their school admin separately.

Forgot password (/forgot-password/*)

ForgotPasswordWrapper mounts ForgotPasswordPage at the index and RequestPasswordResetPage at /forgot-password/request. Same shape as the teacher app: email submission → success state with mail icon, no in-app OTP, the reset link arrives by email.

Blocked state

/blocked (UserBlockedPage) shows the same suspended-account UI as the teacher app — ShieldX icon, "Access Restricted", Contact Support (mailto), and Logout. It's reached when the API flags the account as suspended.

Profile & settings

  • /dashboard/profile — top bar with back button, avatar + name + class/section, and action cards. Pulls from the user store first; falls back to a profile fetch on cold open. On 401 the page redirects to /login.
  • /dashboard/profile/edit — name, phone, profile picture. Picture upload follows the same flow as the teacher app.
  • No in-app password change screen in the current build — to change passwords, students go through /forgot-password/request and use the email link.

Error & utility pages

PathPurpose
/404 (and any unmatched route)Not-found
/500Server error fallback
/maintenanceGlobal maintenance screen with a reload CTA
/blockedSuspended-account screen

Unmatched routes redirect via <Navigate to="/404" replace />. Maintenance is shown when the global app-state flag is on.

Edge cases & things to test

  • Onboarding for signed-in user: open / with a valid persisted session — does the carousel auto-redirect to /dashboard, or does the user have to tap "Login"? Verify against the teacher app's behavior, which auto-redirects.
  • Independent vs school student dashboard: an independent student opens /dashboard/school — does the hub show graceful empty / disabled states for attendance, results, PTM, projects?
  • Disabled bottom-bar tabs: tapping "My Plan" or "More" should do nothing (no toast, no nav). Confirm with a screen reader that they announce as disabled.
  • AI Tutor FAB from /dashboard/school: tap it — it should go to /dashboard/ai-tutor, not get blocked by the school sub-route.
  • Hydration flicker: on cold native launch, the / carousel must not flash before the user-store rehydrates from Capacitor Preferences.
  • Greeting boundary: open the app at 11:59 / 12:00 / 16:59 / 17:00 — the greeting should flip ("Good morning" → "afternoon" → "evening").
  • Notification bell dot: the dot is currently a static visual; confirm whether it actually reflects unread state (it's not wired to the notification count in the current code path).
  • Push deep-link to /dashboard/asignment-detail/:id: kill the app, tap a homework-assigned push — verify it opens the detail screen, not just /dashboard.
  • 401 on profile fetch: simulate an expired refresh token — /dashboard/profile should redirect to /login, not show a broken loading state.
  • Maintenance during a quick test: flip maintenance on while a student is mid-test — what happens to their in-progress answers when they're bounced?
  • Independent student viewing /dashboard/notice-board or /dashboard/diary: should be empty (no school context), not a 500.
  • Profile picture upload — same file twice: re-upload the same image — should still update timestamps and refresh the avatar everywhere.