How We Built PrintFlow ERP: Real-Time Firebase Sync Across 8 User Roles
PrintFlow came to us with a familiar problem: their entire inventory, procurement, and production workflow was managed through a shared Excel spreadsheet. Multiple people editing the same file. No version control. No real-time visibility. No audit trail.
We built them a custom ERP in 4 months. Here is how.
Why Electron + Firebase?
The client had multiple workstations across different departments — procurement, production, delivery. They needed real-time sync: if the production manager marks a job card complete, the logistics team should see it instantly on their machine.
Firebase Firestore was perfect for this. Electron wrapped the whole thing into a cross-platform desktop app that works on Windows and Mac without any browser.
The Role System
Eight distinct user roles, each with a completely different view of the system:
- Admin (full access)
- Procurement Manager
- Production Supervisor
- Delivery Manager
- Accountant
- Warehouse Staff
- Sales Representative
- Viewer (read-only)
We implemented role-based routing at the app level. When a user logs in, Firestore returns their role, and the app loads only the modules they are permitted to access. Attempting to navigate to a restricted route redirects instantly — no server round-trip needed.
Real-Time Sync with onSnapshot
Every critical data view uses Firestore's `onSnapshot` listener instead of one-time `get()` calls:
const unsubscribe = db.collection('jobCards')
.where('status', '==', 'in-production')
.onSnapshot((snapshot) => {
const jobs = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }))
setJobCards(jobs)
})// Cleanup on component unmount return () => unsubscribe() ```
When any workstation updates a job card, every other workstation sees the change within milliseconds. No polling. No manual refresh.
Cascade Updates
One of the trickiest requirements: if a product name changes, every related purchase order, delivery note, and job card across the entire database needs to update automatically.
We built a cascade utility using Firestore write batches:
async function cascadeProductUpdate(productId, newName) {
const batch = db.batch()
const affected = await db.collection('purchaseOrders')
.where('productId', '==', productId).get()affected.docs.forEach(doc => { batch.update(doc.ref, { productName: newName }) })
await batch.commit() // Atomic — all succeed or all fail } ```
Atomic batch writes guarantee consistency. Either all records update, or none do.
PDF Generation
Purchase orders and delivery notes are generated client-side using jsPDF, then printed via a hidden Electron window — the same silent printing pattern we use in our POS systems.
Lessons
- Firestore onSnapshot is transformative for multi-user desktop apps
- Design your role system before writing a single component
- Cascade operations must be atomic — partial updates cause data corruption
- Always give the user a loading state during Firestore writes, even fast ones
PrintFlow has been running in production for 8 months with zero data loss incidents. The client went from Excel chaos to a fully audited, real-time system that all 8 departments use daily.
Developer at Peacebox Studio, building games, ERP systems, and mobile apps since 2016.
More Articles
Building a Secure Bilingual Offline POS with Electron and SQLite
Cover Urdu RTL layouts, renderer/main-process isolation, local backups, inventory workflows, and silent thermal printing.
How Much Does It Cost to Develop an AI App in 2026?
How much does it cost to develop an AI app in 2026? Explore the estimated cost, key development factors, AI features, technology choices, and ways to build an AI application within your budget.
How Much Does Game Development Cost in 2026?
Explain the cost drivers, production stages, scope trade-offs, and questions clients should answer before requesting an estimate.