MedusaJS v2 Development Setup Runbook¶
This runbook covers everything needed to bootstrap the Research Relay MedusaJS v2 development environment. Follow it step-by-step when setting up the project for the first time.
Separate Repository
Actual Medusa development happens in a separate repository, not this documentation repo (rr-bizops). This runbook documents the setup procedure for that project repo.
1. Prerequisites¶
1.1 Required Software¶
| Software | Version | Notes |
|---|---|---|
| Node.js | v20+ LTS | v22 LTS recommended. v25+ is not supported with the Next.js Starter Storefront. |
| PostgreSQL | 14+ | Must be installed and running before project creation. |
| Redis | 7+ | Optional for local development. Required for production (event bus, workflow engine, caching). |
| Git | Latest | Required by create-medusa-app. |
| yarn or pnpm | Latest | pnpm is recommended for faster installations. This runbook uses yarn to match the project plan. |
1.2 Verify Prerequisites¶
# Check Node.js version (must be v20+)
node -v
# Check PostgreSQL is running
pg_isready
# Check Git
git --version
# Check yarn
yarn --version
1.3 PostgreSQL Setup¶
If PostgreSQL is not yet running locally:
1.4 Redis Setup (Optional for Development)¶
Redis is not required for local development. Medusa v2 uses in-memory implementations for the event bus and workflow engine in development mode. For production-like testing:
2. Project Initialization¶
2.1 Scaffold the Medusa Project¶
This command:
- Creates a Medusa application in a
research-relay/directory - Sets up a PostgreSQL database named
research-relay - Installs the Medusa server (Node.js) and embedded Vite admin dashboard
- Installs the Next.js Starter Storefront in a
research-relay-storefront/directory - Prompts you to create an initial admin user
If you already have a database or want to skip database creation:
# Use an existing database
yarn dlx create-medusa-app@latest research-relay \
--db-url postgres://postgres@localhost/research-relay \
--with-nextjs-starter
# Skip database setup entirely (configure later)
yarn dlx create-medusa-app@latest research-relay \
--skip-db \
--with-nextjs-starter
2.2 Verify Initial Setup¶
After the installation completes:
cd research-relay
# The Medusa server should be running at http://localhost:9000
# The admin dashboard should be at http://localhost:9000/app
# The storefront (if installed) at http://localhost:8000
Stop the server (Ctrl+C), then verify the file structure exists:
2.3 Initialize Git Repository¶
3. Project Directory Structure¶
After scaffolding and adding all custom modules from the project plan, the full directory structure will be:
research-relay/
├── .medusa/ # Auto-generated types (do NOT modify or commit)
├── src/
│ ├── admin/ # Admin dashboard customizations
│ │ ├── routes/ # Custom UI routes (new pages)
│ │ │ ├── compliance/ # Compliance management pages
│ │ │ │ └── page.tsx
│ │ │ └── settings/ # Custom settings pages
│ │ │ └── compliance/
│ │ │ └── page.tsx
│ │ └── widgets/ # Widgets injected into existing pages
│ │ └── product-compliance-widget.tsx
│ ├── api/ # Custom API routes
│ │ ├── admin/ # Admin-authenticated routes
│ │ │ ├── compliance/
│ │ │ │ └── route.ts
│ │ │ └── coa/
│ │ │ └── route.ts
│ │ ├── store/ # Customer-authenticated routes
│ │ │ └── compliance/
│ │ │ └── route.ts
│ │ ├── hooks/ # Webhook endpoints
│ │ │ └── btcpay/
│ │ │ └── route.ts
│ │ └── middlewares.ts # Route middleware definitions
│ ├── jobs/ # Scheduled jobs (cron tasks)
│ │ └── sync-accounting.ts
│ ├── links/ # Module links (cross-module associations)
│ │ ├── product-compliance.ts
│ │ ├── cart-attestation.ts
│ │ └── order-attestation.ts
│ ├── modules/ # Custom modules
│ │ ├── product-compliance/ # RUO compliance module
│ │ │ ├── models/
│ │ │ │ ├── lot.ts
│ │ │ │ ├── coa.ts
│ │ │ │ ├── purity-record.ts
│ │ │ │ └── ruo-disclaimer.ts
│ │ │ ├── migrations/
│ │ │ ├── loaders/
│ │ │ ├── __tests__/
│ │ │ ├── service.ts
│ │ │ └── index.ts
│ │ ├── compliance-checkout/# Checkout compliance module
│ │ │ ├── models/
│ │ │ │ └── checkout-attestation.ts
│ │ │ ├── migrations/
│ │ │ ├── __tests__/
│ │ │ ├── service.ts
│ │ │ └── index.ts
│ │ ├── btcpay/ # BTCPay payment provider
│ │ │ ├── __tests__/
│ │ │ ├── client.ts
│ │ │ ├── types.ts
│ │ │ ├── service.ts
│ │ │ └── index.ts
│ │ ├── authorize-net/ # Authorize.net payment provider
│ │ │ ├── __tests__/
│ │ │ ├── client.ts
│ │ │ ├── types.ts
│ │ │ ├── service.ts
│ │ │ └── index.ts
│ │ ├── shipstation/ # ShipStation fulfillment provider
│ │ │ ├── __tests__/
│ │ │ ├── client.ts
│ │ │ ├── types.ts
│ │ │ ├── service.ts
│ │ │ └── index.ts
│ │ └── avalara/ # Avalara tax provider
│ │ ├── __tests__/
│ │ ├── types.ts
│ │ ├── service.ts
│ │ └── index.ts
│ ├── scripts/ # Custom CLI scripts
│ │ └── seed.ts
│ ├── subscribers/ # Event handlers
│ │ ├── order-placed.ts
│ │ └── payment-captured.ts
│ └── workflows/ # Custom workflow definitions
│ ├── create-compliant-product.ts
│ ├── process-btcpay-payment.ts
│ └── validate-compliance-checkout.ts
├── medusa-config.ts # Application configuration
├── package.json
├── tsconfig.json
└── .env # Environment variables (do NOT commit)
3.1 Key Conventions¶
| Customization | Location | Pattern |
|---|---|---|
| Custom modules | src/modules/<name>/ |
Module() export in index.ts, service in service.ts, models in models/ |
| Module providers | src/modules/<name>/ |
ModuleProvider() export in index.ts for payment/fulfillment/tax |
| Custom API routes | src/api/<path>/route.ts |
Export named HTTP methods (GET, POST, etc.) |
| Subscribers | src/subscribers/<name>.ts |
Default export = handler function, named export config = event subscription |
| Scheduled jobs | src/jobs/<name>.ts |
Default export = job function, named export config = schedule |
| Workflows | src/workflows/<name>.ts |
createWorkflow() composing createStep() functions |
| Admin widgets | src/admin/widgets/<name>.tsx |
React component + defineWidgetConfig() |
| Admin UI routes | src/admin/routes/<path>/page.tsx |
React component + defineRouteConfig() |
| Module links | src/links/<name>.ts |
defineLink() between module data models |
4. Environment Variables¶
4.1 Environment Variable Template¶
Create .env in the project root (this file must NOT be committed):
# ============================================================
# Research Relay -- Medusa v2 Environment Variables
# ============================================================
# Copy this file to .env and fill in values.
# Do NOT commit .env to version control.
# ============================================================
# ----------------------------------------------------------
# Core / Database
# ----------------------------------------------------------
DATABASE_URL=postgres://postgres@localhost/research-relay
NODE_ENV=development
# ----------------------------------------------------------
# Redis (optional for dev, required for production)
# ----------------------------------------------------------
# REDIS_URL=redis://localhost:6379
# ----------------------------------------------------------
# HTTP / CORS / Auth
# ----------------------------------------------------------
STORE_CORS=http://localhost:8000
ADMIN_CORS=http://localhost:9000
AUTH_CORS=http://localhost:8000,http://localhost:9000
JWT_SECRET=your-super-secret-jwt-key-change-me
COOKIE_SECRET=your-super-secret-cookie-key-change-me
# ----------------------------------------------------------
# BTCPay Server (Phase C)
# ----------------------------------------------------------
# BTCPAY_SERVER_URL=https://btcpay.researchrelay.com
# BTCPAY_STORE_ID=
# BTCPAY_API_KEY=
# BTCPAY_WEBHOOK_SECRET=
# ----------------------------------------------------------
# Authorize.net (Phase D)
# ----------------------------------------------------------
# AUTHNET_API_LOGIN_ID=
# AUTHNET_TRANSACTION_KEY=
# AUTHNET_SIGNATURE_KEY=
# AUTHNET_ENVIRONMENT=sandbox
# ----------------------------------------------------------
# Stripe ACH (conditional -- uncomment if approved)
# ----------------------------------------------------------
# STRIPE_API_KEY=
# ----------------------------------------------------------
# Avalara / AvaTax (Phase G)
# ----------------------------------------------------------
# AVALARA_USERNAME=
# AVALARA_PASSWORD=
# AVALARA_COMPANY_CODE=
# AVALARA_COMPANY_ID=
# AVALARA_ENVIRONMENT=sandbox
# ----------------------------------------------------------
# SendGrid (Phase H+)
# ----------------------------------------------------------
# SENDGRID_API_KEY=
# SENDGRID_FROM=orders@researchrelay.com
# ----------------------------------------------------------
# ShipStation (Phase F)
# ----------------------------------------------------------
# SHIPSTATION_API_KEY=
# ----------------------------------------------------------
# Production Worker Mode (deployment only)
# ----------------------------------------------------------
# MEDUSA_WORKER_MODE=shared
# DISABLE_MEDUSA_ADMIN=false
# MEDUSA_BACKEND_URL=https://api.researchrelay.com
4.2 Generate Secrets¶
For JWT_SECRET and COOKIE_SECRET, generate cryptographically secure random strings:
# Using openssl
openssl rand -hex 32
# Or using Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
5. Medusa Configuration¶
5.1 medusa-config.ts¶
The medusa-config.ts file is the central configuration file. After scaffolding, update it to match the project plan. The full configuration with all modules registered:
import { loadEnv, defineConfig, Modules } from "@medusajs/framework/utils"
loadEnv(process.env.NODE_ENV || "development", process.cwd())
module.exports = defineConfig({
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
redisUrl: process.env.REDIS_URL,
http: {
storeCors: process.env.STORE_CORS!,
adminCors: process.env.ADMIN_CORS!,
authCors: process.env.AUTH_CORS!,
jwtSecret: process.env.JWT_SECRET || "supersecret",
cookieSecret: process.env.COOKIE_SECRET || "supersecret",
},
workerMode: process.env.MEDUSA_WORKER_MODE as
| "shared"
| "worker"
| "server"
| undefined,
},
admin: {
disable: process.env.DISABLE_MEDUSA_ADMIN === "true",
backendUrl: process.env.MEDUSA_BACKEND_URL,
},
modules: [
// Custom modules
{ resolve: "./src/modules/product-compliance" },
{ resolve: "./src/modules/compliance-checkout" },
// Payment providers
{
resolve: "@medusajs/medusa/payment",
options: {
providers: [
{
resolve: "./src/modules/btcpay",
id: "btcpay",
options: {
serverUrl: process.env.BTCPAY_SERVER_URL,
storeId: process.env.BTCPAY_STORE_ID,
apiKey: process.env.BTCPAY_API_KEY,
webhookSecret: process.env.BTCPAY_WEBHOOK_SECRET,
},
},
{
resolve: "./src/modules/authorize-net",
id: "authorize-net",
options: {
apiLoginId: process.env.AUTHNET_API_LOGIN_ID,
transactionKey: process.env.AUTHNET_TRANSACTION_KEY,
signatureKey: process.env.AUTHNET_SIGNATURE_KEY,
environment: process.env.AUTHNET_ENVIRONMENT || "sandbox",
},
},
],
},
},
// Tax provider
{
resolve: "@medusajs/medusa/tax",
options: {
providers: [
{
resolve: "./src/modules/avalara",
id: "avalara",
options: {
username: process.env.AVALARA_USERNAME,
password: process.env.AVALARA_PASSWORD,
companyCode: process.env.AVALARA_COMPANY_CODE,
companyId: parseInt(process.env.AVALARA_COMPANY_ID || "0"),
appEnvironment: process.env.AVALARA_ENVIRONMENT || "sandbox",
},
},
],
},
},
// Notification provider
{
resolve: "@medusajs/medusa/notification",
options: {
providers: [
{
resolve: "@medusajs/medusa/notification-sendgrid",
id: "sendgrid",
options: {
channels: ["email"],
api_key: process.env.SENDGRID_API_KEY,
from: process.env.SENDGRID_FROM,
},
},
],
},
},
// Fulfillment provider
{
resolve: "@medusajs/medusa/fulfillment",
options: {
providers: [
{
resolve: "@medusajs/medusa/fulfillment-manual",
id: "manual",
},
{
resolve: "./src/modules/shipstation",
id: "shipstation",
options: {
api_key: process.env.SHIPSTATION_API_KEY,
},
},
],
},
},
],
})
Incremental Registration
You do not need all modules registered from the start. Register them as you build each phase. Start Phase A with just the vanilla config (no custom modules), and add modules as each phase is completed.
6. Database Setup and Migrations¶
6.1 Initial Database Setup¶
The create-medusa-app CLI creates the database automatically. If you need to set it up manually:
# Create the database
yarn medusa db:create --db research-relay
# Or set up database, run migrations, and sync links in one command
yarn medusa db:setup --db research-relay
6.2 Generating Migrations¶
When you create or modify data models in a custom module, generate migration files:
# Generate migrations for a specific module
yarn medusa db:generate productComplianceModule
# Generate migrations for multiple modules at once
yarn medusa db:generate productComplianceModule complianceCheckoutModule
This creates migration files in the module's migrations/ directory based on the data model definitions.
6.3 Running Migrations¶
# Run all pending migrations and sync links
yarn medusa db:migrate
# Skip link syncing (rare)
yarn medusa db:migrate --skip-links
6.4 Rolling Back Migrations¶
6.5 Seeding Data¶
A custom seed script for Research Relay should:
- Create test products with variants (peptides with different sizes)
- Create lots linked to product variants
- Create COAs with purity records for each lot
- Create a sample RUO disclaimer
- Set up test payment providers in regions
- Configure a US region with USD currency
7. Development Workflow¶
7.1 Start the Development Server¶
This starts:
- Medusa server at
http://localhost:9000 - Admin dashboard at
http://localhost:9000/app - File watcher that recompiles on changes to
src/(admin customizations are hot-reloaded)
7.2 Start the Storefront¶
In a separate terminal, from the storefront directory:
The Next.js Starter Storefront runs at http://localhost:8000.
7.3 Package Scripts Reference¶
These are the standard scripts in package.json:
{
"scripts": {
"dev": "medusa develop",
"build": "medusa build",
"start": "medusa start",
"seed": "medusa exec ./src/scripts/seed.ts",
"predeploy": "medusa db:migrate",
"test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit",
"test:integration:http": "TEST_TYPE=integration:http NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
"test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit"
}
}
7.4 Common CLI Commands¶
# Start dev server
yarn dev
# Generate types (auto-runs during dev, but can run manually)
yarn medusa generate
# Database commands
yarn medusa db:generate <module_name> # Generate migration files
yarn medusa db:migrate # Run pending migrations + sync links
yarn medusa db:rollback <module_name> # Rollback last migration
yarn medusa db:setup --db <name> # Create DB + migrate + sync
# Run a custom script
yarn medusa exec ./src/scripts/<script>.ts
# Build for production
yarn build
# Start production server
yarn start
8. Testing¶
8.1 Test Structure¶
Tests live alongside the code they test, in __tests__/ directories:
src/
├── modules/
│ └── product-compliance/
│ └── __tests__/
│ ├── service.test.ts
│ └── models.test.ts
├── workflows/
│ └── __tests__/
│ └── create-compliant-product.test.ts
└── api/
└── admin/
└── compliance/
└── __tests__/
└── route.test.ts
8.2 Running Tests¶
# Unit tests
yarn test:unit
# Integration tests (HTTP / API routes)
yarn test:integration:http
# Integration tests (modules)
yarn test:integration:modules
8.3 Test Dependencies¶
The project uses Jest with SWC for fast compilation. Required dev dependencies:
{
"devDependencies": {
"@medusajs/test-utils": "2.x",
"@swc/core": "1.5.7",
"@swc/jest": "^0.2.36",
"@types/jest": "^29.5.13",
"jest": "^29.7.0"
}
}
8.4 Testing Strategy by Module Type¶
| Module Type | Test Approach | What to Test |
|---|---|---|
| Custom modules (compliance) | Unit tests | Data model validation, service methods, custom business logic |
| Payment providers (BTCPay, Authorize.net) | Unit tests with mocked HTTP | Webhook signature verification, status mapping, error handling |
| Workflows | Integration tests | Step composition, compensation/rollback logic, end-to-end flow |
| API routes | HTTP integration tests | Request validation (Zod), auth/authz, response format |
| Admin widgets | Manual + Storybook (optional) | UI renders correctly with mock data |
9. Custom Module Quick-Start Patterns¶
9.1 Creating a Standard Module¶
This pattern applies to the Product Compliance Module and Compliance Checkout Module:
Step 1: Define the data model
// src/modules/<name>/models/<model>.ts
import { model } from "@medusajs/framework/utils"
const MyModel = model.define("my_model", {
id: model.id().primaryKey(),
name: model.text(),
// ... other fields
metadata: model.json().nullable(),
})
export default MyModel
Step 2: Create the service
// src/modules/<name>/service.ts
import { MedusaService } from "@medusajs/framework/utils"
import MyModel from "./models/my-model"
class MyModuleService extends MedusaService({
MyModel,
}) {
// Auto-generated CRUD: createMyModels, retrieveMyModel,
// listMyModels, updateMyModels, deleteMyModels
}
export default MyModuleService
Step 3: Create the module definition
// src/modules/<name>/index.ts
import MyModuleService from "./service"
import { Module } from "@medusajs/framework/utils"
export const MY_MODULE = "myModule"
export default Module(MY_MODULE, {
service: MyModuleService,
})
Step 4: Register in medusa-config.ts
Step 5: Generate and run migrations
9.2 Creating a Payment Provider Module¶
This pattern applies to the BTCPay and Authorize.net modules:
Step 1: Implement the provider service
// src/modules/<name>/service.ts
import { AbstractPaymentProvider } from "@medusajs/framework/utils"
import { Logger } from "@medusajs/framework/types"
type Options = {
apiKey: string
// ... provider-specific options
}
type InjectedDependencies = {
logger: Logger
}
class MyPaymentProviderService extends AbstractPaymentProvider<Options> {
static identifier = "my-provider"
protected logger_: Logger
protected options_: Options
constructor(container: InjectedDependencies, options: Options) {
super(container, options)
this.logger_ = container.logger
this.options_ = options
}
// Must implement: initiatePayment, authorizePayment, capturePayment,
// refundPayment, cancelPayment, deletePayment, retrievePayment,
// updatePayment, getWebhookActionAndData
}
export default MyPaymentProviderService
Step 2: Create the module provider definition
// src/modules/<name>/index.ts
import MyPaymentProviderService from "./service"
import { ModuleProvider, Modules } from "@medusajs/framework/utils"
export default ModuleProvider(Modules.PAYMENT, {
services: [MyPaymentProviderService],
})
Step 3: Register in medusa-config.ts
{
resolve: "@medusajs/medusa/payment",
options: {
providers: [
{
resolve: "./src/modules/<name>",
id: "my-provider",
options: {
apiKey: process.env.MY_PROVIDER_API_KEY,
},
},
],
},
}
Webhooks are automatically handled at POST /hooks/payment/<identifier>_<id> (e.g., /hooks/payment/btcpay_btcpay).
10. Production Build and Deployment¶
10.1 Build¶
This creates a .medusa/server/ directory containing:
- Compiled JavaScript from
src/ - Production admin dashboard build
package.jsonand lock file for production dependencies
10.2 Start in Production¶
The predeploy script runs medusa db:migrate to ensure all migrations are applied.
10.3 Production Environment Variables¶
For production, set these additional variables:
MEDUSA_WORKER_MODE=server # For the server instance
# MEDUSA_WORKER_MODE=worker # For the worker instance
DISABLE_MEDUSA_ADMIN=false # false for server, true for worker
REDIS_URL=redis://<production-redis-url>
MEDUSA_BACKEND_URL=https://api.researchrelay.com
In production, deploy two instances of the Medusa application:
- Server mode -- handles API requests and serves the admin dashboard
- Worker mode -- handles background tasks (scheduled jobs, subscribers)
11. Implementation Roadmap¶
Each phase builds on the previous one. Only register modules in medusa-config.ts as you reach each phase.
Phase A: Vanilla Medusa Setup + Basic Product Catalog¶
Goal: Working Medusa v2 instance with products, regions, and basic configuration.
- Scaffold project with
create-medusa-app - Configure
medusa-config.tswith database, CORS, and session settings - Set up PostgreSQL database
- Create initial admin user
- Configure US region with USD currency
- Create product categories for peptide/chemical classifications
- Add sample products with variants (sizes, quantities)
- Install and configure Next.js Starter Storefront
- Verify storefront can browse products and admin can manage catalog
Done when: Admin dashboard is accessible, products are visible in storefront, cart and basic checkout flow works with the system (manual) payment provider.
Phase B: Product Compliance Module (Lot Tracking, COAs)¶
Goal: Custom module for lot tracking, COA management, and purity records linked to products.
- Create
src/modules/product-compliance/with data models:Lot,Coa,PurityRecord,RuoDisclaimer - Create module service extending
MedusaService - Register module in
medusa-config.ts - Define module link:
ProductVariant <-> Lot - Generate and run migrations (
yarn medusa db:generate productComplianceModule) - Create admin and store API routes for lot/COA CRUD
- Create subscribers for compliance events
- Write unit tests
Done when: Admin can create lots and upload COAs, lots are linked to product variants, public lot lookup works, COA PDFs can be downloaded.
Phase C: BTCPay Payment Integration¶
Goal: Accept BTC and Lightning payments through self-hosted BTCPay Server.
- Create
src/modules/btcpay/with payment provider service - Implement all
AbstractPaymentProvidermethods - Implement
getWebhookActionAndDatafor BTCPay webhook events - Create BTCPay Greenfield API client
- Register as payment provider in
medusa-config.ts - Configure webhook URL in BTCPay Server:
POST /hooks/payment/btcpay_btcpay - Test end-to-end with BTCPay regtest mode
- Write unit tests for webhook handler and status mapping
Done when: Customer can select BTC at checkout, BTCPay invoice is created, webhooks process payment, order is created on successful payment.
Phase D: Authorize.net Payment Integration¶
Goal: Accept card payments via Authorize.net through high-risk ISO.
- Create
src/modules/authorize-net/with payment provider service - Implement all
AbstractPaymentProvidermethods - Create Authorize.net API client
- Configure storefront to use Accept.js for PCI-compliant card tokenization
- Register as payment provider in
medusa-config.ts - Test with Authorize.net sandbox
- Write unit tests
Done when: Card authorization succeeds via sandbox, capture works on fulfillment, refund and void operations work, fraud hold webhooks are handled.
Phase E: Compliance Checkout Flow¶
Goal: Enforce RUO acknowledgment, age verification, and research-use attestation at checkout.
- Create
src/modules/compliance-checkout/withCheckoutAttestationdata model - Create module links to Cart and Order
- Create store API route for submitting attestation
- Create workflow step to validate compliance before cart completion
- Hook into cart completion workflow
- Create subscriber on
order.placedto archive attestation - Build storefront UI components for attestation form
- Write tests for validation logic
Done when: Checkout requires RUO acknowledgment + age verification + research attestation, cart cannot complete without valid attestation, attestation data is stored with the order.
Phase F: Shipping + Fulfillment (ShipStation)¶
Goal: Integrate ShipStation for shipping label generation and fulfillment management.
- Create
src/modules/shipstation/with fulfillment provider service - Implement
AbstractFulfillmentProviderServicemethods - Create ShipStation API client
- Register as fulfillment provider in
medusa-config.ts - Configure shipping options in admin
- Test shipping rate calculation and label purchase
Done when: Shipping rates appear at checkout, fulfillment creates ShipStation shipment, labels can be purchased, tracking numbers sync back to Medusa.
Phase G: Tax Calculation (Avalara)¶
Goal: Integrate Avalara/AvaTax for accurate tax calculation.
- Create
src/modules/avalara/with tax provider service implementingITaxProvider - Implement
getTaxLines()using AvaTax SDK - Register as tax provider in
medusa-config.ts - Create subscribers for product sync and transaction commit
- Test with Avalara sandbox
Done when: Tax is calculated correctly during checkout, tax line items appear on cart/order, transactions are committed in Avalara.
Phase H: Admin UI Customizations¶
Goal: Custom admin dashboard widgets and pages for compliance management.
- Product detail widget showing lot/COA data
- Order detail widget showing compliance attestation
- Compliance dashboard UI route (
/admin/compliance) - Compliance settings page (
/admin/settings/compliance) - COA upload form and lot management pages
- Style using
@medusajs/uicomponents
Done when: Product pages show linked lots and COAs, order pages show attestation, full compliance dashboard is functional.
Phase I: Accounting Sync Automation¶
Goal: Automated sync of order/payment data to Zoho Books with Mercury bank reconciliation.
- Scheduled job for daily order sync to Zoho Books
- Subscriber on
order.placedto create Zoho invoice - Subscriber on
order.payment_capturedto record payment - Scheduled job for Mercury bank reconciliation
- Admin settings page for accounting configuration
Done when: Orders automatically create Zoho invoices, payments record receipts, Mercury transactions reconcile against Medusa orders.
12. Useful Links¶
| Resource | URL |
|---|---|
| Medusa v2 Documentation | docs.medusajs.com |
| Medusa CLI Reference | docs.medusajs.com/resources/medusa-cli |
| Create Medusa App Reference | docs.medusajs.com/resources/create-medusa-app |
| Payment Provider Guide | docs.medusajs.com/resources/references/payment/provider |
| Module Development Guide | docs.medusajs.com/learn/fundamentals/modules |
| Data Model Language (DML) | docs.medusajs.com/learn/fundamentals/data-models |
| Workflows Guide | docs.medusajs.com/learn/fundamentals/workflows |
| Deployment Guide | docs.medusajs.com/learn/deployment/general |
| RR Project Plan | Medusa Project Plan |
| BTCPay Architecture | BTCPay Architecture |
| ISO Options | ISO Options |