Skip to content

Architecture & Data Model — Technical Reference

Part of the Aashray Technical Reference. Pairs with Business Logic — Architecture & Data Model, which describes the repos, the shared membership-record pattern, and the three access tiers in plain terms with no code detail. This file covers the same ground for engineers: the exact stack per repo, the Express middleware chain, every route-mount base path, the full entity-relationship map with table/model names, and the one known security defect in the member auth model.

This file is 100% derived from reading the backend, admin, and app source on main — no operational/staff-knowledge content lives here (that's in the business-logic companion, and there is none for this particular file). It is the backbone every other technical file assumes: the repos, the request lifecycle, the three authentication realms, and the complete data model with its relationships.

Verification status: audited & anchored per docs/DOCS-METHODOLOGY.md on 2026-07-07 against aashray-backend main. Every rule below carries a [src: …] anchor pointing at the code that proves it; re-audit by re-checking those anchors.


1. The three repos and how they connect

Repo Stack Role
aashray-backend Node.js, Express, Sequelize ORM (MySQL), node-cron, Razorpay, FCM, nodemailer, WhatsApp The API + business logic + database + scheduled jobs + integrations. Source of truth.
aashray-app Expo SDK 56 / React Native The member client. Calls the backend's client, stay, food, travel, adhyayan, utsav, guest, mumukshu, razorpay, profile, wifi, maintenance, support, location, updates route groups.
aashray-admin Vanilla JS / HTML (multi-page) The staff client. Calls the backend's admin/*, coordinator, and short-links route groups.

The two front-ends never talk to each other or to the database directly — everything goes through the backend API. When the app and admin appear to disagree about behavior, the backend controller is authoritative. [src: aashray-backend/package.json; app.js:1-57 (route imports name the client vs admin groups)]


2. Backend request lifecycle

app.js builds one Express app: - Middleware order: urlencoded + json body parsing → cors (currently origin: '*', credentials on) → httpLogger (Winston HTTP logging with per-request context) → express-session (cookie, 24h maxAge: 86400000) → routers → 404 (throw ApiError(404,'Page Not Found')) → ErrorHandler (central error middleware that shapes all error responses). [src: app.js:106-118; app.js:206-210] - On boot (non-test): sequelize.authenticate()sequelize.sync() (auto-creates tables) → connection-pool warm-up → a connectionMonitor. Graceful shutdown on SIGTERM/SIGINT and uncaught errors. [src: app.js:65-92; app.js:219-260] - Health/util endpoints: GET /api (liveness), GET /api/health (DB + pool status). [src: app.js:120-161] - Success responses are wrapped as { data, status }; errors flow through ErrorHandler (this is why the app's API wrapper reads res.data.message on failure).

Route groups & base paths (from app.js)

Client (member app) — all under /api/v1/: [src: app.js:164-203]

Base path Router Domain file
/client auth 02
/profile profile 02
/location location (countries/states/cities) 02
/stay room + flat booking 04
/food food booking 05
/travel travel booking 06
/adhyayan adhyayan booking 07
/utsav utsav booking 07
/guest, /mumukshu, /unified booking on behalf of others / unified engine 03
/razorpay payments 08
/wifi wifi codes 09
/maintenance maintenance requests 09
/support support tickets 09
/updates remote app config / version 10

Admin (staff) — under /api/v1/admin/: sudo (adminControls), auth, adhyayan, card, food, gate, stay, travel, accounts, maintenance, bookings, location, utsav, avt, wifi. Plus /api/v1/coordinator (coordinator auth), /api/v1/short-links, and / (public short-link redirect). See Admin Panel Map and API Reference. [src: app.js:180-198]

Note: /api/v1/admin/utsav mounts two routers — a public one (no auth, so the app/anyone can read utsav+package data) and an auth-protected admin one. This is why utsav browsing works without admin login. [src: app.js:192-193]


3. The three authentication realms

  1. Member (client) — the app user. Logs in with phone + password (/client/verifyAndLogin), which returns the member record. ⚠️ There is no member session token. Client endpoints are gated only by a validateCard check that the supplied cardno exists in CardDb — so possession of a card number is effectively the credential (a real security gap; see Discrepancies, below). The token column on the card stores the Expo push token, not a session. No public signup; accounts are pre-issued. [src: middleware/validate.js:10-13] See 02.
  2. Admin (staff) — the admin panel user. Authenticates via /admin/auth, receives a JWT signed with process.env.SECRET. middleware/AdminAuth.js verifies the Bearer token, loads the AdminUsers record by id + username, and rejects it if status === STATUS_INACTIVE (an account is denied when explicitly inactive, not required to be explicitly active). It then attaches the user's active role names — read straight from AdminRoles.role_name where status = active — to req.roles. Individual admin routes are gated with authorizeRoles(...roleNames), which allows the request if the user holds any of the listed roles (roles.some(...)). This is the RBAC system. [src: middleware/AdminAuth.js:8-48] See Admin Panel Map.
  3. Coordinator — a limited operational role (e.g., travel bus coordinators) authenticated by OTP (/api/v1/coordinator, coordinatorOtp model, sendCoordinatorOtp helper). [src: helpers/sendCoordinatorOtp.js; app.js:196] See 06.

Plus public (no auth) endpoints: the utsav public router, the short-link redirect (/), and health checks.


4. The data model (the connective map)

The hub: CardDb

Every member is a card (CardDb, keyed by cardno). Almost every other table hangs off it. The single most important pattern:

Bookings carry two card references: cardno (whose booking this is — the beneficiary) and bookedBy (who created it). When they're equal it's a self-booking; when different, someone booked on behalf of a guest or mumukshu. This one pattern is what powers the entire self / guest / mumukshu system across rooms, flats, food, travel, adhyayan, and utsav.

Entity groups (all Sequelize models, from models/associations.js) [src: models/associations.js]

  • Identity & access: CardDb (members), GuestDb + GuestRelationship (guests a member brings), AdminUsers + AdminRoles + Roles (staff RBAC), coordinatorOtp (coordinator login), CountriesStatesCities (location cascade), CentreDb (centres).
  • Stay: RoomDb (rooms) → RoomBooking; FlatDb (flats, with owner → CardDb) → FlatBooking; BlockDates (dates blocked from booking).
  • Food: FoodDb (per-meal bookings), BulkFoodBooking, FoodPhysicalPlate (issued plates), FoodRate (pricing), Menu.
  • Travel: TravelDb (bookings) → grouped by staff into TravelBusGroupTravelBusPassengers + TravelBusStops.
  • Adhyayan: ShibirDb (sessions/shibirs) → ShibirBookingDbShibirAttendanceDb / ShibirAttendanceRecord; ShibirSession (session breakdown); AdhyayanFeedback.
  • Utsav: UtsavDbUtsavPackagesDb (ticket packages) + UtsavBooking; UtsavFeedbackUtsavFeedbackAnswer.
  • Money: Transactions (one per chargeable booking, linked by bookingid), RazorpayWebhook, RazorpaySettlement, RazorpaySettlementRecon.
  • Services: WifiDb (temporary) + PermanentWifiCodes; MaintenanceDb + Departments; SupportTickets; GateRecord (entry/exit scans).
  • Config & misc: Updates (remote app config/version), ShortLink (short-link/redirect service), Menu (also staff-managed).

Key relationships (the connections)

graph TD
  Card[CardDb / cardno — the hub]
  Card -->|cardno + bookedBy| Room[RoomBooking]
  Card -->|cardno + bookedBy| Flat[FlatBooking]
  Card -->|cardno + bookedBy| Food[FoodDb]
  Card -->|cardno + bookedBy| Travel[TravelDb]
  Card -->|cardno + bookedBy| Shibir[ShibirBookingDb]
  Card -->|cardno + bookedBy| Utsav[UtsavBooking]
  Card --> Guest[GuestDb + GuestRelationship]
  Card --> Txn[Transactions]
  Card --> Wifi[WifiDb / PermanentWifiCodes]
  Card --> Maint[MaintenanceDb]
  Card --> Support[SupportTickets]
  Card --> Gate[GateRecord]
  Card --> AFb[AdhyayanFeedback]
  Card --> UFb[UtsavFeedback]

  Room -->|bookingid| Txn
  Flat -->|bookingid| Txn
  RoomDb[RoomDb] -->|roomno| Room
  FlatDb[FlatDb owner→Card] -->|flatno| Flat

  ShibirDb[ShibirDb] --> Shibir
  ShibirDb --> Sess[ShibirSession]
  Shibir --> Att[ShibirAttendanceRecord/Db]
  ShibirDb --> AFb

  UtsavDb[UtsavDb] --> Utsav
  UtsavDb --> Pkg[UtsavPackagesDb]
  Pkg --> Utsav
  UtsavDb --> UFb
  UFb --> UFbA[UtsavFeedbackAnswer]

  TravelDb2[TravelBusGroup] --> Pass[TravelBusPassengers]
  TravelDb2 --> Stops[TravelBusStops]

  Maint --> Dept[Departments]
  Admin[AdminUsers] --> ARoles[AdminRoles] --> Roles[Roles]
  Countries --> States --> Cities

Notes that matter for "how things connect": - Transactions attach to a booking via bookingid and to a member via cardno. Only RoomBooking/FlatBooking declare the explicit hasMany Transactions association, but transactions exist for every chargeable booking type (see 08). - Feedback is tied to both the event (ShibirDb/UtsavDb) and the member (CardDb); utsav feedback has child answers rows. - Attendance links a member + a shibir + a specific booking (bookingid) — enabling per-session attendance capture (see 07). - onDelete: CASCADE is set on most card→booking relations, so deleting a card cascades to its bookings/records (a data-integrity note).


5. Cross-cutting infrastructure

  • Payments (Razorpay): order creation → checkout in the app → webhook capture → settlement + reconciliation records. Charges/credits are computed server-side. Full detail in 08.
  • Scheduled jobs (cron.js): the most important is the 24-hour auto-cancel of unpaid pending bookings — MAX_APP_PAYMENT_DURATION = 24 * 60 minutes, defined in cron.js itself (not config/constants.js); the job runs every 30 minutes (*/30 * * * *) and cancels bookings whose payment window has elapsed, which on cancel re-opens seats (adhyayan/utsav), promotes waitlisted travel, and emails/WhatsApps status changes. Also meal-count notification jobs at 21:00/22:00/23:00 and a wifi low-capacity alert every 30 min. Full list in 13. [src: cron.js:38; cron.js:43; cron.js:142; cron.js:286-330]
  • Notifications: push (FCM/Expo token captured at login), transactional email (mailer.helper + emails/ templates), and WhatsApp (whatsapp.helper — status-change messages, tomorrow's meal count). Detail in 10.
  • Remote config / updates: /updates serves app version/config flags (force-update gating, dev flags). Detail in 10.
  • Database: Sequelize over MySQL; sequelize.sync() on boot; pooled connections with warm-up and monitoring.

Discrepancies

  1. No member session token. Member-facing (client) endpoints authenticate a request only by checking, via validateCard, that the cardno supplied in the request body/query exists in CardDb. [src: middleware/validate.js:10-13] /client/verifyAndLogin validates phone + password once at login and returns the member record, but issues no session token, JWT, or cookie tied to that login — nothing is re-checked on subsequent requests. In practice, knowing (or guessing) a valid cardno is sufficient to call any client endpoint as that member, with no proof that the caller ever authenticated as them. This is materially different from the admin realm (JWT + authorizeRoles) and the coordinator realm (OTP-issued JWT scoped to that coordinator), both of which re-verify identity on every request. Full severity write-up and remediation options are tracked in 99 — Discrepancies & Open Questions.

How this connects to other domains (technical)

  • Accounts, Identity & Auth (business-logic file 02): expands the member/admin/coordinator realms above — card issuance, AdminUsers/Roles RBAC detail, and the guest/GuestRelationship model.
  • Booking Lifecycle & Engine (business-logic file 03): every domain's booking rows use the cardno/bookedBy pattern described in §4 above; the /guest, /mumukshu, and /unified route groups are where self/guest/mumukshu bookings actually get created.
  • Stay, Food, Travel, Adhyayan & Utsav (business-logic files 0407): each is one spoke off the CardDb hub in the ER map in §4, and each domain's own technical file has its own route table, schema, and discrepancies.
  • Payments, Credits & Reconciliation (business-logic file 08): Transactions is the shared money table referenced by bookingid across every chargeable domain (§4, §5).
  • Admin Panel Map (technical-only file 11, no business-logic pairing): the AdminUsers/AdminRoles/Roles RBAC model in §3 is what the admin panel's module-level permissions are built on.
  • API Reference (technical-only file 12, no business-logic pairing): the exhaustive route index; §2 above lists only base paths and their owning router.
  • Status & Cron (business-logic file 13): the 24-hour auto-cancel job referenced in §5 is defined and detailed there.