Back to work
Live in productionMedical concierge platform

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
DR.CAREMEDICAL CONCIERGE / BANGKOKSURFACESPUBLIC SITEEN / MYADMINREST APISYSTEM OF RECORDPOSTGRESQLWAS: ONE GOOGLE SHEETFOLLOW-UP WINDOW+14D-90D-60D-30DTODAY+30DOVERDUEUPCOMINGESTIMATED
Follow-up reminders: booked appointments from 90 days overdue to 30 days ahead, plus an estimated check-in 14 days after the last visit when none is booked.

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.