Skip to content

Discrepancies & Open Questions

Part of the Aashray Technical Reference. This is the aggregated, backend-verified discrepancy log surfaced while auditing all three repos. Each item was found by reading actual backend/admin/app code on main — these are not guesses. Severity is informal: 🔴 security/data-integrity, 🟠 functional bug, 🟡 inconsistency/UX gap, ⚪ note.

Per-domain detail and code-level context live in the "Discrepancies" section of each domain's technical reference file (this directory); the paired business-logic files instead carry a short, plain-language "Known limitations today" note wherever a gap is genuinely user-visible. This page is the cross-cutting index across all domains so nothing gets lost, sorted by severity rather than by domain. Superseded/duplicated app-only findings from the app's own data-model/appendices documentation (Appendix E) are folded in here where the backend confirms or corrects them.


🔴 Security & auth

  1. No member session token. Client (/api/v1/* app-facing) endpoints are gated only by validateCard — a check that the supplied cardno exists in CardDb. There is no password/JWT check per request; possession of a 10-digit card number is effectively the bearer credential for that member's data. See 02, 01.
  2. POST /admin/auth/reset-password has no auth middleware. Any caller who knows an admin username can reset that admin's password — a privilege-escalation path. See 02.
  3. POST /razorpay/verifyPayment is a public, unauthenticated webhook with no signature verification. Anyone who can guess/construct the right JSON can mark a transaction paid and confirm a booking without ever paying. See 08.
  4. Shared default password. Every new CardDb row is created with the same hardcoded bcrypt hash, and the "reset to default" admin action resets a member back to that same, effectively public, password. See 02.
  5. Temporary password is only 5 alphanumeric characters (a code comment incorrectly claims special symbols are included) — weak for a credential sent over WhatsApp/email. See 02.
  6. fetchTotalTransactions builds SQL by string-interpolating cardno (flagged // TODO: FIX this in the code) — a SQL-injection surface. See 02.
  7. Several admin/public endpoints are intentionally unauthenticated (kiosk/scanner use cases) but worth a deliberate security review: POST /utsav/utsavCheckin, POST /utsav/issue/:cardno, the location admin router (missing authorizeRoles), and the short-link /go/:slug redirect. See 11, 07, 10.
  8. Admin RBAC is broad by designsuperAdmin is included in almost every route group's allow-list, and the panel's client-side roleCheck.js is cosmetic only (the real boundary is server-side authorizeRoles). Not a bug, but worth confirming matches intended least-privilege. See 11, 13.

🟠 Money, pricing & credits

  1. The app's constants/prices.js (₹400/600/315/120/80/50) is dead/stale. The backend's real base prices are NAC_ROOM_PRICE=700, AC_ROOM_PRICE=1100, BREAKFAST_PRICE=60, LUNCH_PRICE=120, DINNER_PRICE=120 (config/constants.js). See 13, 08.
  2. FoodRate DB table is never read or written — all food prices are hardcoded constants; there is no admin UI to change rates despite the table existing. See 05.
  3. Flats are always billed at the NAC room rate (₹700/night) — there is no dedicated flat tariff or AC/NAC distinction for flats, despite a code comment implying one should exist. See 04, 08.
  4. Guest flat booking can double-create a Razorpay order (bookFlat for guests omits the createOrder=false flag that the mumukshu path passes) and separately returns an amount already in paise that gets multiplied by 100 again at the controller — a likely charge-amount bug. See 03, 04.
  5. RoomBooking/FlatBooking have no amount column, yet status-update code writes one — Sequelize silently drops it. See 04.
  6. Refund/credit asymmetry: cancelling a paid room or flat booking always credits the member; cancelling travel or utsav does not auto-credit (only an admin-initiated credit does); adhyayan credit is neither previewed nor earned automatically. This is a real, user-visible inconsistency, not just a doc gap. See 04, 06, 07, 08.
  7. adjustAmount calls addCredit(user, …) but user is not an in-scope parameter — a latent ReferenceError in the admin re-price path. See 08.
  8. Country-casing bug: booking code compares country != 'India' while the auto-cancel cron filters on country = 'INDIA' — mismatched casing could mean some international-flagged cards are never auto-cancelled as expected (or vice versa). See 08.
  9. /api/v1/razorpay/pay (v1) rejects any food line item; /payv2 allows food when the category matches — the two payment endpoints behave inconsistently for the same booking type. See 08.
  10. Self-paid food transactions are created pending but food cannot be paid online — they only ever clear via cash payment or the 24h auto-cancel cron, an easy-to-miss dead-end state. See 05, 08.
  11. Guest self-paid meals aren't refunded on cancelcancelFood only reverses a transaction when bookedFor is set (an in-code FIXME confirms this is known). See 05.
  12. Reconciliation is fully manual (Excel upload) and cross-app "Satshrut" payments can only be recovered by parsing raw razorpay_webhook JSON — no structured link. See 08.
  13. Settlement schema has a misspelled column cerated_at that is relied on throughout; settled_by is written on reconciliation upsert but not declared on the model. See 08.

🟠 Booking engine, availability & waitlists

  1. The /api/v1/unified/* booking/validate routes are dead — they return HTTP 410. The real "unified" booking engine lives under /api/v1/guest and /api/v1/mumukshu. Per-type flat shortcuts (/stay/flat, /guest/flat) are marked deprecated but still function. See 03, 12.
  2. Admin bookings/cancel/:type only implements the room case — every other booking type falls through the switch to a 404; flat cancellation is handled by a separate endpoint entirely. See 03.
  3. Room waitlist is never auto-promoted (unlike adhyayan/utsav/travel, which do auto-promote on a cancellation/seat-open). A room's WL status appears not to clear automatically. See 04.
  4. Utsav seats are never auto-promoted from the waitlist eitheropenUtsavSeat only increments a counter (and only while the utsav is still open); cancelling from a closed utsav silently fails to restore a seat for anyone waiting. This is the mirror-image gap to #24. See 07.
  5. Travel waitlist logic appears dormant: booking creation always sets awaiting confirmation (never waiting) and reports waitingBookingCount: 0, yet promotion logic and a waiting column default still exist in the code — suggesting a half-migrated feature. Promotion, when it does run, matches only on the Research-Centre end + date, ignoring the specific city. See 06.
  6. Travel's Research-Centre XOR pairing rule is validated client-side and on /validate, but the actual create endpoint (bookTravelForMumukshus) never re-checks it — a client that skips validation could create an invalid pickup/drop pair. See 06.
  7. softDeleteShibir (adhyayan) orphans bookings — it flips the shibir to deleted and notifies registrants but never cancels or refunds their bookings. See 07.
  8. Free-adhyayan waitlisters get promoted to pending (with a ₹0 transaction) rather than being auto-confirmed. See 07.
  9. Block dates are enforced for room bookings but not for flats, and the overstay/late-checkout extension handler exists in code but its call site is commented out (dead feature). See 04.
  10. Three error constants are referenced but never imported in roomManagement.controller.js (ERR_INVALID_DATE, ERR_ROOM_FAILED_TO_BOOK, ERR_BOOKING_ALREADY_CANCELLED) — those branches throw a raw ReferenceError instead of a clean API error. See 04.
  11. pickupRC/dropRC admin travel filters are dead code — they query for the literal string 'RC', but the stored value is 'Research Centre', so these filters match zero rows. See 06.
  12. A cron routine to cancel unpaid past room/flat bookings exists in code but its call is commented out — only the 24-hour online-pending auto-cancel rule is actually active. See 13.

🟡 Content, data-model & UX inconsistencies

  1. The app's Credits card labels (Stay / Travel / Food / Utsav) don't match the "How to Use" modal copy (Room / Flat / Utsav / Guest Food) — a client-side copy inconsistency, not a backend issue. See the app's own data-model/appendices documentation, Appendix E.
  2. Flat credits fold into the same pool as Room credits (getCreditType: flat → room) — undocumented anywhere in the UI, so a member who cancels a paid flat booking sees the credit appear under "Stay," which may be surprising. See 04.
  3. Adhyayan feedback eligibility window is inconsistent between what's shown and what's enforced: the "Give Feedback" button's visibility counts 15 days from the shibir's end_date, but the backend's actual eligibility gate counts 15 days from start_date — despite the error copy saying "after the adhyayan ends." A parallel 8-vs-15-day mismatch exists for Utsav. See 07.
  4. Admin's Utsav feedback report always shows a blank "overall" rating — it reads a column overall_rating but the actual survey question id is event_rating. See 07.
  5. WiFi's advertised validity periods are fiction: the app/admin copy claims "permanent = 1 year," "temporary = 2 weeks + data limit," but the backend enforces no expiry and no data cap at all. wifi_pwd status semantics are also inverted (active = free/unclaimed, inactive = claimed) — a naming trap for anyone reading the code. See 09.
  6. deviceType is used in WiFi code but not declared on the permanent_wifi_codes model — likely an unmodeled/ad-hoc column. See 09.
  7. Support tickets have no admin surface at all. There is no admin route, controller, or panel page for support; tickets are effectively write-only from the member's side, the model has no status/response field, and the staff email notification is commented out in code. This is the single biggest functional gap found in the audit — members can submit a ticket that no one can ever see or resolve through the product. See 09.
  8. Maintenance eligibility only checks for a room check-in — flat and utsav guests can be locked out of filing a maintenance request even though they're on-site, because the eligibility check doesn't consider those booking types. See 09.
  9. Gate entry/exit is asymmetric: entry auto-checks-in both room and flat bookings; exit only auto-checks-out flat bookings, so a room-booked member's status can linger in checkedin after they've actually left. gateExit is also missing the null-guard that gateEntry has, a latent 500 on an unknown card. See 09.
  10. Push notifications are Expo (via expo-server-sdk), not raw Firebase/FCM as some client-side references imply — Firebase is only the underlying Android transport. See 10.
  11. Push token lifecycle has no refresh path: the Expo token is written once at login and cleared at logout; stale tokens from DeviceNotRegistered receipts are logged but never removed, and only one token is stored per card (last device wins). See 10.
  12. Default push-notification deep-link target is inconsistent between two code pathsNotificationService defaults to '/', while sendDualUserNotifications defaults to '/home'. See 10.
  13. The remote "force update" / app-config endpoint (GET /api/v1/updates?os=) is undocumented on the client side — it exists and is public, but there's no admin UI to manage updates rows, and "latest" is resolved by createdAt rather than a proper semantic-version comparison. See 10.
  14. Meal-count baseline state lives in a local file (last_meals_count.json) — not durable across restarts or multiple server instances, so a meal-count-changed WhatsApp alert can be silently skipped after a deploy. See 05, 10.
  15. /go/:slug short-link redirects are public and increment click_count on every hit, including bot/prefetch traffic, so click analytics are inflated; a disabled short link returns a bare 404 with no explanation. See 10.
  16. Admin's /admin/location routes are dead codeapp.js actually mounts the client location router at that admin path, so the parallel controllers/admin/location.* files are never reached. See 02, 12.
  17. Admin's updateCard guest-relationship write uses the wrong column names (referenceCardno/guestType/createdBy instead of the model's guest/type/updatedBy) and keys on the member's card rather than the guest's — so editing an existing guest card silently fails to update the relationship row, while creating a new one works correctly. See 02.
  18. Admin panel cardDetails.js calls PUT /admin/card/update/:cardno, but the backend route expects cardno in the request body, not the URL — this call would 404 as written. See 02.
  19. Admin's meal-count report page is broken: mealCount.js checks result.success, but the backend's getMealCountByMobile response never includes a success field, so every valid response renders as a failure in the UI. See 05.
  20. Inconsistent food-booking cutoff enforcement: the member-facing 11 AM cutoff is enforced only client-side (by the app's calendar); the general food-booking API itself enforces no such cutoff. The Smilestones-admin bulk-food tooling additionally uses two different cutoffs between its create (11 AM) and edit (8 PM) flows. See 05.
  21. No database-level uniqueness constraint on food_db (cardno, date) — the one-meal-record-per-day-per-meal-type invariant is enforced only in application code, not the schema. See 05.
  22. Route-prefix trap: the admin "Room Management" module is mounted at /api/v1/admin/stay, not /admin/room as its name would suggest — easy to mistrace when following the code. See 11.
  23. The smilestones admin folder is largely a stub — the smilesAdmin role's real working entry point is food/manageBulkFood.html, reached from the home menu rather than a dedicated Smilestones module. See 11.
  24. Non-ENUM statuses referenced in code: updateBookingStatus (travel) has branches for seats full cancel / wrong form cancel that would violate the declared travel_db.status ENUM if ever hit; the real cancellation path uses admin cancelled + a comments field instead. See 06.
  25. coordinator_bookingid on travel bookings is a plain string, not a declared foreign key, and the is_coordinator flag can only be toggled when a bus_group_id is also supplied in the same request. See 06.
  26. Attendance schema drift for long adhyayans: the legacy session_1..9 columns on ShibirAttendanceDb cannot represent a shibir longer than 9 sessions (~3 days); longer sessions are tracked only in the newer shibir_attendance_records table, so the two attendance sources can disagree for multi-day shibirs. See 07.
  27. Pagination off-by-one in FetchUpcoming (adhyayan/utsav browse list): offset = (page - 1) * (pageSize - 1) — subtly wrong page-size arithmetic that will cause overlapping or skipped items across pages. See 07.

⚪ Notes (not bugs, but worth knowing)

  1. Hardcoded operational recipients exist in several places: the WiFi low-code WhatsApp alert number, and the specific card numbers used for nightly meal-count notifications. Changing staff assignments currently requires a code deploy. See 09, 10.
  2. (Resolved) This documentation set went through two structural changes since it was first assembled — first consolidating a duplicated app-spec copy, then splitting every domain file into a business-logic/technical pair. Both rounds have been fully reconciled and link-checked; if you ever find a dangling [N](...) link, it's a new regression, not a leftover from either change.
  3. This holistic set treats main on each repo, read at audit time, as ground truth. Both aashray-admin and aashray-backend had active feature branches (feat/support-ticketing at the time of this audit) not yet merged to main — anything already fixed there (e.g., a support-admin surface, per finding #40) would not yet be reflected here. Re-run the relevant domain section after such branches merge.

Open questions for the product/eng team

  • Is the lack of a real member session token (#1) intentional (trusted-network assumption) or a genuine gap to close?
  • Should room and utsav gain waitlist auto-promotion (#24, #25) to match adhyayan/travel, or is manual admin promotion intended for those types?
  • Is the credit-on-cancel asymmetry (#14) a deliberate business rule (only stay-type bookings are refundable-as-credit) or an oversight to fix uniformly?
  • Does Support (#40) already have an admin surface on an in-progress branch (e.g. feat/support-ticketing), or is this genuinely unbuilt?
  • What are the intended WiFi validity/data-cap rules (#38) — should the backend actually enforce what the UI claims, or should the UI copy be corrected instead?