
Let's be honest. As software engineers, we are accustomed to building landing pages, SaaS MVPs, e-commerce integrations, or dashboard mockups. We work in sprints, ship to staging, and iterate.
But every once in a while, a project lands on your desk that makes everyone sit upright. A project where the client isn't a small startup looking to validate an idea, but an entire accredited academic institution.
I'm talking about Gandhinagar University.
Winning a contract to build a university website is a completely different beast. A university isn't a single business. It is an ecosystem. Under one umbrella, you have 16 distinct institutes—ranging from Technology (GIT) and Law (GIL) to Management (GIM), Pharmacy (GIP), and Liberal Studies (GILS). You have an administrative division, an admission portal, thousands of prospective student leads, event management systems, academic calendars, job portals, compliance boards, and a strict requirement to keep page load times fast while giving non-technical staff the power to edit everything.
As the Full Stack Developer on the team, my job was to design the system architecture, write the integrations, build out the dynamic routing, establish the caching layers, and coordinate the deployment. The sheer scope was daunting. If we built it with 16 separate WordPress sites, we would end up in dependency and hosting hell. If we built it as 16 separate React builds, deployment and updates would become a logistical nightmare.
We needed a solution that was unified, scalable, incredibly fast, and maintainable. Here is the story of how our engineering team designed the digital core of Gandhinagar University, the architectural patterns that made it work, the failures that almost derailed the launch, and the lessons learned along the way.
When we first sat down to map out the codebase, the immediate instinct of some stakeholders was to split the project into multiple repositories—one for the student portal, one for the admin panel, one for the API, and one for each major institute.
As a team, we strongly opposed this. In a project of this size, code sharing is paramount. If you have different repositories, sharing typescript interfaces, API validator rules, and common UI components (like buttons, form inputs, and modal wrappers) becomes an exercise in frustration. You end up publishing private npm packages, managing version mismatches, and wasting hours on setup.
Instead, we chose a pnpm monorepo orchestrated by Turborepo.
Our folder structure was organized like this:
├── apps/ │ ├── api/ # Express.js backend API │ ├── web/ # React + Vite frontend │ └── public/ # Static assets and docs ├── packages/ │ └── utils/ # Shared helper functions, validators, formatter utilities │ └── types/ # Common TypeScript types and interfaces ├── package.json # Monorepo root configuration ├── turbo.json # Turborepo build pipeline config └── pnpm-workspace.yaml
packages/types/, we defined database entities, request/response structures, and access controls. If we changed a DB field, TypeScript caught the mismatches instantly.The centerpiece of our architectural design was the subdomain routing system. Gandhinagar University has 16 institutes, each requiring a separate URL (e.g., git.gandhinagaruniversity.ac.in for the Institute of Technology).
We built a single, highly dynamic React application that detects the active hostname at runtime and mounts the correct layout. Deploying one React application with wildcard DNS is infinitely easier to maintain than 16 separate apps. If we fix a bug in the global navbar, it immediately rolls out to all 16 subdomains in a single deployment.
By parsing the window location hostname at runtime, our routing layer dynamically extracts the subdomain, matches it against our centralized institute configuration registry, and determines user layout privileges. This allows us to serve custom themes and navigation matrices seamlessly without executing separate builds.
During peak times—such as academic result announcements or admission openings—traffic spikes drastically. A single uncached request fetching a course catalog with placement statistics requires joining four database tables. If thousands of visitors hit that route simultaneously, the database CPU spikes, causing API timeouts.
To combat this, I designed a multi-layer caching system using Redis:
blog:*) as soon as an administrator saves changes to content.Building software on local machines is easy; building software for production, where humans interact with it, is a chaotic exercise in edge cases. Here are three critical engineering challenges we hit during the project and how we solved them.
During the soft launch, administrators began uploading raw 15MB to 20MB images directly from DSLR cameras, and 50MB PDFs for academic disclosures. Node.js was reading these giant files into RAM as buffers before sending them to S3, causing Out-Of-Memory (OOM) process crashes.
The Fix: We overhauled the media pipeline to stream incoming file uploads directly to temporary disk storage rather than memory. We then wrote an image processing utility using the Sharp library to resize, compress into next-generation WebP/AVIF formats, and strip unnecessary EXIF metadata. This reduced page load sizes by 82% and stabilized server memory.
When integrating the BillDesk payment gateway for cultural event registrations, concurrent traffic tests revealed that some database transactions remained in a pending state despite successful bank notifications. This was caused by the bank webhook and user redirect API call colliding at the exact same millisecond.
The Fix: We implemented optimistic row-level locking (SELECT FOR UPDATE) on payment records, cryptographically verified all bank payloads using JOSEService, and built a self-healing reconciliation cron worker running in the background to automatically resolve stale pending states.
The admissions department wanted prospective student leads synced in real-time to a Google Sheet. When admission campaigns launched, concurrent submissions crashed the sync due to Google's strict API rate limits (60 writes/minute).
The Fix: We introduced a background worker queue pattern. Form submissions are saved immediately to PostgreSQL (<50ms). A background sync worker wakes up every 10 seconds, batches all pending lead IDs, aggregates them into a single 2D array, and writes to Google Sheets in a single API call, reducing our rate-limit footprint by 98%.
To improve student support, we integrated an AI Chatbot directly into the website shell using the Google Gemini API.
To prevent hallucination, the system loads prompts dynamically from our database, matching them with verified administrative FAQs. The chatbot is also configured for chat-based lead generation, gathering name and email details before resolving complex course-eligibility questions. Endpoints are strictly rate-limited and secured with CSRF session tokens to prevent API quota exploitation.
Building the digital core of Gandhinagar University was a trial by fire. It proved that system architecture must precede code, that failures are simply checkpoints to build more resilient, self-healing code, and that a monorepo setup is a massive superpower for small development teams.