Feature #174
openTask list
0%
Description
1. Free vs Premium course segments — tag each exam/course FREE or PREMIUM; show badges + a filter on Practice Hub; Freemium users can open Free only, Premium needs a paid plan.
2. M9 Pricing models (Gantt W9) — surface Freemium / Monthly / Quarterly / Annual / Enterprise on candidate profile + Admin User Management (field already exists; it is not shown or enforced on courses).
3. M9 Access gate — reuse the existing paid-test check in AssessmentService so Premium PYQ / mock / test-paper routes respect plan; leave Razorpay as the current stub.
4. M5 Negative / partial / bonus scoring (Gantt W9) — negativeMarks is stored on questions; wire it into server grading and add partial + bonus fields for MCQ / multi-correct.
5. M4 Auto-save + attempt audit log (Gantt W9) — confirm CBT auto-save still works after the Practice Hub/PYQ changes; add a simple attempt audit trail (save / submit / tab-leave).
6. M7 Faculty vs candidate listing (Gantt W9, thin) — Admin User Management: filter/list Faculty and Candidates separately (roles already exist; no full institution tenant work).
7. Catalog consistency — keep the new exam-category cards (Engineering / Medical / MBA / …) and apply Free/Premium on those same cards in ExamTicketCard.tsx.
Updated by Ayush Yadav on 09/03/2026 10:56 AM
- Tracker changed from Bug to Task
- Status changed from Default to New
Ayush Yadav wrote:
1. Free vs Premium course segments
What this is. Practice Hub today groups exams by stream only (Engineering, Medical, MBA, CUET, Boards, UPSC). A second axis is missing: which exams a Freemium user may open for free, and which need a paid plan. That is the extra product point you asked to add on Redmine — it is not a named Gantt row, but it is the catalog half of M9 Freemium.
What exists. streamExams.ts and PracticeHome.tsx cards have id, name, years, subjects, category only. ExamTicketCard.tsx has no badge. Users already have subscriptionPlan defaulting to FREEMIUM in Users.java. Tests have a separate paid flag — that is per-mock, not per-exam in the catalog.
What we will do.
Add tier: "free" | "premium" on StreamExam (and on courses.ts so syllabus pages stay consistent).
Tag a first cut: flagship exams (JEE Main, JEE Advanced, NEET, CAT) as premium; the rest (state CETs, AIIMS archive, JIPMAT, CUET, NTA Abhyas, etc.) as free unless you later change the mix.
Practice Hub: All / Free / Premium filter plus a badge on each ticket.
Freemium (or logged-out) users can open Free exams. Opening Premium shows a plan wall, not the PYQ workspace.
2. M9 Pricing models (Gantt W9)
What this is. The Gantt W9 row: “Pricing Models: Freemium, Monthly, Quarterly, Annual, Enterprise License.” The column already exists on the user. Nobody can see or change it in the UI except indirectly: a stub payment hard-sets the user to MONTHLY.
What exists.
Allowed values in Users.java: FREEMIUM | MONTHLY | QUARTERLY | ANNUAL | ENTERPRISE.
Returned on sign-in via UserResponse and stored on teamtalks_user in auth.ts.
Candidate2.tsx never shows the plan.
UserManagementPanel.tsx has no plan field and no admin API to set it.
PaymentService.verify() always writes MONTHLY.
What we will do.
Candidate: show current plan (read-only) on the profile / header area after login.
Admin: table column + dropdown to set plan (PUT /admin/users/{id}/subscription or an extra field on an existing admin update). Roles stay as they are.
Do not build a public pricing page or live checkout. Razorpay stays the current stub. Optionally stop hard-coding MONTHLY on verify and let admin-assigned plans be the source of truth for this week.
3. M9 Access gate
What this is. Task 1 is the label. This task is the lock. Premium catalog items and paid official mocks must respect the same plan idea.
What exists. Only published tests are gated, and only when starting via /attempts/start:
private void assertPaid(Users user, AssessmentTest test) {
if (!Boolean.TRUE.equals(test.getPaid())) {
return;
}
if ("FREEMIUM".equalsIgnoreCase(...) && !paymentService.hasPaid(...)) {
throw new RuntimeException("This mock requires a paid plan...");
}
}
Non-FREEMIUM plans skip the check. Practice Hub PYQ / chapter open in PracticeHome.tsx never calls this — JEE chapters load through jeeMainApi.ts with no plan check. CAT goes to /syllabus/cat with no gate.
What we will do.
Shared helper: isPaidPlan(subscriptionPlan) is true for Monthly / Quarterly / Annual / Enterprise (not Freemium).
Frontend: before openExamWorkspace / handleChapterPick / CAT syllabus, if tier === "premium" and the user is not on a paid plan, show the wall (sign-in or upgrade). Do not navigate.
Backend: keep assertPaid for authored paid tests. If we add a premium-exam query later, reuse the same helper — this week the Practice Hub gate is client-side plus the existing test gate. Do not wire live Razorpay.
4. M5 Negative / partial / bonus scoring
What this is. Gantt W9: “Scoring Engine: Negative Marks, Partial Marking, Bonus Marks.” Official tests that go through AssessmentService.evaluate() should apply those three rules. Practice.tsx local +1 scoring is a separate demo path — we do not replace every local quiz this week.
What exists in AssessmentService.gradeObjective():
Negative: wrong SINGLE_MCQ / NUMERICAL / MULTI_MCQ subtracts TestQuestion.negativeMarks. Empty answer = 0 (no penalty).
Partial: only MULTI_MCQ — if no wrong option is selected, score is marks * (right / expected).
Bonus: missing. No field on ExamQuestionBase or TestQuestion.
Frontend Practice.tsx still scores +1 / 0 locally and never calls /attempts.
What we will do.
Add bonusMarks (default 0) on bank question + test snapshot; copy it in snapshot() like negativeMarks.
On a fully correct objective answer, add marks + bonusMarks.
Keep existing negative and MULTI_MCQ partial behavior; expose bonusMarks on admin/authoring if the question form already edits marks.
Do not build formula/range extras beyond the numerical tolerance already there.
5. M4 Auto-save + attempt audit log
What this is. Gantt W9: “Auto-Save & Comprehensive Audit Logging.” The backend already has save/submit. The candidate CBT screens do not call them, and there is no event history (only lastSavedAt and a tabSwitchCount integer).
What exists.
API: POST /attempts/start, PUT /attempts/{id}/answers, POST /attempts/{id}/submit in AttemptController. Save writes answers + lastSavedAt + optional tabSwitchCount.
No UI in Practice.tsx, CAT quizzes, or Assesment.tsx calls those endpoints. Admin Examiner/Reports only read attempts.
Tab-switch in Assesment / QuizExamShell is local (reset + modal). It never posts an audit row.
What we will do.
Thin attempt_audit (or equivalent) events: SAVE, SUBMIT, TAB_LEAVE with attempt id, user id, timestamp.
On save() and submit(), write an event. Accept TAB_LEAVE from the save payload or a tiny extra field.
Wire one official CBT path (the assessment attempt UI that already has a test id) to start → debounced save → submit, and send tab-leave. Then confirm Practice Hub chapter → Practice.tsx did not break (local path can stay if it has no testId).
Resume IN_PROGRESS if start already returns it.
6. M7 Faculty vs candidate listing (thin)
What this is. Gantt W9: “Faculty & Candidate Management” — a list split only. Not multi-institution tenants, batches, or a new Faculty portal.
What exists. UserManagementPanel.tsx filters by search, role dropdown, and banned. Roles include Candidate, Examiner, Author, Reviewer, Test Admin, etc. There is no Faculty role in ALLOWED_ROLES. No “Candidates only” / “Faculty only” preset.
What we will do.
Treat faculty as staff roles already in the system: Examiner, Author, Reviewer, Test Admin, Institution Admin (not a new role unless you insist on the word Faculty).
Treat candidates as Candidate / USER.
Add two preset chips or a Type filter: All / Candidates / Faculty. Reuse GET /admin/users?role= or filter client-side from the existing search.
No new institution tables.
7.Catalog consistency (ExamTicketCard)
What this is. Tasks 1–3 must not fork a second card design. The Engineering / Medical / … grid stays. Free/Premium is an extra chip on the same ticket.
What exists. PracticeHome.tsx still uses ExamCategoryCard then ExamTicketCard (code, name, description, meta, actionLabel).
What we will do.
Add optional tier (and maybe locked) to ExamTicketCard.
Badge + disabled/lock styling when Freemium hits Premium.
Stream category cards unchanged (they are folders, not sellable items).
Updated by Ayush Yadav on 09/03/2026 10:57 AM
- Tracker changed from Task to Feature