Table of Contents

#SectionPage
1Table of ContentsTop
2System Overview2.1
3Technology Stack3.1
4Prerequisites4.1
5Configuration Guide5.1
 Environment Variables5.2
 shopify.app.toml5.3
 TypeScript & Vite Config5.4
6Database Schema6.1
7API Routes7.1
8Data Flow Architecture8.1
9Analytics Engine9.1
10AI Integration10.1
11Installation Steps11.1
12File Structure12.1
13Deployment13.1
14Pricing & Plans14.1

System Overview

MTS AI Business Intelligence is an embedded Shopify application that provides real-time analytics dashboards, AI-powered insights, and comprehensive business intelligence directly within the Shopify admin panel. The app synchronizes store data via webhooks and the GraphQL Admin API, stores it locally, and surfaces actionable metrics through an intuitive React-based UI.

Application
MTS AI Business Intelligence
Version
1.0.0
Architecture
Embedded Shopify App
Runs inside Shopify admin iframe
API Version
2024-10
Shopify GraphQL Admin API

Core Capabilities

Technology Stack

The application leverages a modern, full-stack JavaScript/TypeScript stack optimized for the Shopify embedded app ecosystem.

TechnologyVersionPurpose
React Router v7 7.x SSR-enabled framework (formerly Remix) with file-based routing for server-rendered pages
Shopify Polaris 13.x Shopify's design system providing consistent UI components for embedded admin apps
Recharts 2.x Declarative charting library built on D3 for sales analytics visualizations
Prisma 6.x Next-generation ORM for type-safe database access with SQLite
SQLite Lightweight embedded relational database for local data storage
OpenAI GPT-4 Natural language AI insights, daily briefs, and conversational analytics
TypeScript 5.x Type-safe JavaScript with strict mode, path aliases, and full type coverage
Vite 6.x Next-generation frontend tooling for fast development and optimized production builds

Supporting Libraries

PackagePurpose
@shopify/shopify-app-remixShopify app authentication and session management
@shopify/polarisUI component library (Layout, Card, DataTable, etc.)
@prisma/clientPrisma database client
openaiOfficial OpenAI SDK for GPT-4 API calls
rechartsChart components (LineChart, BarChart, PieChart)

Prerequisites

Before setting up the development environment, ensure the following requirements are met:

RequirementDetailsStatus Check
Node.js Version 18+ (LTS recommended, v20 preferred) node --version
Package Manager npm (bundled) or yarn 1.x npm --version
Shopify Partner Account Required for app creation and API credentials partners.shopify.com
Shopify Development Store Test environment for app installation and data sync Create via Partner Dashboard
Custom App Created in Partner Dashboard with required scopes and embedded setting App credentials (API key, secret)
OpenAI API Key Required for AI-powered insights (optional, has fallback) OPENAI_API_KEY env var
Required Access Scopes

The custom Shopify app must request these scopes: read_orders, read_products, read_customers, read_inventory, read_analytics, read_content

Configuration Guide

The application requires configuration across multiple files for environment variables, Shopify app manifest, TypeScript compilation, and build tooling.

Environment Variables (.env)

Create a .env file in the project root by copying from .env.example:

# ─── Shopify App Credentials ───
SHOPIFY_API_KEY=your_shopify_api_key_here
SHOPIFY_API_SECRET=your_shopify_api_secret_here
SCOPES=read_orders,read_products,read_customers,read_inventory,read_analytics,read_content

# ─── App URLs ───
SHOPIFY_APP_URL=https://your-app-domain.com
HOST=0.0.0.0
PORT=5173

# ─── Database ───
DATABASE_URL="file:./dev.db"

# ─── AI Integration ───
OPENAI_API_KEY=sk-your-openai-api-key-here
VariableRequiredDescription
SHOPIFY_API_KEYYesClient ID from your Shopify custom app
SHOPIFY_API_SECRETYesAPI secret for HMAC verification and token exchange
SCOPESYesComma-separated OAuth scopes
SHOPIFY_APP_URLYesPublic URL where the app is hosted
DATABASE_URLYesSQLite connection string (file path)
OPENAI_API_KEYNoOpenAI key for GPT-4 insights (rule-based fallback if omitted)
HOSTNoServer bind address (default: 0.0.0.0)
PORTNoServer port (default: 5173)

shopify.app.toml

The Shopify app manifest defines the app's metadata, access scopes, authentication redirects, webhook subscriptions, and app proxy configuration.

# shopify.app.toml

client_id = "your_client_id"
name = "MTS AI Business Intelligence"
handle = "mts-ai-business-intelligence"
application_url = "https://your-app-domain.com"
embedded = true

# ─── Access Scopes ───
[access_scopes]
scopes = "read_orders,read_products,read_customers,read_inventory,read_analytics,read_content"

# ─── Auth Redirects ───
[auth]
redirect_urls = [
  "https://your-app-domain.com/auth/callback",
  "https://your-app-domain.com/auth/shopify/callback"
]

# ─── Webhook Subscriptions ───
[[webhook_subscriptions]]
topic = "orders/create"
uri = "https://your-app-domain.com/webhooks"

[[webhook_subscriptions]]
topic = "orders/update"
uri = "https://your-app-domain.com/webhooks"

[[webhook_subscriptions]]
topic = "orders/fulfilled"
uri = "https://your-app-domain.com/webhooks"

[[webhook_subscriptions]]
topic = "products/create"
uri = "https://your-app-domain.com/webhooks"

[[webhook_subscriptions]]
topic = "products/update"
uri = "https://your-app-domain.com/webhooks"

[[webhook_subscriptions]]
topic = "products/delete"
uri = "https://your-app-domain.com/webhooks"

[[webhook_subscriptions]]
topic = "customers/create"
uri = "https://your-app-domain.com/webhooks"

[[webhook_subscriptions]]
topic = "customers/update"
uri = "https://your-app-domain.com/webhooks"

# ─── App Proxy ───
[app_proxy]
subpath = "apps/mts-ai-bi"
replace = true
prefix = "apps"

TypeScript & Vite Configuration

tsconfig.json

{
  "include": [
    "env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "app/routes/**/*.ts"
  ],
  "compilerOptions": {
    "lib": ["DOM", "DOM.Iterable", "ES2022"],
    "types": ["@shopify/cli"],
    "isolatedModules": true,
    "esModuleInterop": true,
    "jsx": "react-jsx",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "resolveJsonModule": true,
    "target": "ES2022",
    "strict": true,
    "allowJs": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "paths": {
      "~/*": ["./app/*"]
    },
    "noEmit": true
  }
}

vite.config.ts

import { vitestConfigGenerator } from "@shopify/hydrogen/vite";
import { hydrogen } from "@shopify/hydrogen/vite";
import { oxygen } from "@shopify/mini-oxygen/vite";
import { vitePlugin } from "@shopify/remix-oxygen/vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [
    hydrogen,
    vitePlugin({
      presets: [],
      serverConditions: ["worker"],
    }),
    oxygen(),
  ],
  test: vitestConfigGenerator({
    pools: ["forks"],
    poolOptions: { forks: { singleFork: true } },
  }),
});

react-router.config.ts

import { defineConfig } from "@shopify/remix-oxygen/react-router";

export default defineConfig({
  future: {
    v3_fetcherPersist: true,
    v3_relativeSplatPath: true,
    v3_throwAbortReason: true,
    v3_lazyRouteDiscovery: true,
    v3_singleFetch: true,
    v3_optimizeDeps: true,
  },
  ssr: true,
});

Database Schema

The application uses Prisma 6.x as the ORM with SQLite as the embedded database. The schema defines 11 models covering session storage, user management, data synchronization, analytics caching, and AI conversation history.

// prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

// ─── Session Storage ───
model Session {
  id           String   @id
  shop         String
  state        String
  isOnline     Boolean  @default(false)
  scope        String?
  accessToken  String
  expires      DateTime?
  userId       String?
  user         User?    @relation(fields: [userId], references: [id])
  accounts     Account[]
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  @@index([shop])
  @@map("Session")
}

// ─── User ───
model User {
  id           String   @id
  email        String   @unique
  name         String?
  role         String   @default("merchant")
  sessions     Session[]
  accounts     Account[]
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt
  @@map("User")
}

// ─── Account ───
model Account {
  id           String   @id
  userId       String
  user         User     @relation(fields: [userId], references: [id])
  sessionId    String?
  session      Session? @relation(fields: [sessionId], references: [id])
  type         String
  createdAt    DateTime @default(now())
  @@map("Account")
}

// ─── Synced Order ───
model SyncedOrder {
  id              String              @id
  shopId          String
  shopifyId       String              @unique
  orderNumber     Int
  name            String
  email           String?
  totalPrice      Float
  subtotalPrice   Float
  totalTax        Float              @default(0)
  totalDiscounts  Float              @default(0)
  currency        String             @default("USD")
  financialStatus String?
  fulfillmentStatus String?
  customerName    String?
  customerEmail   String?
  shippingAddress String?
  createdAt       DateTime           @default(now())
  updatedAt       DateTime           @updatedAt
  syncedAt        DateTime           @default(now())
  lineItems       SyncedOrderItem[]

  @@index([shopId])
  @@index([createdAt])
  @@map("SyncedOrder")
}

// ─── Synced Order Item ───
model SyncedOrderItem {
  id              String   @id
  orderId         String
  order           SyncedOrder @relation(fields: [orderId], references: [id])
  shopifyId       String?
  title           String
  quantity        Int
  price           Float
  totalDiscount   Float    @default(0)
  sku             String?
  vendor          String?
  productTitle    String?
  variantTitle    String?
  productId       String?
  variantId       String?
  createdAt       DateTime @default(now())
  @@index([orderId])
  @@index([productId])
  @@map("SyncedOrderItem")
}

// ─── Synced Product ───
model SyncedProduct {
  id              String   @id
  shopId          String
  shopifyId       String   @unique
  title           String
  description     String?
  vendor          String?
  productType     String?
  status          String   @default("ACTIVE")
  handle          String?
  tags            String?
  totalInventory  Int      @default(0)
  totalVariants   Int      @default(0)
  imageSrc        String?
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt
  syncedAt        DateTime @default(now())
  variants        SyncedProductVariant[]

  @@index([shopId])
  @@map("SyncedProduct")
}

// ─── Synced Product Variant ───
model SyncedProductVariant {
  id              String   @id
  productId       String
  product         SyncedProduct @relation(fields: [productId], references: [id])
  shopifyId       String   @unique
  title           String
  sku             String?
  price           Float
  compareAtPrice  Float?
  inventory       Int      @default(0)
  inventoryPolicy String?
  weight          Float?
  weightUnit      String?
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt
  syncedAt        DateTime @default(now())
  @@index([productId])
  @@map("SyncedProductVariant")
}

// ─── Synced Customer ───
model SyncedCustomer {
  id              String   @id
  shopId          String
  shopifyId       String   @unique
  email           String?
  firstName       String?
  lastName        String?
  phone           String?
  totalSpent      Float    @default(0)
  ordersCount     Int      @default(0)
  averageOrderValue Float  @default(0)
  tags            String?
  state           String?
  city            String?
  country         String?
  lastOrderAt     DateTime?
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt
  syncedAt        DateTime @default(now())
  @@index([shopId])
  @@map("SyncedCustomer")
}

// ─── Analytics Snapshot ───
model AnalyticsSnapshot {
  id              String   @id
  shopId          String
  type            String
  period          String
  data            String   // JSON serialized analytics
  expiresAt       DateTime
  createdAt       DateTime @default(now())
  @@index([shopId, type, period])
  @@map("AnalyticsSnapshot")
}

// ─── AI Insight ───
model AiInsight {
  id              String   @id
  shopId          String
  question        String
  response        String
  type            String   @default("chat")
  context         String?  // JSON context used for generation
  model           String?  // "gpt-4" or "rule-based"
  createdAt       DateTime @default(now())
  @@index([shopId])
  @@map("AiInsight")
}

// ─── App Settings ───
model AppSettings {
  id              String   @id
  shopId          String   @unique
  openaiApiKey    String?
  syncEnabled     Boolean  @default(true)
  syncInterval    Int      @default(3600)
  autoSync        Boolean  @default(true)
  aiEnabled       Boolean  @default(true)
  dashboardLayout String?
  customFields    String?  // JSON
  lastSyncAt      DateTime?
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt
  @@map("AppSettings")
}

Schema Relationships

Session
id String @id
shop String
accessToken String
userId → User
User
id String @id
email String @unique
role String
→ Session[]
SyncedOrder
id String @id
shopifyId String @unique
totalPrice Float
→ SyncedOrderItem[]
SyncedOrderItem
id String @id
orderId → SyncedOrder
title, price, qty
productTitle, variantTitle
SyncedProduct
id String @id
shopifyId String @unique
title String
→ SyncedProductVariant[]
SyncedProductVariant
id String @id
productId → SyncedProduct
price, inventory
sku String?
SyncedCustomer
id String @id
shopifyId String @unique
totalSpent, ordersCount
averageOrderValue
AiInsight
id String @id
question, response
type "chat" | "brief"
model "gpt-4" | "rule-based"
AppSettings
shopId String @unique
openaiApiKey String?
syncEnabled, aiEnabled
lastSyncAt DateTime?

API Routes

All routes are defined using React Router v7 file-based conventions. Loader functions handle data fetching on GET requests; action functions handle mutations on POST requests.

MethodRouteFileDescription
GET /app app/routes/app._index.tsx Dashboard — Loader fetches aggregated analytics (KPIs, recent orders, top products, customer summary)
GET /app/sales app/routes/app.sales.tsx Sales Analytics — Loader fetches revenue, total orders, AOV, and time-series chart data grouped by day/week/month
GET /app/products app/routes/app.products.tsx Product Performance — Loader fetches products with variants, sorted by revenue using SyncedOrderItem
GET /app/customers app/routes/app.customers.tsx Customer Analytics — Loader fetches customer metrics (segments, LTV, top customers) and order history
GET /app/inventory app/routes/app.inventory.tsx Inventory Health — Loader fetches inventory items with stock status classification (in-stock, low-stock, out-of-stock)
GET /app/insights app/routes/app.insights._index.tsx AI Insights — Loader fetches analytics summary, revenue forecast, and chat history from AiInsight table
POST /app/insights app/routes/app.insights._index.tsx AI Chat — Action calls generateAiInsight(), stores question/response in AiInsight, returns rendered response
GET /app/settings app/routes/app.settings.tsx Settings — Loader fetches per-store AppSettings (OpenAI key, sync config, AI toggle)
POST /app/settings app/routes/app.settings.tsx Save Settings / Trigger Sync — Action saves AppSettings or triggers manual data synchronization
POST /api/sync app/routes/api.sync.tsx Data Sync Endpoint — Fetches data from Shopify GraphQL API and upserts to SQLite
POST /api/ai app/routes/api.ai.tsx AI API Endpoint — Programmatic access to AI insights (used by webhooks and scheduled tasks)
WEBHOOK /webhooks app/routes/webhooks.tsx Shopify Webhook Handler — Processes incoming webhooks, verifies HMAC, upserts order/product/customer data

Route Loading Pattern

// Example: app/routes/app.sales.tsx — loader
export const loader = async ({ request }: LoaderFunctionArgs) => {
  const { admin, session } = await authenticate.admin(request);
  const shopId = session.shop;

  const [revenueKpi, ordersKpi, aovKpi, chartData] = await Promise.all([
    getRevenueKpi(shopId),
    getOrdersKpi(shopId),
    getAovKpi(shopId),
    getSalesChart(shopId, "day"),
  ]);

  return json({ revenueKpi, ordersKpi, aovKpi, chartData });
};

Webhook Processing Pattern

// app/routes/webhooks.tsx
export const action = async ({ request }: ActionFunctionArgs) => {
  const { topic, shop, session, admin } = await authenticate.webhook(request);

  if (!admin) throw new Response("Unauthorized", { status: 401 });

  const payload = await request.json();

  switch (topic) {
    case "orders/create":
    case "orders/update":
      await upsertOrder(shop, payload);
      break;
    case "products/create":
    case "products/update":
      await upsertProduct(shop, payload);
      break;
    case "customers/create":
    case "customers/update":
      await upsertCustomer(shop, payload);
      break;
  }

  return json({ received: true });
};

Data Flow Architecture

The application operates on three primary data flows: sync, display, and AI analysis. Each flow is designed for reliability, with local SQLite caching reducing API calls and webhook-driven updates maintaining data freshness.

Primary Sync Flow

Data Ingestion Pipeline
Shopify Admin
GraphQL API
fetchOrders()
fetchProducts()
fetchCustomers()
Prisma ORM
→ SQLite
Analytics Engine
getRevenueKpi / getSalesChart / etc.
React UI
Recharts + Polaris

Webhook-Driven Real-Time Flow

Event-Driven Updates
Shopify
Webhooks
/webhooks Route
HMAC Verification
upsertOrder / upsertProduct / upsertCustomer
→ Prisma → SQLite

AI Analysis Flow

Natural Language Insights
User Question
(Chat Input)
Analytics Context Builder
(Revenue, Orders, Trends)
OpenAI GPT-4 API
(or Rule-Based Fallback)
AiInsight Table
(Stored in SQLite)
Rendered Response
(Markdown → HTML)

Sync Detail: GraphQL Fetching

// Core sync function: fetchOrders via Shopify GraphQL Admin API
async function fetchOrders(admin: AdminClient, shopId: string) {
  const query = `{
    orders(first: 250, sortKey: CREATED_AT, reverse: true) {
      edges {
        node {
          id name email totalPrice subtotalPrice
          totalTax currency financialStatus fulfillmentStatus
          createdAt updatedAt
          lineItems(first: 50) {
            edges { node {
              title quantity price sku vendor
              product { title id }
              variant { title id sku }
            }}
          }
          shippingAddress { address1 city province country zip }
        }
      }
      pageInfo { hasNextPage endCursor }
    }
  }`;

  const response = await admin.graphql(query);
  const { orders } = await response.json();

  for (const edge of orders.edges) {
    await prisma.syncedOrder.upsert({
      where: { shopifyId: edge.node.id },
      update: { /* fields */ },
      create: { shopId, /* fields */ },
    });
  }
}

Analytics Engine

The analytics engine is a collection of Prisma-based query functions that aggregate synced data into business metrics. All functions accept a shopId parameter for multi-tenant data isolation.

KPI Functions

FunctionReturnsDescription
getRevenueKpi(shopId) { total, period, change } Total revenue for current period vs previous period with percentage change
getOrdersKpi(shopId) { count, period, change } Order count for current period vs previous with percentage change
getAovKpi(shopId) { aov, period, change } Average Order Value calculated from total revenue / total orders
getCustomersKpi(shopId) { total, newCount, returningCount } Customer count with new vs returning segmentation
getRepeatRateKpi(shopId) { rate, count } Percentage of customers with 2+ orders

Chart & Report Functions

FunctionParametersDescription
getSalesChart shopId, groupBy: "day"|"week"|"month" Time-series data for Recharts: [{ date, revenue, orders }]
getTopProducts shopId, limit?: number Top products ranked by revenue using SyncedOrderItem aggregation (accurate per-SKU revenue)
getCustomerMetrics shopId Segments (new/returning/VIP), LTV calculation, top customers by spend
getInventoryItems shopId Products with variants, stock status classification: In Stock (>10), Low Stock (1-10), Out of Stock (0)
getFullAnalytics shopId Aggregated dashboard payload: all KPIs + recent orders + top products + summary

Revenue Forecasting Algorithm

The forecasting module uses historical revenue data to project future trends via a weighted moving average:

async function forecastRevenue(shopId: string) {
  // 1. Fetch last 30 days of daily revenue
  const dailyData = await getSalesChart(shopId, "day");

  // 2. Calculate 7-day weighted moving average
  const weights = [0.35, 0.25, 0.20, 0.10, 0.05, 0.03, 0.02];
  const recent = dailyData.slice(-7);
  const wma = recent.reduce((sum, d, i) =>
    sum + d.revenue * (weights[i] || 0.01), 0);

  // 3. Project next 30 days with trend adjustment
  const trend = calculateTrend(dailyData); // slope of linear regression

  return {
    daily: Array.from({ length: 30 }, (_, i) => ({
      day: i + 1,
      projected: wma + trend * (i + 1),
    })),
    totalProjected: wma * 30 + trend * (30 * 31) / 2,
    confidence: calculateConfidence(dailyData),
  };
}

AI Integration

The AI integration provides natural language business insights by combining store analytics context with OpenAI's GPT-4 model. When no API key is configured, the system falls back to rule-based analysis.

OpenAI GPT-4 API Integration

import OpenAI from "openai";

const openai = new OpenAI({
  apiKey: settings.openaiApiKey || process.env.OPENAI_API_KEY,
});

async function generateAiInsight(
  shopId: string,
  question: string
): Promise<AiInsight> {
  // 1. Build context from analytics
  const analytics = await getFullAnalytics(shopId);
  const context = buildContextString(analytics);

  // 2. Check for OpenAI API key
  const settings = await prisma.appSettings.findUnique({
    where: { shopId },
  });

  let response: string;
  let model: string;

  if (settings?.openaiApiKey || process.env.OPENAI_API_KEY) {
    // 3a. Use GPT-4
    const completion = await openai.chat.completions.create({
      model: "gpt-4",
      messages: [
        {
          role: "system",
          content: `You are a business intelligence analyst...`,
        },
        {
          role: "user",
          content: `Context: ${context}\n\nQuestion: ${question}`,
        },
      ],
      max_tokens: 1500,
      temperature: 0.7,
    });
    response = completion.choices[0].message.content || "No insight generated.";
    model = "gpt-4";
  } else {
    // 3b. Rule-based fallback
    response = generateRuleBasedInsight(analytics, question);
    model = "rule-based";
  }

  // 4. Store in database
  return prisma.aiInsight.create({
    data: { shopId, question, response, model, type: "chat" },
  });
}

Context Building

The buildContextString() function aggregates key metrics into a structured prompt context:

function buildContextString(analytics: FullAnalytics): string {
  return `
Store Analytics Summary:
- Total Revenue: $${analytics.revenue.total.toFixed(2)}
- Revenue Change: ${analytics.revenue.change}%
- Total Orders: ${analytics.orders.count}
- Average Order Value: $${analytics.aov.aov.toFixed(2)}
- Total Customers: ${analytics.customers.total}
- Repeat Purchase Rate: ${analytics.repeatRate.rate}%
- Top Products: ${analytics.topProducts.slice(0, 5).map(p =>
    `${p.title} ($${p.revenue.toFixed(2)})`).join(", ")}
- Revenue Trend (last 7 days): ${analytics.chart.slice(-7).map(d =>
    `$${d.revenue.toFixed(0)}`).join(" → ")}
  `;
}

Rule-Based Fallback

When no OpenAI API key is available, the system generates insights using deterministic rules:

ConditionInsight
Revenue > $10,000"Strong revenue performance. You're generating significant sales volume."
Revenue change > 20%"Excellent growth! Revenue increased significantly compared to the previous period."
AOV > $100"High average order value indicates strong per-transaction revenue."
Repeat rate > 30%"Healthy customer retention. Over 30% of customers are repeat buyers."
Top product > 20% of revenue"Revenue concentration: top product accounts for a significant portion of sales."

Conversation History & Daily Brief

Installation Steps

Follow these steps to set up the MTS AI Business Intelligence app in your local development environment.

  1. Clone or Extract the Project
    Obtain the project source code and navigate to the project directory.
    # Clone from repository or extract archive
    cd I:\xampp8212\htdocs\mtsaivusinessintelligence
    dir # verify project files present
  2. Install Dependencies
    Install all npm packages defined in package.json.
    npm install
  3. Create Environment File
    Copy the example environment file and customize it.
    # Windows
    copy .env.example .env
    
    # macOS / Linux
    cp .env.example .env
  4. Configure Environment Variables
    Edit .env with your actual credentials and configuration values.
    # Edit .env with your values
    SHOPIFY_API_KEY=abc123def456
    SHOPIFY_API_SECRET=shpss_abcdef123456
    SCOPES=read_orders,read_products,read_customers,read_inventory,read_analytics,read_content
    SHOPIFY_APP_URL=https://your-app.ngrok.io
    DATABASE_URL="file:./dev.db"
    OPENAI_API_KEY=sk-your-key-here
    HOST=0.0.0.0
    PORT=5173
  5. Update shopify.app.toml
    Configure the Shopify app manifest with your app credentials and webhook URIs.
    # Edit shopify.app.toml
    client_id = "your_client_id"
    application_url = "https://your-app.ngrok.io"
    
    # Update webhook URIs to match your development URL
    [[webhook_subscriptions]]
    topic = "orders/create"
    uri = "https://your-app.ngrok.io/webhooks"
    # ... repeat for all webhook topics
  6. Initialize Database
    Push the Prisma schema to SQLite and generate the Prisma client.
    npx prisma db push
    npx prisma generate
  7. Start Development Server
    Launch the Vite dev server with SSR enabled.
    npm run dev
  8. Install on Shopify Store
    Navigate to your Partner Dashboard → App → Install on development store. Authorize the app with the requested scopes. The app will appear in the Shopify admin sidebar.
Development Tip

Use ngrok or shopify app dev to create a publicly accessible tunnel for your local development server. Shopify requires HTTPS for embedded apps and webhooks.

# Option A: Using ngrok
ngrok http 5173

# Option B: Using Shopify CLI
npx shopify app dev

File Structure

Complete project directory layout showing all application files and their organizational structure.

mts-ai-business-intelligence/ ├── shopify.app.toml ← Shopify app manifest ├── package.json ├── tsconfig.json ← TypeScript configuration ├── vite.config.ts ← Vite build configuration ├── react-router.config.ts ← SSR configuration ├── .env.example ← Environment template ├── .env ← Local environment (git-ignored) │ ├── prisma/ │ ├── schema.prisma ← Database schema (11 models) │ └── dev.db ← SQLite database file │ ├── app/ │ ├── root.tsx ← Root layout, Polaris provider │ ├── shopify.server.ts ← Shopify auth + Prisma client │ ├── db.server.ts ← Prisma client singleton │ │ │ ├── routes/ │ │ ├── app.tsx ← App shell (sidebar + outlet) │ │ ├── app._index.tsx ← Dashboard page │ │ ├── app.sales.tsx ← Sales analytics page │ │ ├── app.products.tsx ← Product performance page │ │ ├── app.customers.tsx ← Customer analytics page │ │ ├── app.inventory.tsx ← Inventory health page │ │ ├── app.insights._index.tsx ← AI insights (GET + POST) │ │ ├── app.settings.tsx ← Settings (GET + POST) │ │ ├── api.sync.tsx ← Data sync endpoint │ │ ├── api.ai.tsx ← AI API endpoint │ │ ├── webhooks.tsx ← Webhook handler │ │ └── auth.login.tsx ← Login route │ │ │ ├── components/ │ │ ├── KpiCard.tsx ← KPI metric card │ │ ├── SalesChart.tsx ← Recharts line/bar chart │ │ ├── ProductTable.tsx ← Product data table │ │ ├── CustomerTable.tsx ← Customer data table │ │ ├── InventoryGrid.tsx ← Inventory status grid │ │ ├── AiChat.tsx ← AI chat interface │ │ └── SettingsForm.tsx ← Settings form │ │ │ ├── lib/ │ │ ├── analytics.server.ts ← All analytics functions │ │ ├── sync.server.ts ← Shopify data fetching │ │ ├── ai.server.ts ← AI integration (GPT-4 + fallback) │ │ ├── webhooks.server.ts ← Webhook data upserts │ │ ├── forecast.server.ts ← Revenue forecasting │ │ └── utils.ts ← Helper utilities │ │ │ └── styles/ │ └── app.css ← Application styles │ └── public/ ├── favicon.ico └── Magetechsol-Blue-logo.png

Deployment

The application supports deployment to Shopify's managed infrastructure or custom hosting platforms. This section covers production build, environment configuration, and deployment options.

Production Build

# 1. Build the application for production
npm run build

# 2. The build output is in the build/ directory
# 3. Start the production server
npm run start

Production Environment Variables

# Production .env — ensure all values are set
SHOPIFY_API_KEY=production_api_key
SHOPIFY_API_SECRET=production_api_secret
SCOPES=read_orders,read_products,read_customers,read_inventory,read_analytics,read_content
SHOPIFY_APP_URL=https://your-production-domain.com
DATABASE_URL="file:./production.db"
OPENAI_API_KEY=sk-production-key
HOST=0.0.0.0
PORT=3000
NODE_ENV=production

Deployment Options

PlatformMethodNotes
Shopify Managed npx shopify app deploy Deploys to Shopify's infrastructure. SQLite replaced with managed storage. Recommended for production.
Custom Server npm run build && npm run start Self-hosted deployment on any Node.js-compatible server. Requires HTTPS.
Docker Dockerfile + docker-compose Containerized deployment. Mount volume for SQLite persistence.
Cloud Platforms Render, Railway, Fly.io Deploy via Git. Configure environment variables in platform dashboard.

Post-Deployment Checklist

  • Verify shopify.app.toml points to production URL
  • Run npx prisma db push to initialize production database
  • Update webhook URIs to production endpoint
  • Confirm all required access scopes are granted
  • Test webhook delivery via Partner Dashboard → App → Webhooks
  • Verify SSL/TLS certificate is valid for all endpoints
  • Run manual sync via Settings page to populate initial data
  • Configure OpenAI API key in Settings for AI insights

Pricing & Plans

MTS AI Business Intelligence offers a tiered pricing model with a free plan to get started and a Pro plan for advanced features. Below is the detailed plan comparison and feature breakdown.

Plan Overview

Free Plan
$0 / month
No credit card required • Get started instantly
Pro Plan
$29 / month
Cancel anytime • Full access to all features

Free Plan

Free Plan — $0/month

Includes:

  • Dashboard Overview
  • Basic Sales Analytics
  • Settings & Data Sync

Pro Plan

Pro Plan — $29/month

Everything in Free, plus:

  • Advanced Product Analytics
  • Customer Segmentation
  • Inventory Health Monitoring
  • AI-Powered Business Insights
  • Revenue Forecasting
  • Data Export

Plan Comparison

FeatureFree PlanPro Plan
Dashboard Overview
Basic Sales Analytics
Settings & Data Sync
Advanced Product Analytics
Customer Segmentation
Inventory Health Monitoring
AI-Powered Business Insights
Revenue Forecasting
Data Export
Monthly Price Free $29/month

MTS AI Business Intelligence — Technical Documentation v1.0.0

Built by MageTech Solutions · Shopify GraphQL Admin API 2024-10