Connecting an app to Odoo without creating a second truth
Six rules for building a satellite application that presents a process without turning into a second system somebody has to reconcile. Including why cache yes, own database no, and how to make it work the same on Odoo Online as on-premise.
Say you have decided a process needs its own screen, outside the ERP. A portal for the shop floor to report production, a packing station, a private storefront for distributors.
Now comes the part where the project goes wrong, and it almost always goes wrong the same way: the application starts saving things.
First the catalogue, "so it loads fast". Then the prices, "they're the same anyway". Then the orders, "just while they're being confirmed". Six months later there are two systems, somebody reconciles them on Fridays, and when they disagree nobody knows which one is right.
These are the six rules we use so that does not happen. None of them is complicated; the hard part is holding them when the deadline shows up.
1. The application has no database. It has a cache
The distinction sounds semantic and it is not. It is the rule the other five rest on.
A database holds things only it knows. A cache holds copies of things somebody else knows, and its defining property is that it can be wiped entirely without losing anything.
That is the test, and it is binary: if you delete everything the application stored and restart it, do you lose information? If the answer is yes, you already have two systems whether you meant to or not.
In practice: cache catalogues, names, categories, lists that rarely change. Give them an expiry. And be far more careful with prices and stock, the two figures where a stale copy is not slowness — it is a promise you cannot keep.
2. The application's session is not the ERP's session
There is a real decision here, with two legitimate paths, and it is worth taking it deliberately rather than inheriting it.
Path A: each person signs in with their ERP user. The application authenticates against Odoo and operates with the credentials of whoever is in front of it. The upside is enormous: permissions are the ERP's, and the record of who did what is the system's real record, not a note. So is the cost: one user per person.
Path B: the application has its own access records and operates through an integration user. An access model built with Studio holds who may sign in, with what password and at what permission level. No licence per operator, which is exactly the point when there are forty of them.
The cost of path B has to be stated in full: the audit trail stops being automatic. Since every write is made by the integration user, the ERP will say it was them. If you want to know who it really was, the application has to write it — usually as a note in the document's history. And each person needs their own password, because a shared one turns that record into decoration.
Neither path is always right. A is for people inside your company with responsibility; B is for volume, and for outsiders who are never going to be users of your ERP.
3. Write little, and write so that repeating it does not hurt
A well-built satellite application reads a great deal and writes very little. Every write is a surface where something can duplicate.
And it will repeat. The connection drops mid-request, the operator presses twice because nothing happened on screen, the process restarts right after writing and before confirming. This is not an edge case: this is Tuesday.
The defence is that every write carries an external reference — an identifier the application generates and the ERP stores — and that before writing you check whether that reference already exists. If it does, you do not create it again: you return what was already created.
It is one line of code, and it is the difference between retrying without fear and finding duplicated orders three weeks later.
4. The cache needs a door to be flushed through, and that door needs a lock
A fifteen-minute cache means that for fifteen minutes you may be showing a stale price. For catalogues that is fine. For the day the price list gets updated, it is not.
The answer is to let the ERP raise its hand: an automated action in Odoo that, when prices or products change, calls the application and tells it to drop that part of the cache. Both sides find out in seconds rather than in fifteen minutes.
With a warning we have learned reviewing this kind of connector: that call is an open door and it needs a lock. An endpoint that flushes the cache with no authentication is an invitation for anyone to wreck your performance with a loop. A shared token is enough, and it costs five minutes on day one — considerably more on the day you have to explain it.
5. Do not assume the version: ask the ERP
Odoo renames fields between versions. That is normal and documented, but if your application hard-codes the name, it works on the instance you tested against and breaks on the next one.
The alternative is cheap: on start-up, ask the ERP what fields that model has and keep whichever name exists. Done once, held in memory, finished.
That small gesture is what lets you say "it works from 16 to 19" without maintaining four versions of the code or crossing your fingers on every new install. And it applies beyond names: if your application needs an optional field, ask whether it is there before reading it, rather than assuming.
6. What the ERP lacks gets built with Studio, not with a module
This is the rule that decides which customers you will be able to install your work on, which is why we left it last despite it being the most important.
Almost any satellite application needs something standard Odoo does not ship: a field for the courier's waybill, a model holding the portal's access records, a flag on the product. There are two ways to create it, and only one works everywhere.
If you create it with a module, it has to be installed. And on Odoo Online the customer cannot install modules, so you have just excluded an entire segment through an implementation decision rather than a product one.
If you create it with Studio — custom fields and models — the customer has it alike on Odoo Online, on Odoo.sh and on-premise. The application never notices the difference: they are fields, and it reads them the same way.
The practical test: if your application lives outside and only needs fields and models, Studio is enough. What Studio does not accept is uploading backend JavaScript or CSS — but a satellite application does not need either, because its interface is its own, not the ERP's.
What you accept in exchange
None of these rules is free, and it helps to have the full list before starting:
- If the ERP does not answer, the application does not operate. That is the direct counterpart of having no second database. There is no offline mode, and pretending there is means reinventing the second truth through the back door.
- Latency is real. Every screen is one or several calls. You offset it with cache where you can, and by measuring where it hurts.
- There is one more server to look after, with its annual cost and its monitoring.
In exchange: nothing to reconcile, no Friday spent working out why two systems disagree, and a single place to fix a figure when it is wrong.
How we solved it
The six rules came out of building three applications and getting some of them wrong before writing the rules down.
The Operations Portal takes path B from rule 2 and writes the operator's name into each order's history, for exactly the reason that rule gives. It also detects the quantity field's name at runtime, which is rule 5 in its most literal form: that field was renamed between Odoo 16 and 17.
The B2B Distributor Portal leans hardest on the cache and on having Odoo invalidate it, because a wholesale catalogue gets browsed a lot and edited rarely.
OneButtonPrint took path A: every operator signs in with their own Odoo user, because what gets recorded there is the validation of a transfer and the trail has to be the ERP's.
All three connect and none installs, which is what makes all three work alike across the three environments.
If you are about to connect something to your Odoo and the conversation has already drifted towards "and we'll store it on this side too", it is worth talking first.
Keep reading
When a screen should not live inside the ERP
An ERP is designed for the person who needs to see everything. Some jobs need three fields. Four questions to decide whether a process needs its own view, a portal, or a separate application — and why the cheapest answer is usually the right one.
Odoo already has plenty of reports. Why we write more
The pivot view answers new questions. Dashboards freeze a view. Neither one stores the criteria, and the criteria is what gets argued about every Monday.

