Documentation Index
Fetch the complete documentation index at: https://mintlify.com/openshiporg/openfront/llms.txt
Use this file to discover all available pages before exploring further.
Openfront provides comprehensive inventory management capabilities, allowing you to track stock levels, manage multiple warehouse locations, and monitor inventory movements throughout your supply chain.
Inventory Architecture
Inventory management in Openfront is built around three core concepts:
- Product Variants - Individual SKUs with inventory tracking
- Locations - Warehouse and fulfillment center management
- Stock Movements - Audit trail of inventory changes
Product Variant Inventory
Each product variant maintains its own inventory settings:
ProductVariant {
title: string
sku: string // Unique identifier
barcode: string // Barcode/UPC/EAN
ean: string // European Article Number
upc: string // Universal Product Code
inventoryQuantity: integer // Current stock level
allowBackorder: boolean // Allow orders when out of stock
manageInventory: boolean // Enable inventory tracking
// Relationships
product: → Product
location: → Location
stockMovements: [→ StockMovement]
lineItems: [→ OrderLineItem]
}
Enabling Inventory Tracking
Configure inventory settings for a variant:
mutation UpdateVariantInventory {
updateProductVariant(
where: { id: "variant_id" }
data: {
sku: "SHIRT-BLK-M"
barcode: "1234567890123"
manageInventory: true
allowBackorder: false
inventoryQuantity: 100
location: { connect: { id: "location_warehouse1" } }
}
) {
id
sku
inventoryQuantity
manageInventory
location {
name
}
}
}
Checking Stock Availability
Query current stock levels:
query CheckStock {
productVariant(where: { sku: "SHIRT-BLK-M" }) {
id
title
sku
inventoryQuantity
allowBackorder
manageInventory
location {
name
address
}
}
}
Location Management
Locations represent physical warehouses or fulfillment centers:
Location {
name: string
description: string
address: string
variants: [→ ProductVariant]
}
Creating Locations
Set up warehouse locations:
mutation CreateLocation {
createLocation(data: {
name: "Main Warehouse"
description: "Primary fulfillment center"
address: "123 Warehouse Blvd, City, ST 12345"
}) {
id
name
address
}
}
Assigning Products to Locations
mutation AssignToLocation {
updateProductVariant(
where: { id: "variant_id" }
data: {
location: { connect: { id: "location_id" } }
}
) {
id
sku
location {
name
}
}
}
Multi-Location Inventory
View inventory across all locations:
query LocationInventory {
locations {
id
name
variants {
id
sku
title
inventoryQuantity
product {
title
}
}
}
}
Stock Movements
All inventory changes are tracked as stock movements:
StockMovement {
type: "adjustment" | "sale" | "return" | "restock" | "transfer"
quantity: integer // Positive for increases, negative for decreases
reason: string // Why the movement occurred
note: string // Additional details
variant: → ProductVariant
}
Movement Types
- adjustment - Manual inventory adjustments
- sale - Inventory sold to customers
- return - Customer returns
- restock - Receiving new inventory
- transfer - Moving between locations
Recording Stock Movements
Manual inventory adjustments:
mutation AdjustInventory {
createStockMovement(data: {
variant: { connect: { id: "variant_id" } }
type: "adjustment"
quantity: -5
reason: "Damaged goods"
note: "Water damage from warehouse leak"
}) {
id
type
quantity
reason
variant {
sku
inventoryQuantity
}
}
}
Viewing Movement History
query InventoryHistory {
stockMovements(
where: { variant: { id: { equals: "variant_id" } } }
orderBy: [{ createdAt: desc }]
take: 50
) {
id
type
quantity
reason
note
createdAt
variant {
sku
}
}
}
Automatic Inventory Updates
Openfront automatically tracks inventory changes:
Order Fulfillment
When an order is fulfilled, inventory is decremented:
// Automatically creates stock movement
{
type: "sale",
quantity: -2, // Sold 2 units
reason: "Order fulfillment",
note: "Order #1234"
}
Customer Returns
Returned items increase inventory:
// Automatically creates stock movement
{
type: "return",
quantity: 1, // Returned 1 unit
reason: "Customer return",
note: "Return ID: ret_123"
}
Claim Processing
Replacement items affect inventory:
// Creates stock movement for replacement
{
type: "adjustment",
quantity: -1,
reason: "Claim replacement",
note: "Claim #claim_456"
}
Backorder Management
Handle out-of-stock scenarios:
Allowing Backorders
Enable customers to order out-of-stock items:
mutation EnableBackorders {
updateProductVariant(
where: { id: "variant_id" }
data: {
allowBackorder: true
inventoryQuantity: 0
}
) {
id
allowBackorder
inventoryQuantity
}
}
Stock Validation
Validate stock before checkout:
function validateStock(cart: Cart) {
for (const item of cart.lineItems) {
const variant = item.variant;
if (!variant.manageInventory) {
continue; // Skip items without inventory tracking
}
if (item.quantity > variant.inventoryQuantity) {
if (!variant.allowBackorder) {
throw new Error(
`Insufficient stock for ${variant.sku}. ` +
`Available: ${variant.inventoryQuantity}, ` +
`Requested: ${item.quantity}`
);
}
}
}
}
Low Stock Alerts
Monitor inventory levels:
query LowStockProducts {
productVariants(
where: {
AND: [
{ manageInventory: { equals: true } }
{ inventoryQuantity: { lte: 10 } }
{ allowBackorder: { equals: false } }
]
}
) {
id
sku
title
inventoryQuantity
product {
title
}
location {
name
}
}
}
Inventory Reports
Current Stock Report
query StockReport {
productVariants(
where: { manageInventory: { equals: true } }
) {
sku
title
inventoryQuantity
location { name }
product {
title
status
}
}
}
Stock Movement Report
query MovementReport($startDate: DateTime!, $endDate: DateTime!) {
stockMovements(
where: {
AND: [
{ createdAt: { gte: $startDate } }
{ createdAt: { lte: $endDate } }
]
}
orderBy: [{ createdAt: desc }]
) {
type
quantity
reason
createdAt
variant {
sku
product { title }
}
}
}
Inventory Value
Calculate total inventory value:
interface InventoryValue {
sku: string;
quantity: number;
unitCost: number;
totalValue: number;
}
function calculateInventoryValue(
variants: ProductVariant[]
): InventoryValue[] {
return variants
.filter(v => v.manageInventory)
.map(variant => {
const price = variant.prices[0]?.amount || 0;
return {
sku: variant.sku,
quantity: variant.inventoryQuantity,
unitCost: price / 100,
totalValue: (price / 100) * variant.inventoryQuantity,
};
});
}
Best Practices
SKU Management
- Use consistent SKU naming conventions
- Include product attributes in SKUs (e.g.,
SHIRT-BLK-M)
- Make SKUs human-readable
- Never reuse SKUs
Inventory Tracking
- Enable inventory management for all physical products
- Disable for digital products and services
- Set realistic safety stock levels
- Regular cycle counts to verify accuracy
Stock Movements
- Always provide descriptive reasons
- Add detailed notes for auditing
- Review movement history regularly
- Investigate unexpected movements
Multi-Location
- Assign default locations to new products
- Plan fulfillment based on location proximity
- Monitor stock distribution across locations
- Transfer inventory to optimize fulfillment
Backorders
- Only enable for products with reliable restock
- Communicate expected availability dates
- Fulfill backorders in chronological order
- Consider partial fulfillment options
Integration Examples
Inventory Sync Script
Sync inventory from external system:
import { keystoneClient } from './lib/keystone';
async function syncInventory(sku: string, quantity: number) {
const mutation = `
mutation UpdateInventory($sku: String!, $quantity: Int!) {
updateProductVariant(
where: { sku: $sku }
data: { inventoryQuantity: $quantity }
) {
id
sku
inventoryQuantity
}
}
`;
const result = await keystoneClient(mutation, {
sku,
quantity,
});
console.log(`Updated ${sku}: ${quantity} units`);
}
// Sync inventory from CSV or API
await syncInventory('SHIRT-BLK-M', 150);
await syncInventory('PANTS-BLUE-L', 75);
Low Stock Notification
async function checkLowStock() {
const query = `
query LowStock {
productVariants(
where: {
inventoryQuantity: { lte: 10 }
manageInventory: { equals: true }
}
) {
sku
title
inventoryQuantity
}
}
`;
const result = await keystoneClient(query);
const lowStock = result.data.productVariants;
if (lowStock.length > 0) {
// Send notification email
await sendEmail({
to: 'inventory@store.com',
subject: 'Low Stock Alert',
body: `${lowStock.length} products are low on stock`,
data: lowStock,
});
}
}