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.mdon 2026-07-07 againstaashray-backendmain. 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/utsavmounts 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¶
- 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 avalidateCardcheck that the suppliedcardnoexists inCardDb— so possession of a card number is effectively the credential (a real security gap; see Discrepancies, below). Thetokencolumn 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. - Admin (staff) — the admin panel user. Authenticates via
/admin/auth, receives a JWT signed withprocess.env.SECRET.middleware/AdminAuth.jsverifies the Bearer token, loads theAdminUsersrecord byid+username, and rejects it ifstatus === 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 fromAdminRoles.role_namewherestatus = active— toreq.roles. Individual admin routes are gated withauthorizeRoles(...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. - Coordinator — a limited operational role (e.g., travel bus coordinators) authenticated by OTP (
/api/v1/coordinator,coordinatorOtpmodel,sendCoordinatorOtphelper). [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) andbookedBy(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),Countries→States→Cities(location cascade),CentreDb(centres). - Stay:
RoomDb(rooms) →RoomBooking;FlatDb(flats, withowner→ 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 intoTravelBusGroup→TravelBusPassengers+TravelBusStops. - Adhyayan:
ShibirDb(sessions/shibirs) →ShibirBookingDb→ShibirAttendanceDb/ShibirAttendanceRecord;ShibirSession(session breakdown);AdhyayanFeedback. - Utsav:
UtsavDb→UtsavPackagesDb(ticket packages) +UtsavBooking;UtsavFeedback→UtsavFeedbackAnswer. - Money:
Transactions(one per chargeable booking, linked bybookingid),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 * 60minutes, defined incron.jsitself (notconfig/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:
/updatesserves 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¶
- No member session token. Member-facing (client) endpoints authenticate a request only by checking, via
validateCard, that thecardnosupplied in the request body/query exists inCardDb. [src: middleware/validate.js:10-13]/client/verifyAndLoginvalidates 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 validcardnois 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/RolesRBAC detail, and the guest/GuestRelationshipmodel. - Booking Lifecycle & Engine (business-logic file 03): every domain's booking rows use the
cardno/bookedBypattern described in §4 above; the/guest,/mumukshu, and/unifiedroute groups are where self/guest/mumukshu bookings actually get created. - Stay, Food, Travel, Adhyayan & Utsav (business-logic files 04–07): each is one spoke off the
CardDbhub 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):
Transactionsis the shared money table referenced bybookingidacross every chargeable domain (§4, §5). - Admin Panel Map (technical-only file 11, no business-logic pairing): the
AdminUsers/AdminRoles/RolesRBAC 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.