Dr.Care
A platform for a Bangkok medical concierge that helps patients from Myanmar get treatment at Thai hospitals: a bilingual English/Burmese public site that brings in inquiries, and a private admin system that runs the business.
Visit the live site for Dr.Care (opens in a new tab)- My contribution
- Solo, from architecture to production
- Built for
- Dr.Care, Bangkok
- Client product. Source is private.
- Core stack
- FastAPIPostgreSQLReactTypeScriptAWS
How it fits together
React / TypeScript
- Public site (EN / MY)
- Admin dashboard
FastAPI
About 40 endpoints, plus a read-only public API
- AWS S3Images & files
- AWS SESInvites & sign-in codes
PostgreSQL
One system of record, migrated with Alembic
Engineering decisions
Off the spreadsheet in one cutover
The business ran on a single Google Sheet that mixed hospitals, packages, patients, referrals and expenses.
I planned a one-time migration: raw exports were kept untouched as an audit trail, and a cleaned set per table fed a loader script. Staff can still bring in new data through an Excel import in the admin app.
Admin access without a sign-up page
Patient records should only ever be reachable by staff the business has chosen.
Admins are invited, verify a one-time code and set a new password on first login. Passwords are hashed with Argon2, codes are stored only as SHA-256 hashes, and every admin action is written to an audit log.
Follow-ups that surface themselves
Staff need to see which patients are due back, including patients with no appointment on file.
The reminder list shows booked appointments from 90 days overdue to 30 days ahead. For patients without one, it estimates a follow-up 14 days after their last visit.
Auditing my own admin app
A system that holds patient data needed a security review, not just working features.
I audited the admin app and found six issues, including patient files going through the public image upload, cached patient data surviving logout, a vulnerable SheetJS version and formula injection in the CSV export. I fixed four, with regression tests for the code changes. Patient uploads stay disabled until private storage is ready, and moving the session token out of script reach is written up as backend work.
Two languages that stay in sync
Patients from Myanmar read the public site in Burmese, so a missing or half-translated string is a real gap.
A check script fails if the English and Burmese files drift apart, if text is left untranslated, or if a {placeholder} is lost in translation.