Heartbeat Pharmacy Platform
Lead Developer
A full e-commerce platform for a Greek pharmacy, owned outright (no per-transaction SaaS bill), with AI shrinking SKU enrichment from days to hours.
Results
- products in the first full sync
- 10,417
- between stock updates
- 1 min
- catalogue tools an AI assistant can call directly
- 69

The situation
Heartbeat is a Greek pharmacy with a physical shop, where stock already lived in the till system. They wanted their own online store, with no per-order commission going to somebody else’s platform, and without hiring a second person just to type product descriptions. They brought me on as the only developer on the project. Instead of one large program I delivered separate systems that work together, so any one of them can stop or be updated without taking the rest down.
A store they own
The code, the database and the server belong to the pharmacy. No platform takes a cut of each order, and no third party’s pricing change can raise the cost of running the shop overnight.

A product page has to answer the questions a pharmacist gets asked at the counter. Price with VAT shown plainly, whether it is in stock today, how soon it arrives, what the shipping will cost to your address.

How it works
- Store: a Next.js 16 storefront on a Medusa 2 backend, with PostgreSQL, Redis and Meilisearch.
- Search: Meilisearch through InstantSearch, results arriving as the customer types.
- Checkout and mail: a bank gateway integration, Turnstile on the forms, and order email through Resend with React Email templates.
- Monitoring: PostHog for usage and Sentry for errors only, with personal data scrubbed before any report leaves the server.
One person, thousands of product codes
Nineteen top-level categories, each with its own subcategories, is a lot of shelf to keep tidy for a pharmacy that also has a counter to run.

The catalogue has its own system, separate from the store. One person picks products, asks for a draft description, checks the text and the images, and only then does the product reach the storefront.
The point was never to have the machine write instead of a person, but to stop the person starting from a blank page on every single code.

How it works
- Catalogue backend: Express 5 with TypeORM over two separate PostgreSQL databases, one for data and one for logs only, so audit-record noise never weighs on the catalogue.
- Enrichment: the Anthropic SDK and Google GenAI for drafts, Puppeteer 25 with in-house evasions for catalogues that expose no API, BullMQ queues on Redis for bulk jobs, and S3 for images.
- Admin: React 19 with Vite and TanStack Router, Query and Table, a Tiptap text editor and Recharts dashboards.
- Checks: the integration tests bring up a real PostgreSQL in Docker with Testcontainers on every run, no mocks.
The shelf and the screen agree
Stock lives in the pharmacy’s own system, not on the site. A service reads it and sends it to the store every minute, so nothing gets sold that is not on the shelf.

How it works
- First sync: a full one, all 10,417 products; after that only what changed since last time travels.
- Resilience: retries with growing backoff, a lock so two syncs never run at once, a circuit breaker, a DRY_RUN mode for testing without writes, and logs that rotate daily.
- Packing: a separate service asks every 30 seconds for new courier vouchers and prints them on the packing bench’s thermal printer; the picking list carries the customer’s name only, never the address.
- Prices: all price arithmetic lives in one dependency-free package pinned to a version and shared by the backend and the admin, so there are never two versions of the same calculation.
Links
- Live: theheartbeat.gr (pre-launch)
Related work
- Kleidarakos B2B & Papanikolaou Doors: another large commerce build, but B2B instead of B2C
- pooq.gr: WooCommerce commerce engineering, extending a store instead of replacing it