Documentation

Complete Professional Manual

The internal logic of Ledyvas: architecture, security, the full data flow, the Formula-by-PAX engine and the business rules of every module. For whoever administers the system or needs to understand why the numbers come out the way they do.

This manual explains the internal why and how. For the step-by-step usage guide, see the User Manual.

1. General architecture

Ledyvas is a desktop application built on Electron. It runs 100% on the client's machine — there is no application server or cloud database. The only thing Ledyvas queries over the internet is a license server (a Cloudflare Worker), and only every so often.

  • Main process: starts the app, validates the license, opens the database and wires up every module before showing the interface.
  • Interface: HTML/CSS/JavaScript with no framework. Each screen is a view loaded on demand as you navigate.
  • Single bridge: the interface never touches the database directly. Everything goes through a service layer with validation, transactions and calculations.
  • Portable mode: the database lives in a Data folder next to the executable. You can copy the whole folder to another computer or an external disk.

2. License and encryption

Ledyvas is activated with a license code against the license server. Validation uses asymmetric cryptographic signing (Ed25519): the private key lives only on the server, so the app could not forge a license even if someone decompiled it.

  • Offline grace: after activation, Ledyvas works several days without a connection. It revalidates in the background whenever there's internet. Only if the grace expires and there's no connection does the app ask to reconnect.
  • Transfer: the license can be moved to another machine. The server enforces one active machine at a time (hardware fingerprint); activating on a new PC deactivates the previous one.
  • Encrypted database: the opshield.db file is encrypted. The key is derived from the license code with PBKDF2 at 210,000 iterations (OWASP standard). If the laptop is stolen, no one opens the database without the license. Because the key travels with the license and not with the hardware, the same license reactivated on another PC opens the same file again — that's why you can move the folder between computers.

3. Database and migrations

Ledyvas uses a single SQLite file. The schema evolves through numbered, ordered migrations: every app update ships new migrations that apply themselves, once, on the first startup, inside their own transaction. A migration that has already been applied is never modified; a new one is added.

On startup, Ledyvas also checkpoints the write-ahead log (WAL) and repeats it in the background every so often — this keeps the working file from growing without bound during long sessions.

4. Catalog and relationships

The catalog is the basis of everything. It's loaded once and referenced in every later operation by its stable internal identifier, never by name — that's why you can rename a product, a destination or a category at any time without breaking the history.

EntityRoleRelates to
ProductAn item bought, sold or produced. Has category, subcategory, unit, cost, barcode.Purchases, Sales, Recipes, Formula, Inventory
Category / SubcategoryClassify the product. Define grouping in Purchase/Inventory and which "family" it belongs to (Food, Beverages, Single-Use, Fuel…).Product, Formula, Consolidated views
SupplierWho you buy from. Can have a list of supplied products with cost (reference).Purchase
CustomerWho you sell to. If "reseller", has its own stock.Consumer Sale, Destination
DestinationA distribution point. Can have a linked reseller customer and a sale price per PAX.Formula, Logistics Center, Margin by Destination
EquipmentVehicle or boat. Type (boat/land) and group (company/rented).Fuel, Fleet Consolidated

5. The Formula-by-PAX engine

Only with Excursion Mode on. The Formula translates "how many people you'll serve" into "how much to buy and dispatch".

  1. A Value matrix is set up: for each product × destination combination, how much one person consumes (e.g. 0.25 kg of rice per PAX at destination X).
  2. Each day the PAX per destination is entered.
  3. The run calculates, per line (destination × product): Required = Value × PAX.
  4. From the Required, three adjustments loaded per destination are subtracted: Existing stock (what the destination already has), Return (what it returned) and Beach Inventory (physical count at the point). The result is that line's Dispatch (never negative).
  5. To know how much to buy in total, the Dispatch of all destinations of each product is summed (rounding each line up, because you can't deliver a fraction to a restaurant) and the Warehouse Inventory (shared stock already in the Logistics Center) is subtracted once.

Assisted Purchase A (Food) and B (Beverages) only run this calculation — they're a proposal. They generate no real purchase and touch no inventory. The Purchase screen is the only one that confirms.

Single-Use (disposables) by destinationSingle-Use items are calculated within the Food Formula and dispatched by destination just like Food, though for physical stock tracking they're carried together with Beverages and Fuel.

6. Purchase: how stock comes in

The Purchase screen is the only point in the system that generates a real purchase. On confirmation, inside a single atomic transaction:

  1. The purchase document is inserted (supplier, date, lines).
  2. The quantity is added to each product's current_stock, synchronously.
  3. A movement is recorded in the history (stock_movements) with product, quantity, cost, date and user — full traceability.
  4. The Daily Control module is synced for that day/category.
  5. If the product is Beverages, Single-Use or Fuel, it transfers itself to the internal tracking of those categories within the Logistics Center.

Cancelling or modifying a purchase reverses everything above on the document's original date, not on today's date. Ledyvas does not block the cancellation even if the stock goes negative (see section 16).

Buying isn't sellingPurchase only makes goods come in. Distributing to destinations is an independent process (Logistics Center). You can buy 1,000 and dispatch 700.

7. Logistics Center and Sales

Logistics Center is the only warehouse in the system. From there you sell/dispatch to the destinations. Each sale section (Sale to Restaurants = Food + Single-Use; Sale to Boats = Beverages) has its own PAX, independent of the Purchase PAX — the Purchase PAX and the Sale PAX don't overwrite each other (buying and selling are separate processes).

On confirming a sale, for each destination with something calculated a real transfer is generated: it deducts current_stock, credits the stock of that destination's reseller customer, and records the movement — all inside a single transaction (if one destination fails, everything is reversed). The per-destination dispatch uses the same Formula, adjusted by Existing stock / Return / Beach Inventory, as the Purchase.

The sale validates stock and warns what's missing, but does not prevent confirmation — the operation isn't interrupted.

8. Consumer Sale and reseller stock

Every customer marked as a "reseller" has its own stock balance (reseller_stock). It's credited when the Logistics Center dispatches to it, and deducted when that reseller sells to the final customer on the Consumer Sale screen.

  • Confirming a sale from the Logistics Center automatically creates a draft Consumer Sale per destination. The draft exists and can be edited, but doesn't deduct stock until it's explicitly confirmed.
  • Boat Beverage lines carry no sale price of their own (the package charge per PAX is recorded only once on the Food side, to avoid counting the income twice). They're shown as a cost record, not a loss.
  • Resale is just a report of what's already been dispatched — it generates no movement.

9. Beverages, Single-Use and Fuel

These three families have no separate warehouse or screen. They live inside the Logistics Center with their own stock tracking:

  • They transfer themselves to that tracking when a Purchase is confirmed (instead of adding to the general product stock).
  • From the Logistics Center you record their sales, adjustments, outflows/consumption and returns, each with its own movement type and history.
  • Beverages are subdivided into Alcoholic / Non-Alcoholic.
  • The "Returns of the Day" view consolidates all returns (Beverages by subgroup, Consumables, Fuel) in one place, and that returned stock automatically reduces the next day's purchase suggestion.

In the Consolidated views, these families are not split by destination: they're carried as a general cost (except Single-Use, which is dispatched by destination — see section 5).

10. Fuel drums

For businesses that, in addition to the stock in gallons, handle fuel/oil in physical drums (5, 7, 9, 10 and 18 GL). It's a parallel inventory that syncs by itself with the stock in gallons — nothing ever needs to be entered twice.

OperationEffect
PurchaseAdds drums (by capacity and exact quantity, or with a suggestion for optimal splitting given the gallons you need) and adds the equivalent gallons to the general inventory.
Sale / dispatchRemoves drums by assigning them to an equipment, and removes the gallons from the inventory.
ReturnFull (adds the whole amount), partial (adds the real gallons it contains) or empty (adds no fuel, just returns the container).
AdjustmentCorrects the count after a physical inventory. Asks for the correct value by capacity/state and a reason, and it's audited.

It has its own Day Close (Opening + Purchases − Sold + Returned = Closing) and a full history. The display can be toggled between Gallons and Liters; what's stored in the database never changes unit.

11. Daily Control

It's a reconciliation layer, separate from the real stock. It records, per day/category/product: opening, purchases, dispatches (per equipment/destination), returns and the physical count.

Calculated closing = Opening + Purchases − (Dispatched − Returned). If a physical count is loaded, that is the verified number and it's used as the opening for the next day — so a difference between theoretical and real corrects itself and isn't carried forward.

Real purchases and dispatches sync Daily Control automatically; it can also be edited by hand.

12. How each Consolidated view is calculated

Daily Summary / Operational Consolidated

The total operating cost of the business for the period: the real confirmed Purchase (by category, with the Gasoline/Oil buckets separated) plus the configurable manual costs by category (rent, salaries, commissions, etc. — managed in Settings, not a fixed list). It also shows: PAX for the period, total spend, cost per PAX, and a statistical Average PAX by Destination table (average PAX sold per day to each destination, counting only the days with a real sale). That table is purely informational — it enters no cost calculation.

Margin by Destination

Excursion Mode only. Cost, sales and margin per destination, only for what went through the Logistics Center (real transfers). The cost is frozen in each transfer; the sales use the price stored in the transfer. Beverages and Fuel don't appear per destination (they're shown separately as "other costs for the period").

Fleet Consolidated

Fuel consumption per equipment. In weekly mode it uses a quantity-weighted average (a day of heavy consumption weighs more than a light one). Amounts in local currency or US dollars, per the configured rate.

Export to Accounting — in Ledyvas Enterprise onlyA Ledyvas Enterprise screen (the version available through Ledyvas's Partner channel) that generates, for a date range, files ready to import into QuickBooks Online/Desktop, Alegra, Zoho Books and Odoo: transactions CSV, bank CSV (3 signed columns), native IIF for QuickBooks Desktop, double-entry journal, and supplier/customer/product master data. Sources: purchases, resales (confirmed), fuel sales, the configurable manual operating costs, and fuel entered by hand from the Fuel screen. A manual operating cost is included only if its whole period falls inside the exported range. Totals match Daily Summary / Operational Consolidated for the same period exactly. Tax ID, phone, email and address of suppliers/customers come out as they are stored in Ledyvas (empty if never filled). Some fields are platform-specific closed lists (e.g. "Municipality/Province" in Alegra) — they can't be auto-filled from the file, the user picks them by hand in the importer.

Per-file format: asientos.csv = double-entry (columns id, Date, Entry, Account code, Account, Debit, Credit, Description, Counterparty, Currency, Status, Number, Journal). Odoo recognizes the id column on its own (External ID) and uses it to group the lines of each journal entry into one move. The Status field is draft: journal entries come in as a draft and the user publishes them in their platform. Number is one integer per journal entry (Zoho requires it as "Journal Number Suffix"); Journal carries "Operaciones misceláneas" (Odoo requires it as the Journal field). In the Odoo file, each entry spans several rows and only the first carries date/journal/currency — the following rows leave those columns blank, so Odoo groups the lines into one move. banco.csv = 3 columns (Date, Description, signed Amount) for the bank importer of QuickBooks Online and Alegra. transacciones-detalle.csv is NOT imported into any platform: it is an analysis spreadsheet (one row per product of each purchase/sale) for reviewing costs in Excel.

Account names: asientos.csv and the IIF reference chart-of-account entries by name. Defaults are standard Zoho Books Spanish accounts (Ventas, Costes de productos vendidos, Otros gastos, and Fondos sin depositar as the offset for each purchase/sale), which exist out of the box. The offset is NOT "Cuentas por pagar/cobrar" — those Zoho accounts require a per-line vendor/customer with matching currency, and Ledyvas keeps no payables/receivables. Any account the user assigns in "Chart of accounts" must exist in the target platform before importing, or the row is rejected. In QuickBooks the IIF does use Accounts Payable / Accounts Receivable (BILL / INVOICE), which are system accounts.

Zoho Books: transactions go through asientos.csv in Accountant → Manual Journals → "⋯" menu → Import → "Journals" option (not "applied customer/vendor credit"). In "Map fields": Reference Number = Asiento (groups the lines), Journal Number Suffix = Número (file column, one integer per journal — Zoho requires it numeric), Contact Name = empty (if mapped, Zoho requires each contact to exist with matching currency). The Zoho Banking importer does not accept banco.csv (it requires debit and credit in separate columns).

Odoo: verified live against a real Odoo 19 (Dominican localization, Spanish) — 19 journal entries imported and balanced. Accounting → Journal Entries → gear → Import → asientos.csv. In the Format panel, fix by hand before mapping: Thousands separator = "No separator", Decimal separator = "Dot" (Odoo tends to detect them the wrong way round). Mapping (field names shown for a Spanish Odoo): id = External ID (Odoo maps it automatically — leave it, it groups each entry's lines), Fecha = Fecha, Asiento = Número, Cuenta = Apuntes contables / Cuenta, Débito/Crédito = Apuntes contables / Débito and / Crédito, Concepto = Apuntes contables / Etiqueta, Diario = Diario (usually auto-mapped), and Código de cuenta / Contraparte / Moneda / Estado / Número = leave unmapped (if Odoo auto-maps "Moneda" or "Número", remove them with the X — they cause errors). "Test" must say "Everything seems valid" before "Import". The Journal carries "Operaciones misceláneas" (misc journal of the Dominican localization); a plain Spanish Odoo calls it "Operaciones varias" — if "Test" can't find the journal, use "See possible values" and set the real name in Ledyvas "Chart of accounts". Unlike Zoho, the default account names almost never match the Odoo chart: set the exact equivalent account name in Ledyvas "Chart of accounts" before exporting, or create those accounts in Odoo. Amounts are recorded in the Odoo company currency (the numbers are correct, only the currency label changes; for another currency, activate it in Odoo and map the "Moneda" column). Journal entries come in as drafts.

13. Recipes and Production

A recipe defines, for a finished product, how much of each ingredient it takes. The ingredient can be in a unit different from the product's unit in the catalog (grams in the recipe, kilos in Products) — Ledyvas converts automatically by unit family (weight, volume) before calculating cost and consumption.

On producing, inside a transaction:

  1. Each ingredient is deducted from stock per the converted quantity × batches.
  2. The finished product is added (portions × batches).
  3. The finished product's cost is recalculated as a weighted average between the stock already there (at its previous cost) and what was just produced (at the recipe's cost per portion). If the recipe has no costed ingredients, the previous real cost isn't overwritten.

So the finished product always has a real cost: it's worth the right amount in Inventory and can be sold without the validation blocking it for zero cost.

14. Equipment and Fleet Consolidated

Equipment is the register of vehicles/boats. Each with an automatic code, type (boat/land) and group (company / rented). They're used to attribute fuel dispatches and sales per unit, which then feed the Fleet Consolidated (see section 12).

15. Multi-user, roles and access

Ledyvas has a user system with 5 roles: Management, Purchasing, Sales, Warehouse, Accounting. Passwords are stored only as a hash (scrypt), never in plain text.

Free mode (no login)By the owner's decision, Ledyvas today does not require a username or password to enter — it opens directly with full access. The concept of "current user" and roles still exists: they serve for "Switch user" (which filters which screens are shown in the menu) and for recording who did each operation. There is no blocking login screen.

16. Negative stock: a design decision

Ledyvas never blocks confirming a sale, a dispatch, a production or the cancellation of a purchase due to lack of stock. It's an explicit decision: don't interrupt the business operation. Negative stock is not a program error — it's corrected with the Adjust Stock button on that row (in Products or Inventory), which asks for the correct value and a reason and audits it.

The only exception: a reseller's Return of goods does validate that they don't return more than they received (it physically makes no sense).

17. Backup and Master Delete

Backup (on Home): saves a full copy of the database file with one click.

Master Delete (on Home, "Test Mode"): deletes Purchases, Sales and Transfers from a chosen date onward — never before that date, and never the catalog (Products, Customers, Suppliers, Destinations). It asks you to type "DELETE ALL". Each document is deleted using the same mechanism as an individual cancellation, so the stock reversals stay consistent. It's for clearing test data before operating for real.

18. Languages and currency

Ledyvas is translated into Spanish, Italian, English, French and Portuguese. The language changes on the fly with the flags, no restart. The business currency is set in Settings and governs every amount; the exchange rate to US dollars (configurable) is used in the fleet reports.

19. AI Assistant

The in-app assistant answers usage questions. Architecture:

  • The app sends the question (and the recent history) along with its license and hardware fingerprint to the license server.
  • The server validates the license, applies a limit of 40 questions per day per license (a cost safety net), and only then calls the language model.
  • The AI provider's key is never in the app or the installer — it lives only as a server secret.
  • The assistant always answers in the language it's written to, among the 5 supported languages.

20. Key business rules

  • Buying ≠ selling. Purchase only adds stock. Distribution to destinations is independent.
  • A single warehouse. The Logistics Center. There is no separate depot or "satellite warehouse".
  • Assisted Purchase only calculates. It never generates a real purchase.
  • Stable identifiers. Everything is referenced by internal id; names can be changed without breaking anything.
  • Every stock movement is audited in the history, with the document's real date (not today's).
  • Stock never halts the operation (except a reseller's Return).
  • The physical count rules. In Daily Control, the real count corrects the theoretical one and is carried forward as the next day's opening.

21. Frequently asked technical questions

Can I move the installation to another computer?

Yes. Copy the whole folder (program + Data folder) and activate the license on the new machine. The license transfers itself (the previous one is deactivated). Because the encryption key derives from the license, the database opens on the new PC.

Is the data in the cloud?

No. Everything is on your machine, in an encrypted file. Make backups often.

Why was a produced product worth zero and now isn't?

Producing now calculates the finished product's real cost (weighted average). Before, it had to be entered by hand.

Why does Sale to Restaurants now offer Single-Use?

Single-Use / disposables are dispatched by destination just like Food. They need their Value loaded in the Formula (Assisted Purchase A) and their cost in Products.

What happens if I delete a product that's in a recipe?

Ledyvas warns you before confirming in how many recipes and Formula lines it's used. If you delete it, it's removed from there and those recipes recalculate their cost. If the product has real purchases/sales, it isn't deleted: it's deactivated.

If something isn't covered here

Write to info@ledyvas.com.

Just starting out?

User Manual

If what you need is the step-by-step guide to using Ledyvas day to day, start with the User Manual.