Heartbeat Pharmacy Platform
Lead Developer
A full e-commerce platform for a Greek pharmacy, owned outright (no per-transaction SaaS bill), with regulatory data flowing in automatically and AI shrinking SKU enrichment from days to hours.
The system
Heartbeat Pharmacy needed an online store that would launch with real regulatory pharma data flowing in, take payments without bleeding margin to a SaaS vendor, and let one person manage thousands of SKUs without typing every description by hand. I built six integrated systems to get them there: the Next.js 16 storefront customers see, the Medusa 2.14 commerce backend that runs it (replacing what would have been Shopify Plus), an AI-augmented Product Information Management system on Express 5 + TypeORM, the React 19 admin the pharmacy team uses every day, a Node 22 Windows Service syncing stock from the on-site SQL Server every 15 minutes, and the regulatory pharma-data integration. All in production at theheartbeat.gr, all owned outright by the pharmacy.
Architecture
- Storefront: Next.js 16 App Router + Medusa SDK 2.14, Meilisearch search via Instantsearch, PayPal checkout, Turnstile spam protection
- Storefront API (Medusa backend): Medusa 2.14 with PostgreSQL + Redis + Meilisearch, PayPal payment, Resend email with React Email templates, PostHog analytics, regulatory pharma-data SOAP integration for master-data lookups
- Product Information Management (PIM) backend: Express 5 + TypeORM + Postgres, embedded MCP server for AI agent access (@modelcontextprotocol/sdk), Anthropic SDK + Google GenAI for product enrichment, headless browser automation for catalog imports, BullMQ + Redis queues, S3 for assets
- PIM admin frontend: React 19 + Vite + TanStack (Router/Query/Table/Virtual), shadcn/ui (full Radix set), Tiptap rich-text editor, dnd-kit drag-and-drop, kbar command palette, Recharts dashboards, served behind nginx
- product-sync Windows Service: Node 22 daemon syncing on-site SQL Server (stock + orders) to remote API + Skroutz XML feed every 15 minutes, with transactional idempotency, DRY_RUN mode, LockManager, CircuitBreaker, Winston logging
My contribution
I delivered the entire stack as Lead Developer, no other developer on the project. I owned the architectural decision to split into six small production systems instead of one large one, then built each: the commerce backend with the regulatory data integration, the AI-augmented PIM that lets a single person manage thousands of SKUs, the admin frontend the pharmacy team uses every day, and the Windows service that keeps stock in sync with the in-store ERP. The tech served the goals: BullMQ to pull supplier catalogs in without timing out, AES-secured credentials for supplier accounts, transactional idempotency on the sync service so a network blip cannot corrupt stock counts, an embedded MCP server letting Claude agents enrich the catalog without exposing the backend to the public internet. Every component ships with the production-grade essentials (daily-rotating logs, DRY_RUN mode, circuit breakers, Skroutz feed generation) so the system runs without anyone babysitting it.
Stack details
The most interesting piece is the embedded MCP server inside the PIM backend (via @modelcontextprotocol/sdk): Claude agents make direct tool calls against the product catalog without an intermediate REST hop, so AI enrichment runs inline instead of as an out-of-band script. Headless browser automation handles supplier feeds that don’t expose an API, behind per-supplier rate limiting. For integration tests I use Testcontainers, a real Postgres instance in Docker per test run, no mocks. The multi-stage Docker build ensures production images contain no dev dependencies.
Outcomes
- Full stack from API → admin → storefront, launch-ready
- Validated Greek pharma master-data integration: a differentiator most Medusa builds lack
- AI-augmented product enrichment (Anthropic + Google) reduces manual data entry across thousands of SKUs
- Production cutover discipline (transactional sync, circuit breakers, daily-rotating logs)
The challenge
The most complex challenge was designing the embedded MCP server inside the PIM backend. The goal was to allow an AI agent (Claude) to have direct access to the product catalog for enrichment tasks, without intermediate REST calls and without exposing the backend to an external network. The solution: the PIM backend runs a parallel MCP server process via @modelcontextprotocol/sdk, exposing tools like get_product, update_description, enrich_batch. The agent connects via stdio transport, local IPC, no HTTP overhead. The hard part was shared state management: the MCP layer and the REST layer share the same TypeORM data source, so transactions must be safe from both. I solved this through explicit transaction scoping and read-only mode on MCP tools that don’t need writes.
Links
- Live: theheartbeat.gr (pre-launch)
Related work
- Kleidarakos B2B & Papanikolaou Doors: another large commerce build, but B2B instead of B2C
- WooCommerce Plugins for pooq.gr: other pharma-adjacent commerce work in WordPress instead of Medusa
Gallery