Centralised Fulfilment and Shipping Label Generation for Shopify
3m 24s
ShipStation: A Centralised Shopify Fulfilment Application for Multiple Shopify Stores
View code on GitHub Visit Live ProjectTo view the live example application, please use the following credentials: [[email protected]], [password]
Building a Centralised Shopify Fulfilment Application
This blog post explores the process of building a web application designed to streamline the shipment processes of a local furniture manufacturing business. This business operates multiple Shopify stores and supplies products to drop-shipping clients. The ShipStation application consolidates operations by providing a centralised platform for order fulfilment , as well as generating and printing shipping labels.
The Problem:
The business faced challenges in managing orders across multiple Shopify stores, leading to the inefficient manual creation of shipping labels. The manual process of accessing each store individually to manage orders and create labels was very time-consuming. A centralised system was needed to aggregate orders and streamline the label generation process. This solution recovered ~72 hours of manual work every month, which allowed the factory manager to focus on more useful business activities.
Project Overview
The solution involved building a web application using Next.js, MongoDB, and Firebase, with key functionalities including user authentication, order management, and PDF label generation. The project used the pdfme library for creating PDF labels and implemented next.js API routes for handling various operations.
Authentication with Firebase
To secure the application, Firebase was used for handling user authentication. This integration allowed for easy management of user sessions and provided a seamless login experience with options for email/password authentication and third-party providers like Google.
import { auth } from '@/lib/firebase';
import { signInWithEmailAndPassword, createUserWithEmailAndPassword } from 'firebase/auth';
// User registration example
const handleSignUp = async (email, password) => {
try {
await createUserWithEmailAndPassword(auth, email, password);
console.log('User registered successfully!');
} catch (error) {
console.error('Registration failed:', error.message);
}
};
// User login example
const handleLogin = async (email, password) => {
try {
await signInWithEmailAndPassword(auth, email, password);
console.log('Logged in successfully!');
} catch (error) {
console.error('Login failed:', error.message);
}
}
Data Management with MongoDB
MongoDB was chosen for its schema flexibility and scalability, allowing me to efficiently manage data related to clients, orders, and notifications. The data model was designed to capture essential details such as client information and order specifics, facilitating easy access and manipulation.
Client Management
The client management module allowed users to add, update, and delete clients. This was critical for managing the different Shopify stores and their respective order data.
import mongoose from 'mongoose';
import dbConnect from '@/lib/mongodb';
dbConnect();
const clientSchema = new mongoose.Schema({
uid: { type: String, required: true },
clientId: { type: String, required: true },
businessName: { type: String, required: true },
url: { type: String, required: true },
});
const Client = mongoose.models.Client || mongoose.model('Client', clientSchema);
export async function POST(request) {
try {
const body = await request.json();
const newClient = new Client(body);
const savedClient = await newClient.save();
return new Response(JSON.stringify(savedClient), { status: 201 });
} catch (error) {
return new Response(JSON.stringify({ error: 'Internal Server Error' }), { status: 500 });
}
}
API Routes and Webhooks
The application features several API routes that handle different aspects of the business logic. The /api/orderhook
route is particularly crucial as it listens for Shopify webhook notifications, ensuring that new orders are automatically captured and processed.
Order Webhook Handling
The /api/orderhook
route processes incoming order data from Shopify. This route extracts necessary information, such as the store name and order details, and saves it into the MongoDB database.
import { Order } from '@/lib/mongoose/order-schema';
import dbConnect from '@/lib/mongodb';
export async function POST(request) {
await dbConnect();
try {
const data = await request.json();
const storeName = new URL(data.order_status_url).hostname.split('.')[0];
const newOrder = new Order({ ...data, storeName });
await newOrder.save();
return new Response(JSON.stringify({ message: 'Order saved successfully' }), { status: 200 });
} catch (error) {
return new Response(JSON.stringify({ error: 'Failed to process webhook' }), { status: 500 });
}
}
PDF Label Generation with pdfme
Generating shipping labels is a core feature of the application. The pdfme library was utilised to dynamically create PDFs that could be printed and used as shipping labels. This feature was designed to support various label formats for different shipping needs.
import { PDFDocument } from 'pdf-lib';
const generatePDFLabel = async (orderData) => {
const pdfDoc = await PDFDocument.create();
const page = pdfDoc.addPage([500, 700]);
// Add text and other elements to the PDF
page.drawText('Order ID: $ {orderData.orderId}', { x: 50, y: 650 });
page.drawText('Customer: $ {orderData.customerName}', { x: 50, y: 600 });
const pdfBytes = await pdfDoc.save();
return pdfBytes;
};
Conclusion
This project provided a practical solution for a real-world business problem but also served as a valuable learning experience in full-stack development. I used a range of modern technologies, from frontend development with React and Next.js to backend services using Node.js and MongoDB, along with the integration of third-party libraries and services.