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.
Navigation & layout
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:
| Tab | Path | State |
|---|---|---|
| Home | /dashboard | Always active |
| School | /dashboard/school | School Hub — gateway to attendance, results, PTM, projects |
| My Plan | /dashboard/plans | Disabled in current build (greyed out, no nav) |
| More | /dashboard/others | Disabled in current build |
| AI Tutor (FAB) | /dashboard/ai-tutor | Floating 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:
/register/method— choose independent student vs school student (the index route renders thisMethodSelectionStep)./register/email— email entry./register/otp— OTP verification./register/password— set password./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/requestand use the email link.
Error & utility pages
| Path | Purpose |
|---|---|
/404 (and any unmatched route) | Not-found |
/500 | Server error fallback |
/maintenance | Global maintenance screen with a reload CTA |
/blocked | Suspended-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/profileshould 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-boardor/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.
Related
- Homework — the canonical feature flow
- Notifications
- Coins & Credits
- Diary