Building a website for day-to-day clinical operations, billing and inventory tracking from an inherently trilingual perspective
Adinath Multispeciality Hospital sits in Shahibaug, Ahmedabad: orthopedics and gynecology since 1990, run by the builder's parents. Dr. Ashok Sajnani, joint surgeon. Dr. Sunita Sajnani, obstetrics and gynecology. Its website has two jobs. The public half gets a patient from a phone screen to a booked appointment. The half behind the login runs the day: appointments, prescriptions, the medical store's stock and sales, payments. Three constraints decide every technical choice on both sides: the patient may read English, Hindi or Gujarati; the phone is often cheap and the connection often bad; and the number on the contact page rings a real desk.
The site is a static Astro build on Vercel with Supabase behind row-level security. Public pages for services, doctors, conditions and the medical store; a booking flow with a WhatsApp shortcut; legal pages in all three languages; a service worker so it installs like an app; structured data and per-language URLs for search. Behind the login, role portals for patients, doctors, staff and admins, a pharmacy point of sale over an inventory, a pay page, prescriptions, discharge and consent forms, and SMS templates in three languages. None of it is exotic. What is worth writing down is how it was built: in a few evenings with an AI pair, at a speed that produced the whole shape before midnight on the first night, followed by four months of finding out which of the model's defaults were wrong and deleting them. The git log is the evidence for everything below. The subject is the site, the people it serves, and the way of working.
22:42 One fact from the first night sets the tone. Three hours in, with a booking flow, a store and a complete portal system already committed, the most important commit of the project deletes the placeholder content and puts the real receptionist's name and the real statistics where the invented ones had been. The model will happily ship a hospital staffed by stock photos. Deciding that a real hospital gets real people on night one is a human decision, and it is the one that separates this repository from a demo.
Who the site is for, and how they reach a doctor
Almost nobody walks in cold. Patients in Shahibaug call ahead and book a time, and the desk answers in Gujarati or Hindi. That single habit shapes the whole public site. The phone number is not a footer detail; it is the primary interface, so it sits on every page and rings a real desk. The booking form's job is not to replace the call. It lets the same call-ahead habit happen at eleven at night without anyone picking up, and it lets it happen over WhatsApp, which the clinic now accepts alongside the phone. Booking is deliberately simple enough that anyone in a household can do it for anyone else: a doctor, a day, a name and a number.
Three languages are in use in varying degrees, with Gujarati and Hindi at the desk and English for the patients who prefer it. So the site treats the three as peers rather than English with translations bolted on. Every public page, the legal pages included, exists three times, and a patient who arrives on the Gujarati home page stays in Gujarati through the booking form and its confirmation.
Not everyone's phone speaks WhatsApp. A real share of patients prefer a call or a text, which is why the operations layer carries SMS templates in all three languages for the moments that matter after a visit: the prescription is ready, the follow-up is due, the medicine reminder, the signup link. The model's instinct was a chat-app-first design. The clinic's reality is phone-first, with WhatsApp and the web as faster paths to the same desk.
What the AI pair is good at
Shape, and shape fast. The first commit lands at 19:37 on December 20th with the public pages. Forty-nine minutes later there is a booking page, a medical store, SEO tags and a PWA manifest. Two hours and twenty-five minutes in there is a hospital-management layer with a login, three portals and intake forms. By the end of the second day, ninety-one commits later, there are role-based guides, WhatsApp share links and a mobile navigation. An engineer working alone does not produce the outline of a product in an evening. An engineer and a model do, and the outline is mostly right: most of the pages that exist today existed that night.
The pair also works in bursts, which the commit calendar makes visible: 236 commits on 22 active days out of 108, and four of those days hold 72 percent of everything. This is not a side-project pathology. It is what a model-assisted workflow looks like from the outside. When there is a clear brief, output arrives in storms; between storms the site is live and nothing is on fire. A five-week stretch in January holds exactly one commit, from a dependabot bot. The easy reading of that gap is abandonment. The accurate one is that the family was using the site and it held.
The price of the speed shows up on the same first night. Three commits in six minutes at 23:03 and 23:09 do nothing but clean <<<<<<< HEAD markers out of the live page's trust section. Real doctors online by ten, merge-conflict markers in production by eleven. Those are the same fact, and it is what "give in to the vibes, forget the code exists" costs in a log.
Three languages, built once
A trilingual site here is not a feature. Whether a patient can read the booking form in Gujarati decides whether they book or bounce. The first version handled this the way a model reaches for by default: every text element in the DOM carries a data-i18n attribute, a script swaps the strings at runtime, and the chosen language sits in localStorage. It feels pragmatic, and it works in a demo.

It fails in the way only a real user finds. Click Gujarati, and the navigation translates while the booking form directly below it stays in English. Half the page switches, on exactly the page where a patient is about to hand over a name and a phone number. The root cause is not a missing event listener. The forms had been rebuilt as React islands with their own language hook, so the page had two sources of truth for "the current language" and no plan for them to agree. A data-i18n DOM system and a React hook system are not two implementations of i18n. They are two applications sharing a page, almost certainly written in different sessions, neither of which held the other in context.
17:05 The fix tried first, on the afternoon the site moved to Astro, is the one the model proposes: bolt a bespoke runtime translator onto the static build to rescue the runtime translator. 18:08 The fix that ships an hour and three minutes later is the opposite. Each page is generated three times at build time, at /en/, /hi/ and /gu/, with the translated text baked into the HTML. No JavaScript runs to translate anything. The language switcher is three links. A patient on a slow connection downloads one HTML file in their language, and a search engine gets three real pages with hreflang between them.

The general rule fell out of the specific bug: anything that can be decided once at build time should not be decided per visitor at runtime. Translation is the clearest case. It is the same text for everyone who reads the language.
Forms without a framework
The second default the model picked was React for anything interactive. Booking, patient signup, status check: each became a React component mounted as an island, each shipping React and a database client to the browser so that a visitor could type a name into a form. A form does not need a component tree. It needs an HTML <form> and one fetch.
18:08 The same commit that fixed translation deleted the public islands. The booking wizard, the signup form, the status checker and the React language switcher leave together, −905 lines of component code, replaced by plain HTML forms and vanilla JavaScript that posts to Supabase. The booking flow kept its steps, pick a doctor, then a date, then details, then confirm, and kept the shortcut the desk now accepts: a WhatsApp deep link that opens a conversation in one tap.

The security posture is deliberately small. The browser holds only the public anonymous key. Row-level security lets that key insert a booking and read nothing back; a status lookup goes through a stored procedure that requires the exact phone number and booking reference, so there is no table to enumerate. The service key never reaches the browser. It is a defensible design for a clinic's appointment book, and it is not HIPAA compliance, which needs a signed business-associate agreement and a different budget. A security engineer should draw that line himself rather than let a landing page imply otherwise.
What runs behind the login
The public site is static because every visitor sees the same page. The staff side is not, because a staff member is changing state: adding an appointment, closing a sale, writing a prescription. So the React that left the public forms stayed behind the login, where an app is the right tool. Ten islands remain: the staff dashboard, the pharmacy point of sale, the payment form, the patient's appointments and prescriptions, and the onboarding flows for doctor, nurse, staff and patient. Static where the page is the same for everyone, an app where someone is operating it.
The staff dashboard is the desk's screen: new appointment, send a signup link, open a patient form, open the medical store. Its labels run English and Gujarati side by side, for a desk that works in both. The pharmacy point of sale sits on an inventory table that carries stock, unit price, expiry date, reorder level and supplier, with a low-stock view, and writes each transaction to a sales table with the items, total and payment method. A pay page offers a UPI QR code and a Razorpay checkout. Prescriptions are rows with a diagnosis, medicines, advice and a follow-up date. Discharge, consent and intake are forms, and the onboarding flows exist because the people who join a clinic are nurses and front-desk staff, not developers.
Not all of it is used. The schema also holds a queue table with numbered tokens and a queue position on every appointment, built in the first-night sprint because that is what a hospital-management system looks like in the model's training data. A clinic where patients book a time by phone does not hand out tokens, and the builder had to be reminded that the table existed. It is harmless, and it is a small, precise example of this essay's theme: the model builds the generic hospital unless someone keeps telling it which hospital.
Tests that test the easy thing
On the second day the commit log claims "100% test coverage" at 11:43 and "increase unit test coverage to 55%" at 13:23, and does not notice the contradiction. Both numbers are honest in their way. The model writes tests the moment it is asked and reports whatever the runner says.
Today the repository carries 22 spec files and none of them can run. Every one targets the vanilla site the migration deleted: they require a js/hms.js that no longer exists, and npm test prints a note saying so and exits clean. Nobody deleted them because nothing told anyone to.
The sharper lesson is the multilingual spec. It exists. It clicks the Hindi button and asserts that some Devanagari text appears somewhere on the page. The navigation alone satisfies it. The most user-visible failure in the project, Gujarati navigation above an English form, shipped straight through a test that checked the half of the page that worked. That is the characteristic shape of a model-written test: it asserts what is easy to assert, not what is load-bearing, because nothing in the prompt said where the risk was.
What would have caught the bug is almost embarrassing. A five-line build check that fails when Hindi or Gujarati is missing a key that English has. One browser pass per language that reads the form, not the menu. On a trilingual site the bug that ships is not a broken function. It is a missing translation, and pointing a test at that is a person's job.
Defaults that bill later
Every wrong turn above has the same origin: the model reaches for the tool already open on the desk. Runtime translation because the DOM was right there. React because it is the modern default. A token queue because that is what hospital software has. Interactive by default, static as the exception. The framework allows all of it quietly and sends the bill to the slowest phone on the worst connection in Ahmedabad.
02:56 Undoing it was mostly demolition. The commit that scaffolds the move to Astro is the largest in the repository, 68 files, +10,158 lines and −37,423. The warm redesign a month earlier, forest green, cream and Playfair Display in place of a look that read as a SaaS landing page, had already removed −6,464 lines of the first theme across eighty files. Across four months the final count is 54 fix commits to 45 feat. More fixes than features is the signature of something that got used by real patients, not just built. The hundred untyped commit messages are all from December; from January onward every commit carries a type, because the sprint had become a thing someone maintains.
The lesson is not that the model is wrong. It is that the model is fast at generating defaults and has no stake in which ones survive. It delivers the easy seventy percent before midnight. The last thirty, a site a patient's parents can use in their own language on a cheap phone, is the slow work of noticing which defaults were wrong and having the nerve to delete them. Read the history that way and the deletions are the story: the fake data on night one, the runtime translator, the React islands, thirty-seven thousand lines in one commit, the tests that tested the wrong thing. Every important moment is something being removed, which is the part of building with an AI pair that nobody puts in the demo.
Pratik spends his days on trading and security systems, where a wrong default costs milliseconds and money. Adinath is the other end of the spectrum: a static site for a family hospital, where a wrong default costs a patient who cannot read the booking form. This account is reconstructed from the repository, the deployed site, and the people who run the desk; corrections are welcome, especially from his parents, who know the hospital better than the code does.