M. MAUN STUDIO
Let's Work Together
All work
Case Study6 min read

Case Study: Mediko.ph

Case Study: Mediko.ph

Case Study: Mediko.ph — Full-Stack Healthcare E-Commerce Platform

Role: Senior Full-Stack Developer (Solo)
Timeline: 2026–2025
Stack: Shopify, Node.js (Fastify), React/Vite, Supabase, OpenAI, Railway, TypeScript
Live Site: store.mediko.ph


Overview

Mediko.ph is a Philippine-based online pharmacy built on Shopify. What started as a theme customization project evolved into a suite of custom-built systems that handle government-mandated discount compliance, AI-powered customer support, and a fully branded storefront — none of which Shopify's out-of-the-box tooling could adequately address.

The work spans three separate repositories/apps, each solving a distinct product problem, but all working together as a cohesive platform.


The Challenge

Running a compliant online pharmacy in the Philippines presents unique engineering problems:

  1. Legal compliance — Republic Acts 9994 and 10754 (Senior Citizen and PWD laws), alongside JAO 24-02, mandate a 20% discount for qualifying customers. Shopify has no native mechanism to verify eligibility, apply conditional discounts at checkout, and maintain an audit trail.
  2. Customer support at scale — Pharmacy customers frequently ask about product availability, dosage, and order status. A human-only support model doesn't scale; a generic chatbot doesn't serve medical queries well.
  3. Brand & storefront — The default Shopify theme lacked the visual identity and UX patterns needed for a healthcare brand that customers need to trust.

System Architecture

┌─────────────────────────────────────────────────────┐
│                  store.mediko.ph                    │
│              (Shopify Storefront)                   │
│                                                     │
│  ┌─────────────────┐    ┌────────────────────────┐  │
│  │  Custom Theme   │    │  Chat Widget (IIFE)    │  │
│  │  (Liquid/JS)    │    │  React/Vite Embed      │  │
│  └────────┬────────┘    └────────────┬───────────┘  │
└───────────┼─────────────────────────┼───────────────┘
            │                         │
            ▼                         ▼
┌───────────────────┐    ┌────────────────────────────┐
│  SC/PWD Gateway   │    │    Mediko Chat API         │
│  (Fastify/Node)   │    │    (Fastify/Node)           │
│  Railway          │    │    Railway                 │
└────────┬──────────┘    └────────────┬───────────────┘
         │                            │
         ▼                            ▼
┌─────────────────────────────────────────────────────┐
│                    Supabase                         │
│         (Postgres + Realtime + Storage)             │
└─────────────────────────────────────────────────────┘

Sub-Project 1: SC/PWD Discount Compliance Gateway

Repo: mediko-gateway
Stack: Node.js, Fastify, Supabase, Nodemailer, Shopify Admin REST API

The Problem

Philippine law requires pharmacies to grant a 20% discount (on top of VAT exemption in some cases) to Senior Citizens and PWD cardholders. On a standard Shopify store, there is no verified, auditable way to do this — discount codes can be shared, and there's no ID verification flow.

What I Built

A standalone Fastify API that acts as a compliance middleware between the customer and Shopify checkout:

  • Application flow — Customers submit their SC/PWD ID details (name, ID number, card type) through a custom Shopify-embedded form. The gateway stores the application in Supabase with a pending status.
  • Admin review — An admin dashboard (protected route) lists pending applications. Admins verify the submission and approve or reject.
  • Discount issuance — On approval, the gateway calls the Shopify Admin REST API to programmatically generate a single-use, customer-locked discount code (20% off) and emails it to the applicant via Nodemailer.
  • Audit trail — Every application, status change, and discount issuance is logged in Supabase with timestamps — satisfying the record-keeping requirements under JAO 24-02.

Technical Highlights

  • Fastify chosen over Express for its schema-based validation (JSON Schema via @fastify/ajv-compiler), which enforces the structure of incoming ID data at the route level with no extra middleware
  • Supabase Row Level Security (RLS) policies ensure admin-only access to the applications table without an extra auth layer in the API
  • Shopify discount codes are scoped to a single customer email and set to expire in 7 days, reducing misuse risk
  • Environment-separated configs for staging and production deployments on Railway

Sub-Project 2: Mediko Chat — AI Customer Support Widget

Repo: mediko-chat
Stack: Fastify, OpenAI API, Supabase Realtime, React, Vite, TypeScript, Railway

The Problem

Pharmacy customers regularly ask pre-purchase questions: "Is this in stock?", "What's the generic alternative?", "Can I take this with metformin?" A human support team can't be online 24/7, and generic chatbot templates don't understand product catalogs or Philippine healthcare context.

What I Built

An end-to-end AI chat system embedded directly into the Shopify storefront as a lightweight IIFE bundle:

Backend (Fastify API on Railway)

  • Accepts chat messages and maintains conversation history per session
  • Calls OpenAI with a system prompt that includes Mediko's product catalog context (fetched from Supabase) and instructions to respond in a pharmacy support persona
  • Streams responses back to the client using server-sent events (SSE)
  • Logs all conversations and messages to Supabase for analytics

Frontend (React/Vite Widget)

  • Compiled as an IIFE (Immediately Invoked Function Expression) so it loads as a single <script> tag in the Shopify theme — no build pipeline changes needed on the Shopify side
  • Uses Shadow DOM to isolate styles from the Shopify theme, preventing CSS conflicts
  • Implements Supabase Realtime subscriptions so multiple tabs/sessions stay in sync
  • Includes a quick replies system (pre-set buttons like "Track my order", "Browse products") managed via a Supabase-backed CRUD interface

Analytics Dashboard

  • An internal dashboard (separate React page) shows conversation volume, common questions, and response ratings — used to refine the AI's system prompt over time

Technical Highlights

  • Shadow DOM encapsulation solved font loading issues where Shopify's global styles were bleeding into the widget
  • Supabase Realtime subscriptions replaced a polling approach, cutting unnecessary API calls by ~90%
  • IIFE bundle approach means zero Shopify theme dependencies — the widget works on any Shopify theme without modification
  • OpenAI function calling used to trigger product search within the conversation context (e.g., "Do you have losartan 50mg?" triggers a Supabase product lookup)

Sub-Project 3: Mediko Shopify Theme

Repo: mediko-theme
Stack: Shopify Liquid, JavaScript, CSS

The Problem

The default Shopify Dawn theme didn't reflect Mediko's brand as a trusted healthcare provider. Customers needed to immediately feel confidence and clarity — not a generic storefront.

What I Built

A fully customized Shopify theme tailored to Mediko's product catalog structure and brand guidelines:

  • Custom section layouts — Homepage sections built for pharmacy-specific UX: featured categories (OTC, Rx, Vitamins), health banners, and trust indicators (licensed, DOH-compliant messaging)
  • SC/PWD Application embed — The discount gateway application form is embedded as a custom Shopify section that renders in the theme and posts to the external gateway API, keeping everything visually native
  • Chat widget integration — The Mediko Chat IIFE bundle is injected via the theme's theme.liquid so it loads globally across all pages
  • Performance considerations — Scripts are deferred, images use Shopify's built-in CDN transforms (| image_url with size params), and non-critical CSS is lazy-loaded

Outcomes

| Metric | Result | |---|---| | SC/PWD compliance | Fully auditable discount issuance flow aligned with RA 9994, RA 10754, JAO 24-02 | | Support availability | 24/7 AI-assisted chat covering product, stock, and general pharmacy queries | | Chat widget load impact | < 40KB IIFE bundle; negligible Lighthouse score impact | | Deployment | All backend services on Railway with zero-downtime deploys via GitHub Actions |


Key Learnings

Shopify is a platform, not a constraint. Most Shopify limitations aren't walls — they're boundaries that push you toward building better external services. The gateway and chat widget are more maintainable precisely because they're decoupled from the theme.

Legal requirements make great product specs. The SC/PWD system had clearly defined requirements from the law itself. Translating RA 9994 and JAO 24-02 into database schema and API logic was one of the more satisfying engineering challenges in the project.

Shadow DOM is underused in widget development. Embedding third-party UIs into Shopify themes is painful without it. Using Shadow DOM + IIFE compilation made the chat widget drop into any Shopify store without style conflicts.