Case study 02 / 03 · Health / Location-based web app
PharMap
An app that helps people in Cameroon find a medicine: which nearby pharmacies have it in stock, at what price, and how fresh that information is. Pharmacies manage their own listings, and an admin verifies them.
- Role
- Solo · frontend + backend
- Status
- MVP live · private code
- Stack
- React · NestJS · PostgreSQL
- Updated
- Sept 2026

01
What the client needed, and what I built
When someone in Cameroon needs a medicine, they usually go from pharmacy to pharmacy or phone around. Stock information, where it exists at all, is often out of date, and there's no easy way to know which pharmacy to trust.
01 · Find
ProblemTo find a medicine, people go from pharmacy to pharmacy or phone around.
BuiltSearch by generic name or local brand name (Doliprane, Panadol) and see which pharmacies have it.
Plain PostgreSQL search: every word matched against name, generic and brand names, accents ignored, ranked by matches

02 · Trust
ProblemStock information is often out of date, and there's no easy way to know which pharmacy to trust.
BuiltEach pharmacy shows the price, the stock status and how recently it was updated. Only pharmacies checked by an admin are marked verified.
Verification is a state machine, and every status change is recorded in an audit trail

03 · Back in stock
ProblemWhen a medicine is out of stock, patients have to keep checking.
BuiltWhen a pharmacy marks it back in stock, the patients waiting for it are notified.
Notifications are written in the same database transaction as the stock change, so no one is missed

All features (10)
- Search medicines by name, generic name or local brand name (e.g. Doliprane or Panadol for paracetamol)
- See which pharmacies have a medicine, with the price in FCFA, the stock status and how fresh the data is ("Reported 2 hours ago", flagged after 14 days)
- Pharmacies near me on a map (Leaflet + OpenStreetMap), with opening hours and "open now" on each pharmacy
- Pharmacy registration in 3 steps: find the pharmacy on OpenStreetMap or drop a pin, add the details, review. The browser's Back button works at every step
- Pharmacies manage their own stock: status, quantity and price for each medicine
- Admin verification with a real state machine (pending, under review, verified, rejected, suspended) and an audit trail of who decided what
- Restock notifications: a patient can ask to be told when an out-of-stock medicine is back at a pharmacy
- Ratings and reviews, and a way to report a wrong listing
- English and French, installable on a phone like an app, with a mobile bottom navigation that adapts to the account type
- Automated tests (unit and end-to-end) run on every push in CI
02
How it's built
I built PharMap as an installable web app (PWA) with a React frontend and a NestJS API. Patients search for a medicine and see which verified pharmacies have it, with the price and how recently the stock was updated. Pharmacies register themselves on a map and keep their inventory up to date. An admin verifies each pharmacy before it's shown as verified. It works in English and French.
- Frontend
- React + TypeScript + Vite + TailwindA fast, installable PWA. It's an app people log into, so it doesn't need server rendering.
- Maps
- Leaflet + OpenStreetMapFree, with no billing account or API key, and good place search for Cameroon.
- Backend
- NestJS + TypeScriptOne module per area (auth, medicines, pharmacies, reviews, notifications), with role checks enforced on the server.
- Database
- PostgreSQL (Neon) + PrismaPharmacies, stock, members and reviews are all linked, and stock updates need transactions.
- Hosting
- Vercel + Render (Docker)The web app on Vercel, the API on Render from its own Dockerfile. Free tiers that fit this app without losing features.
03
What was hard
- Search had to change to go live. It started on Meilisearch, but free hosting wipes the disk on restart, which deletes its index. I moved search into Postgres, trading typo tolerance for something that runs on the database we already have.
- Keeping notifications exact. When a pharmacy marks a medicine back in stock, waiting patients are notified in the same database transaction, so there's never a moment where stock says "in stock" and a subscriber was missed.
- Cold starts on free hosting. The database sleeps after 5 minutes and the API after 15, so deployments failed while the database woke up. A longer connection timeout fixed the deploys, and a scheduled ping keeps the API awake.
- One account, several roles. A person can be a patient and a pharmacy owner at the same time, so roles are worked out from their data instead of being stored as a single value.
04
Result
It's live as an MVP: the web app on Vercel, the API on Render and the database on Neon, with unit and end-to-end tests running on every push. The code is in a private repository.
05
Screens
8 screens · tap to enlarge
Need an app like this?
Search, maps and verified listings, in English and French.