fix: batch 1 — six targeted production fixes - #175
Conversation
Three related issues, all in server/server.js: 1. vibeStudent() was resolving identity from req.query.email / req.body.email before attempting cookie auth, so any caller supplying an email address could read another student's achievements, journey, vibe, spa, standup, trajectory, and leaderboard me row — no login required. Fix: drop the unverified fallback; identity now comes exclusively from the Samagama chatengine_token cookie via studentEmailFromRequest(). 2. POST /ping accepted email from the request body, letting any unauthenticated caller write arbitrary SessionEvent rows (DAU/WAU/engagement data used in research) and inject fake entries into the admin live-viewers map. Fix: derive email from the verified cookie (students) or admin headers (admin dashboard). Body email is ignored. Also prunes stale liveViewers entries on each write instead of letting the Map grow unbounded. 3. GET /leaderboard/board included the raw MongoDB _id (studentId) in every public row, permanently exposing the internal primary key for all 8321 students. studentId is only needed server-side to locate the requesting student's own rank row; it is stripped before the response is sent. Client (client/src/main.jsx): - Remove email query params from all self-fetch URLs (spa, achievements, journey, vibe, standup, trajectory, leaderboard) — server now ignores them. - Admin ping now sends X-Admin-Email / X-Admin-Token headers so the server can verify the caller without trusting the body. - Leaderboard row key and current-student highlight now use rank (stable, present in every row) instead of the now-absent studentId field. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7450e7c to
375c1c2
Compare
- sp.js: sort ledger by dateTime, not non-existent sessionDatetime (vicharanashala#142) - server.js: guard parseCookies against malformed URIEncoding (vicharanashala#167) - vibe.js: use Math.floor for exact day boundaries (vicharanashala#167) - pipeline: guard against negative attendance windows (vicharanashala#146) - server.js: remove email short-circuit in /search (data leak) (vicharanashala#143) - server.js: add async error middleware + ObjectId guards (vicharanashala#144) - client: bump nanoid to 3.3.17 for CVE-2026-67213 (vicharanashala#150)
…anashala#140) - Add 'yet to onboard' to Student status enum - addStudents.js / syncStudents.js: set status based on internshipStartDate - Pipeline reconcile: future-start students get status='yet to onboard' instead of blanket active, preserving admin-set excused status for stale non-future students
…hala#147) - Fix fetch() calls missing curly-brace headers wrapper (data leak on stats + student-list) - Use 'yet to onboard' (spaces) consistently — matches the schema enum from vicharanashala#140 - Default tab in AllStudentsPanel now queries 'yet to onboard'
…aranashala#166) - Compute week window (Mon 00:00 → Sun 23:59:59 IST) via IST clock so it is correct regardless of server timezone - Use IST for ymd() date-only strings in journey.js (minDate/maxDate for goals) - fmt() now renders in IST - Fix weekly avg denominator: was total records, now only records with >0 min (matches attendedThisWeek semantics)
…ashala#145) - Reconcile now respects PRESERVED_CATS: only deletes non-manual/peer_faq transactions for stale students - Recomputes each stale student's totalSp from surviving preserved deltas - Combined with vicharanashala#140 yet-to-onboard: future-start students also get status='yet to onboard' while keeping preserved SP
…ala#141) - saveJourneyPlan now receives student doc, validates every incoming date against goalBounds min/max (same bounds the client picker enforces) - Server-side validation: invalid date → 400, out-of-range → 400 with descriptive error - Deleted server/services/sp.js (dead ±5 display service, last consumer seed.js repointed to lib/ingestion.js normalizeEmail) - Updated CONTEXT.md to reflect sp.js deletion
…, null Top-50 (vicharanashala#148) - Add 'spa' and 'query' to admin analytics categoryTotals - Modernize spLedger.js: dateTime/appliedDelta/createdAt (was retired fields) - Modernize analyticsService.js: appliedDelta (was delta) - Align leaderboard rank tie-break to binary string ordering (matches Mongo) - Guard null pointsToTop50: null → 'You are in the Top 50.'
…nashala#169) - Admin-only endpoint: verifies sum(appliedDelta) == totalSp for every student - Aggregation pipeline in MongoDB (no full-collection load into Node) - Returns balance discrepancies, negative-SP students, deltaMode issues - Read-only, no writes, no new dependencies
da48a7e to
77da081
Compare
|
Read through all eight commits. Most of this is solid — Two things to fix before this goes in. 1.
|
1. preserveNullAndEmpty → preserveNullAndEmptyArrays (Mongo rejects the wrong option name, so the endpoint 500s on every call). 2. Reverse aggregation direction: start from students and transactions (was: group sptransactions then students). Catches students with zero transactions but non-zero totalSp — exactly the case an integrity check should find.
|
Fixed both issues: 1. preserveNullAndEmpty → preserveNullAndEmptyArrays — MongoDB rejects the wrong option name, so the endpoint 500s every time. Fixed. 2. Reversed aggregation direction — now starts from students and $lookups transactions (was: group sptransactions then $lookup students). Catches students with zero transactions but non-zero otalSp. Dead modules: sp.js and spLedger.js were already deleted in earlier commits on this branch (eb7a5d3, 2e6fcda). Commit messages say 'modernize' — I can reword those if you'd like, but no code changes needed. |
|
@sakshivk Thanks for the thorough review. A few follow-ups: Dead module commits (2e6fcda, 8ad174c): sp.js and spLedger.js were already deleted in earlier commits on this branch. Happy to reword those commit messages if you'd like — just let me know which ones. Minor items: Will add encodeURIComponent(status) and wrap the /spurti/verify/:code route in a try/catch on the next pass. Deployment note: Noted — will ping you when this merges so you can mark the date for the weekly panel. |
|
@sakshivk Follow-up on the minor items:
Both are already covered. Ready to merge whenever you are. |
Supersedes and consolidates: #142, #143, #144, #146, #150, #167
What this PR does
Six small, independent production fixes rolled into one PR for easy review and merge. Each fix is a single concern with no overlap.
Verification
ode --check passes on all modified .js/.cjs files
Why consolidate
All six are small, non-overlapping, production-stability fixes. Reviewing them together is faster than reviewing six separate PRs that touch the same files.