Documentation Index Fetch the complete documentation index at: https://mintlify.com/Mercaline2024/Ecomdrop-ia-connector-2/llms.txt
Use this file to discover all available pages before exploring further.
Architecture
Ecomdrop IA Connector is built with modern, production-ready technologies designed for scalability, maintainability, and performance. This page provides a comprehensive overview of the system architecture.
System Overview
Tech Stack
Frontend
React Router v7 Modern routing with server-side rendering, data loading, and file-based routing
TypeScript Type-safe development with full IDE support and compile-time error checking
Tailwind CSS Utility-first CSS framework for rapid UI development
shadcn/ui High-quality React components built on Radix UI primitives
Additional Frontend Libraries:
{
"@shopify/app-bridge-react" : "^4.2.4" ,
"lucide-react" : "^0.552.0" ,
"react-phone-number-input" : "^3.4.13" ,
"class-variance-authority" : "^0.7.1" ,
"tailwind-merge" : "^3.3.1" ,
"tailwindcss-animate" : "^1.0.7"
}
Backend
Node.js 20+ Modern JavaScript runtime with ESM support
React Router Server Server-side rendering and API routes with type-safe data loading
Prisma ORM Type-safe database client with migrations and schema management
MySQL 8.0 Production-grade relational database with ACID compliance
Backend Dependencies:
{
"@shopify/shopify-app-react-router" : "^1.0.0" ,
"@shopify/shopify-app-session-storage-prisma" : "^7.0.0" ,
"@prisma/client" : "^6.16.3" ,
"mysql2" : "^3.15.3"
}
Docker Containerization for consistent deployment across environments
Docker Compose Multi-container orchestration for local development and production
Traefik Reverse proxy and load balancer with automatic SSL
Portainer Container management UI for monitoring and administration
Project Structure
ecomdrop-ia-connector/
βββ app/
β βββ components/ # React components
β β βββ ui/ # shadcn/ui components
β β β βββ button.tsx
β β β βββ card.tsx
β β β βββ dialog.tsx
β β β βββ input.tsx
β β β βββ ...
β β βββ modals/ # Custom modal components
β β βββ LoadingModal.tsx
β β βββ SuccessModal.tsx
β βββ lib/ # Utility functions and API clients
β β βββ utils.ts
β β βββ ecomdrop.api.server.ts
β β βββ shopify.order.server.ts
β βββ routes/ # React Router routes
β β βββ app._index.tsx # Products page
β β βββ app.configuration.tsx # Configuration page
β β βββ app.configuration.ai.tsx # AI config page
β β βββ app.orders.tsx # Orders page
β β βββ app.theme.tsx # Theme management
β β βββ api.*.tsx # API endpoints
β β βββ webhooks.*.tsx # Webhook handlers
β βββ shopify.server.ts # Shopify authentication
β βββ db.server.ts # Database connection
β βββ globals.d.ts # TypeScript declarations
βββ prisma/
β βββ schema.prisma # Database schema (MySQL)
β βββ migrations/ # Database migrations
βββ public/ # Static assets
βββ Dockerfile # Production Docker image
βββ docker-compose.yml # Docker Compose configuration
βββ package.json # Dependencies and scripts
βββ tsconfig.json # TypeScript configuration
βββ tailwind.config.js # Tailwind CSS configuration
βββ vite.config.ts # Vite bundler configuration
Database Schema
The application uses Prisma ORM with MySQL 8.0 for data persistence.
Schema Overview
// Shopify app sessions and authentication
model Session {
id String @id
shop String @db.VarChar ( 255 )
state String @db.VarChar ( 255 )
isOnline Boolean @default ( false )
scope String ? @db.Text
expires DateTime ?
accessToken String @db.Text
userId BigInt ?
// ... additional fields
}
// Store-specific integration settings
model ShopConfiguration {
id String @id @default ( uuid ())
shop String @unique @db.VarChar ( 255 )
ecomdropApiKey String ? @db.Text
nuevoPedidoFlowId String ? @db.VarChar ( 255 )
carritoAbandonadoFlowId String ? @db.VarChar ( 255 )
dropiStoreName String ? @db.VarChar ( 255 )
dropiCountry String ? @db.VarChar ( 10 )
dropiToken String ? @db.Text
createdAt DateTime @default ( now ())
updatedAt DateTime @updatedAt
}
// Product mappings between platforms
model ProductAssociation {
id String @id @default ( uuid ())
shop String @db.VarChar ( 255 )
dropiProductId String @db.VarChar ( 255 )
shopifyProductId String @db.VarChar ( 255 )
dropiProductName String ? @db.VarChar ( 500 )
shopifyProductTitle String ? @db.VarChar ( 500 )
importType String @db.VarChar ( 50 )
dropiVariations String ? @db.Text
saveDropiName Boolean @default ( true )
saveDropiDescription Boolean @default ( true )
customPrice String ? @db.VarChar ( 50 )
useSuggestedBarcode Boolean @default ( false )
saveDropiImages Boolean @default ( true )
createdAt DateTime @default ( now ())
updatedAt DateTime @updatedAt
}
// AI assistant configuration per store
model AIConfiguration {
id String @id @default ( uuid ())
shop String @unique @db.VarChar ( 255 )
agentName String ? @db.VarChar ( 255 )
companyName String ? @db.VarChar ( 255 )
companyDescription String ? @db.Text
paymentMethods String ? @db.Text // JSON
companyPolicies String ? @db.Text
faq String ? @db.Text // JSON
postSaleFaq String ? @db.Text // JSON
rules String ? @db.Text // JSON
notifications String ? @db.Text // JSON
createdAt DateTime @default ( now ())
updatedAt DateTime @updatedAt
}
All configurations are isolated per Shopify store using the shop field, ensuring multi-tenant security.
Database Features
Indexes on frequently queried fields (shop, dropiProductId, shopifyProductId)
Unique constraints to prevent duplicate associations
Timestamps for tracking creation and updates
Text fields for storing JSON data (payment methods, FAQs, rules, notifications)
UUID primary keys for distributed systems compatibility
Authentication Flow
Shopify OAuth
// shopify.server.ts
import { shopifyApp } from "@shopify/shopify-app-react-router/server" ;
import { PrismaSessionStorage } from "@shopify/shopify-app-session-storage-prisma" ;
const shopify = shopifyApp ({
apiKey: process . env . SHOPIFY_API_KEY ,
apiSecretKey: process . env . SHOPIFY_API_SECRET ,
apiVersion: ApiVersion . October25 ,
scopes: process . env . SCOPES ?. split ( "," ),
appUrl: process . env . SHOPIFY_APP_URL ,
authPathPrefix: "/auth" ,
sessionStorage: new PrismaSessionStorage ( prisma ),
distribution: AppDistribution . AppStore ,
});
Authentication Steps
OAuth Initiation
User installs app from Shopify App Store or clicks βAdd appβ in admin
Permission Request
Shopify displays requested scopes: read_products, write_products, read_orders, read_themes, write_themes
Token Exchange
After approval, Shopify sends authorization code, app exchanges it for access token
Session Storage
Access token and session data stored in MySQL via Prisma
App Bridge Connection
Embedded app connects to Shopify Admin using App Bridge
Protected Routes
All routes are protected with authentication middleware:
export async function loader ({ request } : LoaderFunctionArgs ) {
const { session , admin } = await authenticate . admin ( request );
// Route logic here
}
API Integration Architecture
Ecomdrop API Client
// app/lib/ecomdrop.api.server.ts
const ECOMDROP_API_BASE = "https://panel.ecomdrop.app/api" ;
export async function getEcomdropFlows ( apiKey : string ) {
const response = await fetch ( ` ${ ECOMDROP_API_BASE } /accounts/flows` , {
method: "GET" ,
headers: {
"accept" : "application/json" ,
"X-ACCESS-TOKEN" : apiKey ,
},
});
return response . json ();
}
export async function triggerEcomdropFlow (
apiKey : string ,
flowId : string ,
payload : any
) {
const response = await fetch (
` ${ ECOMDROP_API_BASE } /flows/ ${ flowId } /trigger` ,
{
method: "POST" ,
headers: {
"accept" : "application/json" ,
"X-ACCESS-TOKEN" : apiKey ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ( payload ),
}
);
return response . json ();
}
Dropi API Integration
Dropi integration uses Ecomdropβs bot field API:
const DROPI_COUNTRY_FIELD_MAP : Record < string , string > = {
'CO' : '640597' , // Colombia
'EC' : '805359' , // Ecuador
'CL' : '665134' , // Chile
'GT' : '747995' , // Guatemala
'MX' : '641097' , // MΓ©xico
'PA' : '742965' , // PanamΓ‘
'PE' : '142979' , // PerΓΊ
'PY' : '240677' , // Paraguay
};
export async function validateAndSaveDropiIntegration (
apiKey : string ,
country : string ,
dropiToken : string
) {
const fieldId = DROPI_COUNTRY_FIELD_MAP [ country ];
const response = await fetch (
` ${ ECOMDROP_API_BASE } /accounts/bot_fields/ ${ fieldId } ` ,
{
method: "POST" ,
headers: {
"accept" : "application/json" ,
"X-ACCESS-TOKEN" : apiKey ,
"Content-Type" : "application/x-www-form-urlencoded" ,
},
body: new URLSearchParams ({ value: dropiToken }),
}
);
return response . json ();
}
Caching Strategy
Implements in-memory caching to prevent API rate limiting:
const flowsCache = new Map < string , { data : any ; timestamp : number }>();
const CACHE_DURATION = 60000 ; // 1 minute
export async function getEcomdropFlows ( apiKey : string ) {
// Check cache first
const cached = flowsCache . get ( apiKey );
if ( cached && Date . now () - cached . timestamp < CACHE_DURATION ) {
return { success: true , data: cached . data };
}
// Fetch from API and cache result
const data = await fetchFromAPI ();
flowsCache . set ( apiKey , { data , timestamp: Date . now () });
return { success: true , data };
}
Webhook Processing
Registered Webhooks
// Webhooks are registered automatically by Shopify App package
const webhooks = [
"orders/create" ,
"draft_orders/create" ,
"app/uninstalled" ,
"app/scopes_update"
];
Webhook Handler Example
// app/routes/webhooks.orders.create.tsx
export async function action ({ request } : ActionFunctionArgs ) {
const { topic , shop , session } = await authenticate . webhook ( request );
// Parse webhook payload
const payload = await request . json ();
// Get store configuration
const config = await db . shopConfiguration . findUnique ({
where: { shop }
});
// Trigger Ecomdrop flow if configured
if ( config ?. nuevoPedidoFlowId && config ?. ecomdropApiKey ) {
await triggerEcomdropFlow (
config . ecomdropApiKey ,
config . nuevoPedidoFlowId ,
payload
);
}
return json ({ success: true });
}
All webhooks are verified using HMAC signatures to ensure they come from Shopify.
Docker Deployment
Dockerfile
FROM node:20-alpine
RUN apk add --no-cache openssl netcat-openbsd
EXPOSE 3000
WORKDIR /app
ENV NODE_ENV=production
# Install dependencies
COPY package.json package-lock.json* ./
RUN npm ci --omit=dev && npm cache clean --force
# Copy application files
COPY . .
# Build application
RUN npm run build
# Create entrypoint script that waits for MySQL
RUN echo '#!/bin/sh' > /app/docker-entrypoint.sh && \
echo 'until nc -z mysql 3306; do' >> /app/docker-entrypoint.sh && \
echo ' echo "Waiting for MySQL..."' >> /app/docker-entrypoint.sh && \
echo ' sleep 2' >> /app/docker-entrypoint.sh && \
echo 'done' >> /app/docker-entrypoint.sh && \
echo 'exec npm run docker-start' >> /app/docker-entrypoint.sh && \
chmod +x /app/docker-entrypoint.sh
CMD [ "/app/docker-entrypoint.sh" ]
Docker Compose Configuration
version : "3.8"
services :
mysql :
image : mysql:8.0
environment :
MYSQL_ROOT_PASSWORD : ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE : shopify_app
MYSQL_USER : shopify_user
MYSQL_PASSWORD : ${MYSQL_PASSWORD}
volumes :
- mysql_data:/var/lib/mysql
networks :
- EcomdropNet
shopify_app :
image : shopify-app_shopify_app:latest
environment :
DATABASE_URL : mysql://shopify_user:${MYSQL_PASSWORD}@mysql:3306/shopify_app
SHOPIFY_API_KEY : ${SHOPIFY_API_KEY}
SHOPIFY_API_SECRET : ${SHOPIFY_API_SECRET}
SHOPIFY_APP_URL : https://connector.ecomdrop.io
NODE_ENV : production
networks :
- EcomdropNet
depends_on :
- mysql
deploy :
labels :
- traefik.enable=true
- traefik.http.routers.shopify_app.rule=Host(`connector.ecomdrop.io`)
- traefik.http.routers.shopify_app.tls.certresolver=letsencryptresolver
networks :
EcomdropNet :
external : true
volumes :
mysql_data :
Production Deployment Features
Health Checks MySQL health checks ensure database is ready before app starts
Automatic Restart Failed containers automatically restart with exponential backoff
SSL/TLS Automatic SSL certificate provisioning via Letβs Encrypt
Load Balancing Traefik handles load balancing and request routing
Environment Variables
Required Variables
# Database
DATABASE_URL = "mysql://user:password@host:3306/shopify_app"
MYSQL_ROOT_PASSWORD = "secure_root_password"
MYSQL_PASSWORD = "secure_user_password"
# Shopify API
SHOPIFY_API_KEY = "your_api_key"
SHOPIFY_API_SECRET = "your_api_secret"
SHOPIFY_APP_URL = "https://your-app-url.com"
SCOPES = "read_products,write_products,read_orders,read_themes,write_themes"
Optional Variables
# Theme Configuration
THEME_2_5_GIT_REPO = "your-org/theme-repo"
THEME_2_5_GIT_BRANCH = "main"
THEME_2_5_GIT_PROVIDER = "github"
THEME_2_5_GIT_TOKEN = "your_github_token"
# Custom Domain
SHOP_CUSTOM_DOMAIN = "your-custom-domain.com"
Server-Side Rendering
React Router v7 provides automatic server-side rendering:
// Data loaded on server before page render
export async function loader ({ request } : LoaderFunctionArgs ) {
const { session , admin } = await authenticate . admin ( request );
const [ configuration , associations ] = await Promise . all ([
db . shopConfiguration . findUnique ({ where: { shop: session . shop } }),
db . productAssociation . findMany ({ where: { shop: session . shop } })
]);
return { configuration , associations };
}
Database Optimizations
Connection pooling via Prisma
Indexed queries on frequently accessed fields
Batch operations for bulk updates
Query optimization with Prismaβs query analyzer
Frontend Optimizations
Code splitting with React Router
Lazy loading of heavy components
Image optimization with CDN (Dropi images)
Debounced search to reduce API calls
Security Measures
API keys and tokens stored as encrypted text in database
HTTPS/TLS encryption for all API communications
Secure session storage with encrypted cookies
Authentication & Authorization
OAuth 2.0 for Shopify authentication
HMAC verification for webhook requests
Session-based authorization for API routes
Scoped access tokens with minimal permissions
All data isolated per Shopify store
Unique indexes prevent cross-store data access
Session verification on every request
Monitoring & Logging
The application includes comprehensive logging:
// Structured logging for API calls
console . log ( "π Fetching flows from Ecomdrop API..." );
console . log ( "π‘ API URL:" , ` ${ ECOMDROP_API_BASE } /accounts/flows` );
console . log ( "π Response status:" , response . status );
console . log ( "β
Flows received:" , data );
Log Categories
π API requests
π¦ Data operations
β
Success messages
β Error messages
β οΈ Warnings
π Status updates
Scalability Considerations
Horizontal Scaling
The app supports horizontal scaling:
Stateless design : No server-side state outside database
Session storage in MySQL : Shared across all app instances
Load balancing : Traefik distributes requests across replicas
Database Scaling
# MySQL configuration for production
command :
- --innodb_buffer_pool_size=768M
- --max_connections=200
- --max_allowed_packet=256M
Caching Strategy
Multi-layer caching:
In-memory cache for API responses (1 minute)
Database query cache via Prisma
Browser cache for static assets
Development Workflow
Local Development
Uses Shopify CLI for local development with tunnel
Database Migrations
npx prisma migrate dev --name add_new_field
npx prisma generate
Creates and applies database schema changes
Type Checking
Ensures TypeScript type safety across the codebase
Build
Compiles application for production
Docker Build
docker build -t ecomdrop-ia-connector:latest .
Creates production Docker image
Deploy
Deploys to production with Docker Compose
Migration Path
The application has migrated from SQLite to MySQL:
If upgrading from SQLite, run migrations carefully: # Backup SQLite data first
npx prisma migrate deploy
Migration Benefits
Better performance under high load
ACID compliance for data integrity
Concurrent access support
Production-ready reliability
API Reference
For detailed API documentation, see the Features page.
View Features Explore all features
Quick Start Get started quickly
API Reference API documentation