Technology stack, conditional content rules, SEO architecture, security & compliance, and 25-point dual-launch checklist for the B2C consumer site and B2B institutional microsite on a single domain.
This dual-audience site requires a platform that handles: consumer e-commerce (cart, checkout, consumer accounts), an authenticated B2B microsite with different pricing and content, a single product catalogue powering both experiences, and a clean single-domain URL structure. The platform decision drives every other technical choice.
The B2B institutional microsite is not a separate application — it is a gated route group within the same Next.js application, sharing the same product catalogue and authentication service, with different components, pricing data, and navigation rendered based on the authenticated user's customer group.
| B2B portal technical architecture | |
|---|---|
| URL structure | mgrmmedicare.com/institutional/* — handled by Next.js App Router route group. All routes in /app/(b2b)/institutional/ are wrapped in an authentication layout component that checks for a valid B2B session token before rendering. |
| Auth guard | Server component layout.tsx in the (b2b) route group makes a server-side call to the auth service. If no valid B2B token exists, it redirects to /institutional/login — never exposes any institutional content to unauthenticated requests, including price data. |
| Customer groups | Medusa.js customer groups: CONSUMER (all registered B2C users), INSTITUTIONAL_T1 (Tier 1 verified buyers), INSTITUTIONAL_T2 (Partner Accounts), INSTITUTIONAL_T3 (Strategic Partners). Each group has different price list associations in the product catalogue. |
| Pricing resolution | When an institutional user's session is validated, their customer group ID is included in the session token. All product queries from the B2B portal include the customer group ID — Medusa.js returns the correct institutional price list rather than the consumer price list. |
| B2B-only content | Compliance documents, clinical evidence library, training resources, marketing collateral, quote system, and order management are Next.js pages/components that only exist in the /institutional route group. They are never rendered on the public B2C site. |
| Shared components | The product catalogue data is shared — the same product names, SKUs, specifications, and images are used in both B2C and B2B. Only the price display component, CTA component (Add to Cart vs Add to Quote), and navigation component differ between the two experiences. |
| Authentication architecture | |
|---|---|
| Auth provider | Auth0 (recommended) or AWS Cognito. Both support multiple user pools, custom claims, and MFA — required for institutional account security. Auth0 is preferred for its Action pipeline which allows custom logic at the token issuance step (e.g., injecting customer group ID and tier into the JWT). |
| B2C consumer auth | Auth0 Application: MGRM-B2C. Standard email/password + Google OAuth. JWT contains: user_id, email, customer_group: CONSUMER. Session duration: 30 days (remember me) or session-only. Consumer login → /my-account. |
| B2B institutional auth | Auth0 Application: MGRM-B2B. Email/password + SAML 2.0 / Azure AD SSO for enterprise hospital networks. JWT contains: user_id, email, institution_id, customer_group: INSTITUTIONAL_T1/T2/T3, account_manager_id, institution_name. Session duration: 8 hours (professional use pattern). B2B login → /institutional/dashboard. |
| Token validation | Next.js middleware (middleware.ts) validates the JWT on every request to /institutional/*. If the token is absent, expired, or does not contain a B2B customer group claim, the middleware redirects to /institutional/login. This happens at the Edge — before any page rendering — preventing any B2B content from loading for unauthenticated users. |
| SAML / Azure AD SSO | Required for large hospital networks (Fortis, Apollo, AIIMS) that use centralised identity management. Auth0's SAML connection allows the hospital's Azure AD to authenticate users — the user clicks Sign in with SSO on the B2B login page, is redirected to their hospital's Microsoft login, and returns with a valid session. MGRM never handles their password. |
| MFA requirement | MFA is mandatory for all B2B institutional accounts (Auth0 Adaptive MFA or TOTP). Optional for B2C consumer accounts. The institutional portal contains sensitive pricing, compliance documents, and procurement data that require stronger authentication than consumer e-commerce. |
| Session separation | A user logged into a B2C consumer account and a B2B institutional account simultaneously uses separate Auth0 sessions (separate browser storage namespaces). The B2C session does not grant any B2B portal access, and the B2B session does not render any B2C-only UI (wishlist, loyalty points, etc.). |
| CRM for B2B account management and quote tracking | |
|---|---|
| Recommended CRM | HubSpot CRM (Sales Hub Professional or Enterprise). Rationale: native Deal pipeline for quote tracking, Company records for institutional accounts, custom properties for tier assignment, and bi-directional API with Medusa.js for order sync. Alternative: Salesforce (more powerful but significantly more expensive and complex to configure). |
| Company records | Every verified institutional account in the B2B portal creates a HubSpot Company record. Properties: Institution name, Type (Hospital/Clinic/Distributor/College), GST number, City, State, Tier (T1/T2/T3), assigned Account Manager, portal login status, last login date. |
| Quote pipeline | Quote requests from the B2B portal create HubSpot Deals in a custom Quote pipeline with 5 stages: Submitted → Under Review → Quote Sent → Accepted → Order Raised. The deal value is the estimated quote total. Account managers work the pipeline from their HubSpot inbox. |
| Account manager assignment | HubSpot Contact Owner = Account Manager. When a new institution is approved, the onboarding workflow assigns the Contact Owner based on territory (state). The assigned account manager's details (name, email, phone) are pulled into the B2B portal Account Manager card via the HubSpot API at dashboard load. |
| Order sync | Confirmed orders from the B2B portal sync to HubSpot as closed deals. This populates the institution's order history in HubSpot, allows the account manager to track spend, and triggers the tier upgrade workflow when the 3-order milestone is reached. |
| Email automation | HubSpot sequences send quote status update emails, renewal reminders for expiring compliance documents, and quarterly business review invitations for Tier 3 accounts. These are triggered by deal stage changes in the pipeline. |
| Payment gateway — B2C consumer + B2B invoice/PO | |
|---|---|
| B2C consumer payments | Razorpay (primary recommendation for India). Supports: Credit/debit card (Visa, Mastercard, Rupay, Amex), UPI (GPay, PhonePe, Paytm, BHIM), net banking (all major Indian banks), EMI (no-cost EMI on major cards), and Cash on Delivery. Razorpay integrates natively with Medusa.js via the official Medusa Razorpay plugin. PCI DSS Level 1 compliant — card data never touches MGRM servers. |
| B2C payment flow | Standard checkout → Razorpay hosted checkout page (or Razorpay Elements embedded) → payment confirmation webhook → Medusa.js order created. COD is handled as a deferred payment type — order is created, payment status is pending until delivery confirmation. |
| B2B invoice/PO payments | B2B orders do not use Razorpay. The B2B quote-to-order flow generates an invoice via the MGRM billing system (Zoho Books or Tally integration). Payment methods: NEFT/RTGS bank transfer, cheque, or net credit terms (30/60 days). The portal records PO number and tracks payment status (Unpaid → Partially Paid → Paid) in Medusa.js order metadata. |
| Credit terms management | Tier 2 institutions have 30-day net terms. Tier 3 institutions have 60-day net terms with a credit facility. Credit limits are stored in HubSpot Company properties and checked against outstanding invoices at quote request time. If an institution exceeds their credit limit, the quote system displays an alert and routes to the account manager. |
| Secondary B2C gateway | PayU or Cashfree as a backup payment processor. Medusa.js supports multiple payment providers — if Razorpay experiences downtime, the checkout falls back to the secondary provider without code changes. |
| EMI handling | Razorpay handles no-cost EMI — the bank charges the cardholder the full amount and MGRM pays the bank the interest subsidy. MGRM does not handle EMI financing directly. The EMI option in checkout uses Razorpay's EMI API to display available tenures and interest rates per card/bank. |
The same URL (e.g. a product page) renders different content based on the user's authentication state. This table defines exactly what is shown, hidden, or replaced across the three possible states: unauthenticated visitor, B2C consumer account, and B2B institutional account.
| UI Element | Not logged in | B2C account logged in | B2B institutional logged in |
|---|---|---|---|
| Header navigation | Consumer nav (6 items) + Institutional Login ghost button + Search + Cart | Consumer nav + My Account (filled) + Cart + Search. Institutional Login hidden. | B2B portal nav (Catalogue / Quotes / Orders / Clinical Resources / Account) replaces consumer nav. User pill shows institution name + tier. |
| Product price display | Consumer retail price (MRP shown if discount applies). "From ₹X" for products with variants. | Same as unauthenticated. Loyalty points balance shown if applicable. | Institutional unit price (volume tier at 1–10 units by default). MRP never displayed. Volume pricing table replaces single price. |
| Product CTA button | Add to Cart (primary). "Institutional pricing available — Log in →" secondary text link. | Add to Cart. Wishlist ♡ icon. Compare checkbox. | Add to Quote List (Sky Blue). Add to Quote replaces cart entirely. No Add to Cart shown. |
| Product detail page — pricing section | Single consumer price. MRP struck if on sale. Savings badge if applicable. | Same as unauthenticated + loyalty points preview ("Earn X points"). | 4-row volume pricing table (1–10 / 11–50 / 51–100 / 100+ with tier discounts). Live subtotal estimator. MOQ displayed. |
| Compliance / certification section on PDP | Certification badge pills (CE, ISO, FDA) displayed. No download links. | Same as unauthenticated. No download links. | Full compliance section: 4-cert grid with certificate numbers + validity dates + download links (IFU PDF, spec sheet, CE Declaration, MSDS). |
| Cart / basket | Standard consumer cart. Pharma safety checkboxes. Promo code. Order summary. | Same as unauthenticated. Saved addresses pre-populated. Loyalty points redemption option. | B2B users never see consumer cart. They are redirected to /institutional/quote-list. Consumer cart session is cleared on B2B login. |
| Checkout flow | 3-step consumer checkout (delivery → payment → review). Razorpay payment options (card, UPI, EMI, COD). | Same as unauthenticated but pre-filled with saved address and payment methods. | No consumer checkout shown. B2B flow: Quote Basket → Quote Request Form (PO number, department, delivery address) → Submit to account manager. |
| Account page / Dashboard | Not accessible. Redirects to /login. | /my-account: orders, wishlist, health profile, addresses, Care Points. No B2B content. | /institutional/dashboard: orders, quotes, compliance documents, account manager card, tier progress. No B2C account content (no loyalty points, no wishlist). |
| /institutional/* routes | Middleware redirects all /institutional/* requests to /institutional/login. No content rendered. | B2C JWT is rejected by B2B auth guard. Redirected to /institutional/login with message: "A consumer account cannot access the institutional portal. Apply for institutional access." | Full B2B portal accessible according to tier (Tier 1 / T2 / T3 content gates enforced per section). |
| Recovery Hub / blog | Full public access. All articles, videos, and newsletter signup visible. | Same as unauthenticated + personalised article recommendations based on health profile conditions. | B2B portal has its own clinical resources section (/institutional/clinical-resources). Recovery Hub is visible but institutional users are shown a banner: "Looking for clinical evidence and training? Visit your clinical resources hub →" |
| Telemedicine booking | Book a consultation CTA visible. Routes to /find-care/telemedicine. Registration required to complete booking. | Full booking flow accessible. Health profile pre-fills consultation context. | Telemedicine patient booking is not shown in the B2B portal. Institutional telemedicine integration (for hospitals wanting to deploy MGRM telemedicine for their patients) is handled via a separate enterprise enquiry form. |
| Institutional Login button (header) | Visible. Routes to /institutional/login. | Visible. Routes to /institutional/login with a message suggesting the user applies for institutional access. | Not shown. The user is already in the B2B portal — the header shows their institution name and tier instead. |
// lib/auth/useUserType.ts import { useSession } from 'next-auth/react' export type UserType = 'unauthenticated' | 'b2c' | 'b2b_t1' | 'b2b_t2' | 'b2b_t3' export function useUserType(): UserType { const { data: session } = useSession() if (!session) return 'unauthenticated' const group = session.user?.customerGroup // Injected by Auth0 Action into JWT if (group === 'INSTITUTIONAL_T3') return 'b2b_t3' if (group === 'INSTITUTIONAL_T2') return 'b2b_t2' if (group === 'INSTITUTIONAL_T1') return 'b2b_t1' return 'b2c' // CONSUMER group or any registered user }
// components/product/ProductActions.tsx export function ProductActions({ product }: { product: Product }) { const userType = useUserType() const isB2B = userType.startsWith('b2b') return ( <div> {isB2B ? ( <VolumePricingTable {/* Shows 4-tier institutional pricing */} productId={product.id} customerGroup={userType} /> ) : ( <ConsumerPriceDisplay {/* Shows MRP and retail price */} price={product.variants[0].prices[0]} compareAt={product.variants[0].compare_at_price} /> )} {isB2B ? ( <AddToQuoteButton productId={product.id} /> ) : ( <> <AddToCartButton variantId={product.variants[0].id} /> {userType === 'unauthenticated' && ( <InstitutionalPricingNudge /> {/* "Institutional pricing available" link */} )} </> )} </div> ) }
// middleware.ts import { NextResponse } from 'next/server' import { getToken } from 'next-auth/jwt' export async function middleware(req) { const pathname = req.nextUrl.pathname // B2B portal guard — all /institutional/* routes except login and register if (pathname.startsWith('/institutional') && !pathname.includes('/institutional/login') && !pathname.includes('/institutional/register')) { const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET }) // No token → redirect to login if (!token) { return NextResponse.redirect(new URL('/institutional/login', req.url)) } // B2C token → redirect to login with explanation if (token.customerGroup === 'CONSUMER') { return NextResponse.redirect( new URL('/institutional/login?reason=consumer-account', req.url) ) } // Valid B2B token → proceed, inject tier into request headers const res = NextResponse.next() res.headers.set('x-user-tier', token.customerGroup) res.headers.set('x-institution-id', token.institutionId) return res } }
The dual-experience site must maximise crawlability and indexability for B2C pages (products, conditions, educational content, telemedicine) while ensuring B2B portal pages are never indexed — institutional pricing, compliance documents, and quote systems should not appear in search results.
| B2C SEO technical requirements | |
|---|---|
| Rendering method | Next.js Server-Side Rendering (SSR) for all public B2C pages. Product pages, condition pages, and category pages are rendered on the server and returned as complete HTML — Google crawls the full content without executing JavaScript. This is critical for product and condition pages where the text content drives organic ranking. |
| Incremental Static Regeneration (ISR) | Product pages are pre-built at build time and regenerated on demand (ISR with 60-minute revalidation). This combines the SEO benefit of static pages with the ability to update pricing and stock without a full rebuild. Product description, specifications, and schema markup are always current. |
| Sitemap | Dynamically generated sitemap.xml at /sitemap.xml. Includes: all product pages (/products/[slug]), condition pages (/conditions/[body-area]/[slug]), Recovery Hub articles (/recovery-hub/[article-slug]), and static pages. Excludes: /institutional/*, /my-account/*, /cart, /checkout. Submitted to Google Search Console. |
| robots.txt | User-agent: * / Allow: / / Disallow: /institutional / Disallow: /my-account / Disallow: /cart / Disallow: /checkout / Disallow: /api / Sitemap: https://mgrmmedicare.com/sitemap.xml |
| Canonical URLs | Every public page includes a canonical meta tag pointing to itself. Product variant pages (size/colour) use the canonical pointing to the main product URL to prevent duplicate content. Condition sub-pages use structured canonical hierarchies. |
| Core Web Vitals | LCP target: under 2.5 seconds. INP target: under 200ms. CLS: under 0.1. Achieved via: image optimisation (Next/Image with WebP), font preloading (Lora + Open Sans subsets), deferred non-critical JS, and edge caching via Cloudflare and Vercel Edge Network. |
| hreflang | If/when Hindi (hi-IN) and regional language versions are launched, hreflang tags in the document head and sitemap. English (en-IN) is the primary locale. |
| Priority crawl pages | 1. Condition pages (/conditions/*) — highest intent traffic. 2. Product pages (/products/*) — commercial intent. 3. Recovery Hub articles (/recovery-hub/*) — informational intent, builds topical authority. 4. Find Care pages (/find-care/*) — local/service intent. |
| B2B noindex implementation — multiple defence layers | |
|---|---|
| Layer 1: robots.txt | Disallow: /institutional/ — prevents Googlebot from crawling any /institutional/* URL. First and fastest line of defence. |
| Layer 2: X-Robots-Tag header | Next.js middleware adds the HTTP header X-Robots-Tag: noindex, nofollow to all responses from /institutional/* routes. Even if a Googlebot ignores robots.txt, the response header instructs it not to index the page. |
| Layer 3: Auth guard returns 302 | If Googlebot somehow reaches a B2B page, the middleware auth guard (Section 2.4) returns a 302 redirect to /institutional/login — Google does not index redirect destinations that require authentication. |
| Layer 4: No public links | No B2B portal URL is linked from any public B2C page (only the /institutional gateway URL itself, via the Institutional Login button, is linked). Googlebot discovers pages by following links — deep B2B portal pages with no public inbound links will not be discovered even if robots.txt is misconfigured. |
| Layer 5: Search Console monitoring | Google Search Console URL inspection tool is used weekly during the first 3 months post-launch to verify no /institutional/* pages appear in the index. Any indexed URLs are submitted for removal via the URL Removal Tool. |
| Document URLs (S3) | Compliance documents are stored in a private AWS S3 bucket. Download links are pre-signed URLs that expire after 1 hour — they cannot be indexed by search engines because they expire before Googlebot can crawl them. |
| JSON-LD schema markup — B2C public pages | |
|---|---|
| Product pages | Schema.org/Product: name, description, image, brand (MGRM Medicare), sku, mpn (catalogue reference), offers (price, priceCurrency INR, availability, itemCondition), aggregateRating (when reviews present), category. All implemented as JSON-LD in document head via Next.js generateMetadata(). |
| MedicalOrganization | On the About MGRM page and homepage: Schema.org/MedicalOrganization: name, description, url, logo, address (India), contactPoint, medicalSpecialty, availableService (telemedicine, rehabilitation, pharmacy). Establishes MGRM as a medical entity in Google's Knowledge Graph. |
| FAQPage | On telemedicine page (Step 7) and product pages with FAQ sections: Schema.org/FAQPage with Question/Answer pairs. Enables FAQ rich results in Google Search — particularly valuable for condition guide pages (e.g. "How long does knee surgery recovery take?"). |
| Breadcrumb | BreadcrumbList schema on all product, condition, and article pages. Enables breadcrumb display in Google search results. |
| Article | On Recovery Hub articles: Schema.org/Article with headline, author, datePublished, dateModified, publisher (MGRM Medicare), image, description. Enables article rich results and Google Discover eligibility. |
| LocalBusiness | On the Stockist Locator page: Schema.org/PharmacyOrMedicalBusiness for MGRM head office. Individual stockist listings are not schema-marked (they are third-party businesses). |
| B2B portal | No schema markup on any /institutional/* page. Schema markup is a signal to search engines — B2B pages should not attract any search engine attention whatsoever. |
{
"@context": "https://schema.org",
"@type": "Product",
"name": "ROM Knee Splint — Post-surgical",
"description": "Adjustable range-of-motion knee splint for post-TKR and ACL recovery...",
"sku": "MGRM-RS-ROM-M",
"mpn": "2025-RS-001",
"brand": { "@type": "Brand", "name": "MGRM Medicare" },
"image": "https://mgrmmedicare.com/images/products/rom-knee-splint-m.jpg",
"offers": {
"@type": "Offer",
"price": "3499",
"priceCurrency": "INR",
"availability": "https://schema.org/InStock",
"seller": { "@type": "Organization", "name": "MGRM Medicare Pvt Ltd" }
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.8",
"reviewCount": "312"
}
}The MGRM platform handles health data (telemedicine consultations, health profiles), financial data (payment cards, institutional credit terms), and regulated content (pharmacy products, compliance certificates). Four distinct compliance frameworks apply.
| Health data protection — telemedicine and health profile | |
|---|---|
| Data categorisation | Protected Health Information (PHI) includes: telemedicine consultation transcripts and video recordings, health profile data (conditions, recovery notes, medical history), prescription uploads, and vitals data from TeleKit device syncs. All PHI is stored separately from commercial data (orders, payments) in an isolated database schema with stricter access controls. |
| Encryption at rest | PHI stored in PostgreSQL with column-level encryption for sensitive fields (health_conditions, consultation_notes, prescription_image_url). AWS KMS manages encryption keys. S3 buckets storing telemedicine recordings and prescription PDFs use SSE-KMS with a separate key from non-PHI assets. |
| Encryption in transit | TLS 1.3 minimum on all connections. HSTS (HTTP Strict Transport Security) with 1-year max-age. Certificate pinning on the MGRM Health mobile app. Telemedicine video streams use end-to-end encryption (WebRTC DTLS-SRTP via Doxy.me or Daily.co). |
| Access controls | PHI access requires role: CLINICAL_STAFF, PHARMACIST, or ACCOUNT_HOLDER (the patient themselves). No marketing, sales, or operational staff roles have access to PHI. Auth0 RBAC enforces this. All PHI access is logged to an immutable audit log (AWS CloudTrail). |
| Data retention | Telemedicine consultation records: retained for 7 years (MoHFW Telemedicine Guidelines 2020 requirement for medical records). Health profile data: retained while the account is active + 2 years after deletion request, then permanently purged. Prescription uploads: retained for 6 months then auto-purged unless flagged by pharmacist. |
| Business Associate Agreements | BAAs signed with all third-party vendors who handle PHI: telemedicine API provider (Doxy.me/Daily.co), AWS (hosting), Auth0 (identity — if Auth0 Actions touch health data), and any analytics tool that processes health profile data. |
| Breach notification | Incident response plan defines notification timelines: CERT-In (India) within 6 hours of breach discovery (as required by CERT-In 2022 directions). Affected users notified within 72 hours. If HIPAA-aligned: US HHS notification within 60 days of discovery of a breach affecting 500+ US residents. |
| Data protection compliance — India DPDPA 2023 | |
|---|---|
| Consent management | Explicit, informed consent collected at account registration for: (1) Processing personal data for order fulfilment. (2) Processing health data for telemedicine and health profile. (3) Marketing communications (separate opt-in, not bundled with account creation). Consent records stored with timestamp, user ID, and consent text version. |
| Data Principal rights | DPDPA grants users rights to: access their data, correct inaccurate data, erase their data (subject to legal hold for medical records), nominate a representative, and withdraw consent. These rights are implemented in the /my-account settings page with self-service controls where possible, and a 30-day fulfilment SLA for manual requests. |
| Data Fiduciary obligations | MGRM is a Data Fiduciary under DPDPA. A Data Protection Officer (DPO) is designated. Privacy Policy is published at /privacy-policy. A Data Protection Impact Assessment (DPIA) is conducted for the telemedicine health data processing before launch. |
| Cross-border data transfers | Personal data of Indian residents is stored on AWS servers in the Mumbai (ap-south-1) region. No personal data is transferred outside India without explicit consent. If analytics tools (GA4, Mixpanel) process data outside India, standard contractual clauses and data processing agreements are in place. |
| Cookie consent | Cookie consent banner on first visit (B2C site only). Categories: Essential (always on), Analytics (opt-in), Marketing (opt-in). The B2B portal sets session cookies only — no marketing cookies in the authenticated portal. Cookie preferences stored in the user's browser and account preferences. |
| Children's data | MGRM B2C site: minimum age 18 for account creation (except where a parent/guardian registers for a child's paediatric telemedicine consultation). Age verification at registration. The telemedicine service for children under 12 requires a parent to be present — this is verified in the consultation booking flow. |
| Compliance certificate download security and audit logging | |
|---|---|
| Document storage | All compliance documents (ISO certificates, CE declarations, CDSCO licences, MSDS, IFUs) are stored in a private AWS S3 bucket: mgrm-compliance-docs-private. No public access. The bucket is not accessible via direct S3 URL. |
| Download mechanism | When an authenticated institutional user requests a document download, the Next.js API route: (1) Validates the user's B2B session token. (2) Logs the download event (user ID, institution ID, document ID, timestamp, IP address) to the audit log database. (3) Generates a pre-signed S3 URL valid for 1 hour. (4) Returns the pre-signed URL to the client. The client's browser downloads directly from S3 — MGRM servers are not in the download bandwidth path. |
| Audit log | Every document download is logged to an immutable audit table in PostgreSQL (INSERT-only, no UPDATE/DELETE permissions for application users). Log fields: document_id, document_name, institution_id, user_id, user_email, download_timestamp, ip_address, user_agent. Retained for 3 years. Accessible to MGRM compliance team via admin dashboard. |
| Document versioning | When a compliance document is renewed (e.g. ISO certificate) the new version is uploaded to S3 with a version suffix. The old version is retained (not deleted) for audit trail purposes — if a hospital downloaded a certificate on a specific date, MGRM can prove what version was current on that date. |
| Dossier generation | The "Download all compliance documents" feature generates a ZIP file server-side from the current document set. The ZIP is generated on demand (not pre-built) and the pre-signed download URL expires in 4 hours. ZIP generation is also audit-logged. |
| Access control per document | Some documents are Tier 2+ only (e.g. marketing collateral, co-branded templates). The API route checks the user's customer group claim in the JWT before generating the pre-signed URL — attempting to download a Tier 3 document with a Tier 1 token returns HTTP 403. |
| PCI DSS compliance — consumer checkout | |
|---|---|
| Compliance level | MGRM is a PCI DSS Level 4 merchant (fewer than 20,000 Visa/Mastercard e-commerce transactions per year initially). Annual Self-Assessment Questionnaire (SAQ A) is required — applicable because card data is fully handled by Razorpay, not MGRM servers. |
| Cardholder data scope | Card numbers, CVVs, and expiry dates NEVER touch MGRM servers or databases. The Razorpay Hosted Checkout or Razorpay.js (embedded tokenisation) handles all card input — card data goes directly from the user's browser to Razorpay's PCI DSS Level 1 certified servers. MGRM receives only a Razorpay payment ID and masked card details (last 4 digits, card brand). |
| Network segmentation | The payment processing domain (mgrmmedicare.com/checkout) is served from Vercel's edge network. No payment data is routed through MGRM's application servers or stored in MGRM's database. AWS infrastructure hosting the Medusa.js backend is logically separated from any payment processing network segments. |
| Vulnerability scanning | Quarterly ASV (Approved Scanning Vendor) scans of external-facing IP addresses and domains. Annual penetration test by a PCI SSC approved QSA. Cloudflare WAF provides real-time protection against OWASP Top 10 attacks. |
| Razorpay integration security | Razorpay webhook signatures are verified using HMAC-SHA256 on every incoming webhook — preventing order manipulation via forged webhook events. Razorpay API keys are stored in environment variables (Vercel encrypted env vars) — never in code or git repositories. |
| UPI and wallet payments | UPI and digital wallet payments (GPay, PhonePe, Paytm) are processed via Razorpay's VPA (Virtual Payment Address) system — no card data involved, no PCI DSS scope. MGRM receives the UPI transaction reference ID. |
A complete pre-launch checklist covering B2C site, B2B microsite, and integrated testing. All 25 items must be confirmed by the responsible team member before the site goes live. Items are colour-coded by domain: B2C (blue) · B2B (navy) · Integrated (teal) · Security (orange).