Portfolio / Custom operations ERP
The operating system of an omnichannel boutique.
Curvy Boutique sells in its Bucaramanga store, online, over WhatsApp and on Instagram. We designed and built a mobile ERP that connects inventory by size and colour, sales, orders, customers, production, cash, invoicing and marketing, without duplicating what WooCommerce already does.

01The challenge
Big-company complexity, a boutique team.
A small omnichannel boutique has a chain's problems: garments in six sizes and several colours, one stock shared by the counter and the website, split payments, holds that come in over WhatsApp, orders to pack and ship, workshops delivering production and an electronic invoice the Colombian tax authority requires. All of it, managed across WordPress, spreadsheets and loose services.
The core risk was inventory. A second system with its own stock would have produced two truths at the first simultaneous sale. So we didn't build another stock database: WooCommerce remains the source of truth, and the ERP was designed around contracts, auditing and idempotency.
What had to be coordinated
- 01Variable products by size and colour
- 02Stock shared by store and website
- 03Counter sales with split payments
- 04Holds from WhatsApp and Instagram
- 05Web orders, packing and shipping
- 06Production with workshops
- 07Cash, promotions and reports
- 08Colombian electronic invoicing
- 09Emails, campaigns and newsletter
- 10Different roles for owner and associate
Our role
Discovery and operations modelling, architecture, product design and visual system, frontend and backend development, integrations, automations, testing, documentation and deployment strategy.
02The rule
The decision that ordered the whole system.
One inventory. WooCommerce rules.
WooCommerce keeps the catalog, variations, prices, stock and orders. The ERP's own database stores only what the store doesn't model well: users, walk-in customers, movements, audit log, production, cash, invoices, campaigns and sync events. The ERP records every movement but never deducts twice.
On top of that rule, four product principles: built for the shop floor rather than a desk, in the store's own words, one source of truth, and an operation that doesn't stop when a secondary service fails.
Mobile firstStore languageOne source of truthFail well
03Designing around the operation
A brand tool, not warehouse software.
Run it one-handed.
The bottom navigation puts Home, Products, Sell and Orders first. Every touch target is 48 px or more, fields use 16 px so the iPhone doesn't zoom, and critical journeys are tested at 390 px.
The way the owner talks.
On hold, Paid, Packed, Shipped, Delivered. «I counted the garments», «Stock came in», «Undo». The complexity of WooCommerce's statuses and metadata stays behind that vocabulary.
The sale never waits.
Selling doesn't depend on n8n, a failed email doesn't cancel a sale, a rejected invoice stays retryable, and AI falls back to local rules if it doesn't answer. Secondary things recover later; the counter keeps going.
04Core flows
Three stories that happen every day.

Find the garment, pick colour and size with what's left in view, check the cart and charge by splitting the total between cash, card terminal, Nequi and transfer. Before charging, the service rereads stock in WooCommerce: if the size sold out online a second earlier, the sale stops with a warning, not a mismatch.

Tap a cell in the matrix, add or subtract, choose the reason —required— and save. For a few seconds «Undo» appears, only for whoever made the change. Every adjustment is stored as a movement with author and date.

Today's sales by channel, the orders waiting to ship and each order's detail with its garments, payment, customer and next step. A hold keeps the inventory reserved in WooCommerce until it's paid or cancelled.

A garment's stock at a glance: sold out in red, one or two units in amber, three or more in green. Below, the movements —every sale, delivery or adjustment— with who made it and from which order.
05Architecture without duplicate stock
What happens when a garment is sold.
Pragmatic hexagonal architecture: no screen talks to a provider. Domain services validate, check permissions and audit; the ports —commerce, invoicing and email— each have a real adapter and a simulated one, so the same code runs against the store or its double.
PWA panel
Owner and associateServices
Rules · permissions · auditWooCommerce
Catalog, stock and ordersNeon
Movements and auditSIIGO
Electronic invoicen8n
Sync and reconcile
- 01
The associate charges
A Server Action validates the cart and payments and checks the user is allowed to sell.
- 02
Fresh stock
The service rereads the variants in WooCommerce, bypassing cache. If a size sold out, it returns a conflict the screen knows how to explain.
- 03
WooCommerce creates the order
The store creates the order and deducts the stock. It is the only one that deducts it.
- 04
The ERP records
A movement by size and colour and an audit entry in its own database: who, when and from which order.
- 05
Invoice and receipt
If the customer asks, SIIGO issues it with one idempotency key per order. If it fails, the sale stands and the invoice stays retryable.
- 06
Overnight reconciliation
At 02:00 Bogotá time, n8n compares WooCommerce with the last movement and records any difference.
The first real reconciliation covered 42 products and 463 size × colour combinations. That is the scope of the sync, not the catalog's final size.
06Designed to fail well
What separates an ERP from a dashboard.
The system was built without touching the real store: a simulated WooCommerce with products, variations, orders, coupons and the same errors as the real API, and a contract suite that runs the same against the double and the store.
Live starts without writing.
Connected to the real store, the panel starts read-only: any write is blocked before it reaches the network until it's deliberately enabled.
Retrying doesn't duplicate.
Webhooks, invoices, emails, production receipts and movements carry their own key: a repeated event is recognized and dropped. Whatever fails is reprocessed every 15 minutes, up to five times.
Never overwriting a web sale.
The standard API can't add or subtract stock atomically, so we built a small mu-plugin that does it inside WordPress. Without it, the panel reads, checks, writes and retries once.
Every change has an author.
Relevant writes leave a movement or audit entry, a product is created with all its variations or not at all, and archived items can be restored: nothing is destructively deleted.
07The rest of the day
Cash, reports and everything else.

Sales by period, channel and size, with structured recommendations. One analytics source feeds Home, Cash, Reports and the assistant; when no AI model is available, recommendations come from rules.

The store's day, in Bogotá time, split by payment method with split payments broken down. Expected cash against counted cash, and previous closings kept.

Promotions with sale prices and coupons, email campaigns by goal, production with workshops, electronic invoicing and a help centre with task-based guides. All under «More», out of the sale's way.
08A connected ecosystem
Every integration, with one job.
The source of truth.
Catalog, variations, prices, stock, orders and coupons. The ERP is its operating interface and rules layer, not a copy.
What Woo doesn't model.
Walk-in customers, movements, audit, production, cash, invoices and campaigns. PGlite locally, Neon in production.
Syncing without keeping data.
4 flows: Woo → ERP, retries, overnight reconciliation and a private weekly backup. n8n holds no store keys and no customer data.
Electronic invoicing.
Manual or automatic issuing for paid orders that need it, with ID or tax number, VAT included and the CUFE stored.
Transactional email and campaigns.
Receipts, holds, shipping notices and campaigns segmented by consent, with separate domains to protect reputation.
AI that reads, not acts.
An assistant and recommendations with read-only tools, daily quotas and anonymized customer data. It can't move stock or change prices.
Sessions and roles.
Sign-in without public registration, optional persistent sessions and different permissions for owner and associate.
Hosting and backup.
The panel runs on Vercel, and the weekly backup is kept in private storage with twelve weeks of retention.
09Security and privacy
Less wp-admin, less exposure.
The owner and the associate no longer need to log into WordPress or know a single credential. Keys for the store, invoicing, email and AI live only on the server; permissions are checked on every page and every action, and the associate doesn't see what isn't hers to see.
Privacy was designed into the product: data-processing consent is required to save a customer, marketing consent is a separate decision, and unsubscribing from any email is respected. Whatever goes to the AI leaves without personal data.
The model
- 01Public sign-up disabled
- 02Session in an httpOnly cookie
- 03Lockout after five failed attempts
- 04Role permissions on routes and actions
- 05Signed, idempotent webhooks
- 06Separate marketing consent
- 07Anonymized data to the AI
- 08Audit log for sensitive operations
10Evidence of depth
Technical scope, not a commercial result.
Figures counted on the repository. They describe the size of what was built; not sales, hours saved or adoption, which will be measured once the system has been running for a while.
- 22
- own tables, all with tenant_id for more than one store
- 18
- help guides the assistant also reads
- 82
- interface components
- 28
- test files, with E2E journeys at 390 px
- 4
- automation flows in n8n
- 463
- size × colour combinations in the first real reconciliation
11Actual status
Built, tested and switching on in stages.
Built and verifiable in code: navigation, roles and PWA; catalog, inventory, point of sale, holds, orders and customers; production, promotions, cash and reports; invoicing, marketing, newsletter, assistant and help; webhooks, reconciliation, retries and backup, with their simulated doubles and their tests.
Against the real infrastructure we have already tested reading the catalog, the store's webhooks travelling through n8n to the panel, and the reconciliation of 463 combinations. The weekly backup is set up in the store's private storage.
What's left is switched on gradually, on purpose: installing and validating the atomic stock bridge in the store, enabling writes after controlled tests, verifying the email DNS, validating SIIGO with the real account and the accountant, the initial physical count and training with an accompanied first week.
Pending
- 01Stock bridge on the real store
- 02Writes to WooCommerce
- 03Live email after DNS checks
- 04SIIGO with real account and accountant
- 05Initial physical count
- 06Rules to confirm with the owner
- 07Training and first week
12The outcome
What changes when the operation is visible.
A traceable base to grow on.
The result is a platform that makes the boutique's whole operation visible and lets it grow on a traceable, tested base connected to the sales channel it already has.
One panel on the phone replaces scattered trips through WordPress and separate tools, and every size and colour can be followed movement by movement.
VisibleTraceableConnected
beleafdesign
Does your operation live between spreadsheets and panels nobody wants to open?
We design custom systems that work with what you already use instead of replacing it. We can look at how your business runs today and what should fit on a single screen.
Let's talk about your project