Lodemas: Online Retail Operations
Lodemas is a production Rails 8 application I built as a freelance project for a Chilean e-commerce business that had been running for nearly five years on manual spreadsheets. The system handles the full operations cycle: inventory tracking, MercadoLibre listing management, order fulfillment, and legally-compliant electronic invoicing (DTE) to Chile’s tax authority.
This is a real tool used by a real business — not a tutorial project.
The Problem It Solves
A small e-commerce business selling on MercadoLibre has a lot of moving parts: products spread across physical storage, listings with multiple variants, orders arriving via webhooks, stock to keep in sync, and tax invoices that must comply with Chile’s SII regulations. Before Lodemas, all of this lived in spreadsheets and manual processes.
Lodemas centralizes it all into one system.
Key Features
Inventory Management
- Hierarchical storage locations (facility → rack → shelf → bin) using a self-referential model with cycle-prevention validation — units can be moved between locations directly from the inventory list
- Individual inventory units tracked with quantity, location, and status (available, allocated, shipped, damaged)
- Configurable restock thresholds with low-stock flagging
- Excel report import to map supplier SKUs to internal product codes
MercadoLibre Integration
- Full OAuth 2.0 flow with automatic token refresh — the app redirects users to the MercadoLibre sign-in screen and handles the authorization callback end-to-end
- Import existing listings and sync stock levels across variants in real time, with a dedicated interface showing each listing’s sync status
- Receive and process orders via webhooks
- Retrieve shipping labels and track shipment status
- Rate-limited API client with exponential backoff built from scratch using Net::HTTP
Electronic Invoicing (DTE)
- Generate Chile tax-compliant electronic invoices via SII’s API
- AWS Signature V4 request signing for SII authentication
- Automatically send generated invoices back to MercadoLibre per order
Background Jobs
- 11 Solid Queue jobs handle async work: order ingestion, invoice generation, stock syncing, webhook notifications, shipment tracking
- Mission Control::Jobs dashboard provides real-time visibility into queued, running, and failed jobs with full backtrace on failures
- All jobs run in-process with Puma — no separate worker process needed in production
Technical Decisions Worth Mentioning
Delegated types for listings — The Listing model uses Rails delegated types so the system can be extended to Shopify, Amazon, or other marketplaces without schema changes. Only MercadoLibre is implemented today, but the architecture is ready.
Multi-database SQLite — The app uses four separate SQLite databases: one for application data, and one each for Solid Queue, Solid Cache, and Solid Cable. This keeps job queue and cache state isolated while staying on a simple deployment model.
OwnedResource pattern — Every controller scopes queries to Current.user via a shared concern. This was designed for future multi-tenancy from day one.
Direct Net::HTTP instead of HTTParty/Faraday — Full control over rate limiting, multipart file uploads, and handling multiple base URLs (MercadoLibre, MercadoPago, SII) without fighting a wrapper’s abstractions.
Tech Stack
| Layer | Technologies |
|---|---|
| Backend | Ruby on Rails 8.0, Ruby 3.3 |
| Frontend | Hotwire (Turbo + Stimulus), Tailwind CSS 4, Flowbite |
| Database | SQLite3, Solid Queue, Solid Cache, Solid Cable |
| Background Jobs | Solid Queue, Mission Control::Jobs |
| Asset Pipeline | Propshaft, Importmap (no Node bundler) |
| Integrations | MercadoLibre API, MercadoPago API, Chile SII API (DTE) |
| Deployment | Kamal 2 (Docker), DigitalOcean, Let’s Encrypt SSL |
| CI/CD | GitHub Actions — Brakeman, RuboCop, Minitest + Capybara |
CI/CD Pipeline
Every push to main runs: security scanning with Brakeman, JavaScript dependency auditing via Importmap, RuboCop linting, and the full test suite with Capybara system tests running against Chrome.