Team — working together without a server

Several people (or several of your own devices) can work on the same records — orders in the ERP, the building in the Modeller. There is no database server and no application server: the devices pass small encrypted bundles through a shared place on GitHub, and each device keeps its own copy.

Videos (the owner's channel, ranked by how well each fits this guide)
  1. No Server To Keep Alive — Books Still Close (2026, 8:25): the whole Standard imports, local first section.
  2. The Server Is Dead. Local First ERP multi user setup (2026, 3:15): Set up.
  3. Team Trust and Thin Pipe in serverless local first ERP (2026, 6:18): For the team admin. Its chapter 3 ("a second device can work the results out") was later superseded; see Who may complete a document.
  4. No Server In The Sale Path — Replication Engine (2026, 5:07): background on the concept; it uses earlier simulated data.
  5. POS to ERP integration fast demo from scratch and Sistem ERP iDempiere sepadu dengan POS Unicenta (2019; the second in Malay): the owner's earlier Unicenta POS integration, the prior art of the till's day.
  6. Micro Financing local first payment mobile UI with ERP admin (2026): an earlier mock-up (ThaiGoldPawn); this guide's Micro Finance steps use the GardenWorld borrower page.
  7. From Compiere to iDempiere to SQLite Kernel ERP (2026, 1:46): where this ERP comes from.

Set up

▶ Watch: The Server Is Dead. Local First ERP multi user setup

  1. Press the Team pill (the two heads) — in the Modeller, the Team icon. Press Turn on team mode. The page reloads; in the ERP a Team chip appears in the status bar.
  2. On the first device, open the Team panel and press Start a team. (In the ERP the panel first asks the Kind of team; Office team is the default, and the choice for a till-and-phone team is in Standard imports, local first.) Copy the invite link it shows.
  3. On the other device, open that link (or paste the invite into the panel) and press Join. It shows a device code and Waiting for approval.
  4. Back on the first device, press Check join requests, match the device code, choose the role and press Approve. (In a point-of-sale team, a role that the plan addresses to one record also asks what the device is Bound to.)
  5. On the joining device press Visit. From now on, work as usual and press Visit to send your changes and fetch everyone else's.

You can also pick Your avatar in the panel; the others see it after your next Visit.

The system default, and your own

The Team panel shows System default: a ready-made shared place (a trial repository on our GitHub) so you can try it without setting anything up. You can replace it at any time with your own repository and key (Save as my own); the panel then says Your own.

The trial covers one full test cycle: an order, its line, and Complete. After the first Complete, further new changes stay on your device and the chip says Trial cycle finished. Use your own repository and key to keep going — there is no limit on your own setup.

Who is on what

The Team panel has a People list: who is active, what each person is on, and their last tasks. In the ERP, My role scope shows the people whose role is close to yours and Everyone shows all (the Modeller always shows everyone). Tick Don't show what I'm on if you prefer not to share it. In a point-of-sale team (see Standard imports, local first), a device approved against a record also shows that record's name after the role, for example the branch of a till. In the ERP, when you open a record someone else is editing, a note at the top of the form says <name> is editing this and for how long.

What the chip tells you

Team · 1A2B-3C4D · team devices 2Your device code and how many devices the team has.
waiting for approval — press VisitThe founder has not approved this device yet (or you have not visited since).
my ops · seen · refused · waiting on · last visitWhat you sent, how much of it the others have seen, how much was refused, and when you last visited.
Your copy of … is not the team's … Update it, then try again.Every device in a team must start from the same copy of the shipped demo data. Until yours matches, nothing is taken in and your own new changes stay on this device.
N changes from a newer app wait — update this appSomeone works with a newer version of the app. Their changes are kept, not lost; they are taken in as soon as you update.
N changes wait for a translation rule from the team adminSomeone works with an older version. The team admin publishes a rule that translates their changes; your device picks it up on its next Visit and takes the changes in.
changes from a retired version were ignoredThe team admin has retired that old version; changes still made with it are not taken in.
N local-only (not shared)Changes that stayed on this device (for example after the trial cycle). Hover to see why.
SeatbeltPress it before you Process a document. It checks nine things that decide whether your work will reach the team as you expect: the shared starting data, your device's approval, changes not yet sent, refused changes, missing changes from others, changes waiting for an app update, records someone else changed, changes kept on this device, and document numbering. Each line says OK or ADVISE and what to do. It never stops you: if you Process anyway, that is noted in the log and listed in the panel.
TermsShows which promises of team mode are checked by a test that must fail when the promise is broken, and which are not promised yet. It shows a recorded run and the command to repeat it. The same run is published as the Project quality objectives (tested properties and stated limits, not a warranty; see GOVERNANCE.md). How each term is checked, how to run the checks yourself, and how team data is encrypted and sealed: Team — for developers.

Document numbers in a team

There is no central counter in team mode, so each person numbers their own documents. When a device joins a team, every document type that has no prefix of its own gets one: organization – user – number, for example HQ-gardenad-50000. The middle part is the Search Key of the user you log in with (User window). Each user has their own running number, so two people working offline never give out the same number, and the number shows where it was made.

What happens when two people change the same thing

If two devices change the same field (or both Complete the same document) before they have visited, nobody's work is silently dropped: both devices show the same message as the classic client, Current record was changed by another user, please ReQuery, and keep the last agreed value. A Complete is all-or-nothing: until the clash is settled the document stays as it was, with none of its consequences.

Who may complete a document (ERP)

Who may complete a document is a role, the same as in the classic client: the role's Document Action Access tab (Role window). The Process button lists, under Document Action, only the actions the role you are logged in with may use on that document. If none is left, the list is empty and the button says No legal actions from ….

A team can also name the one role that completes each kind of document: for example only head office's role completes orders, while the shops' devices only send in their sales. The team admin publishes that list (see For the team admin). On every device it then works like ordinary Document Action Access: for the roles that are not the executor, the Process button offers no document action for those documents, and the offer comes back by itself when the list changes.

Standard imports, local first

▶ Watch: No Server To Keep Alive — Books Still Close

A till or a borrower's phone never calls the office while it works. It writes its own rows on the device (the classic client's Import Order lines and Import Payment tenders) and they go up at the next Visit. Head office then runs the same import processes the classic client has, so the books are made the classic way. No real-time connection is needed anywhere.

1. Set up a POS team

  1. Log in (in the GardenWorld sample: GardenAdmin). Press the ⋯ button at the bottom right, then the Team pill. Press Turn on team mode (the page reloads), then open the Team panel again.
  2. Choose the kind of team, then press Start a team. Under Kind of team choose Point-of-sale team (tills and phones send up what the plan declares and receive only what is addressed to them). The other choice, Office team, is the default: everyone shares the same records. Then press Start a team. The choice is written into the team when it starts and every device reads the same one, so it cannot be changed afterwards: the panel then shows Kind of team: Point-of-sale team · chosen when the team was started; it cannot be changed, on this device and on every device that joins. The two choices appear only when the app has both plans; if it has only the office plan there is nothing to choose. (An address ending in ?teamplan=pos still works, but only to have Point-of-sale team ticked when the panel opens; you can tick the other one.)
    The Team panel's Pairing box before a team exists: Kind of team with Office team and Point-of-sale team, and the Start a team button
    Before: This browser is not in a team yet. and the Kind of team choice.
    The Pairing box after Start a team, with the kind of team shown as fixed, the invite link and Check join requests
    After Start a team: the kind of team (fixed), the Invite link and Check join requests.
  3. Copy the invite link. On each till (or phone), open it, or paste the invite into the Team panel and press Join. The device shows a device code and Waiting for approval — then press Visit. (The borrower's phone has its own page, see section 4.)
  4. Back at head office press Check join requests and match the device code. In the role list choose Web Service Execution (50004): a Bound to list appears under it (next step). Press Approve when it is filled.
  5. Bind the device to its branch or its customer. In a point-of-sale team a device is tied to one record, and the plan then sends it only what is addressed to that record. The Bound to list is grouped by the kind of record the plan addresses, named as the dictionary names it: Organization (a till is bound to its branch) and Business Partner (a borrower's phone is bound to the customer). Choose the till's branch or the borrower's customer, then press Approve. A record made in this session is on the list too. If you leave it at — choose — the panel refuses and sends nothing: Choose what this device is bound to first: the plan sends it only that record's data. A second device of the same branch is approved onto the same record by choosing the same one. A branch's replenishment goes only to the till bound to that branch.
    A join request with role Web Service Execution (50004), the Bound to list left at choose, and the refusal message
    Role 50004, Bound to left empty: refused, nothing sent.
    A join request with role Web Service Execution (50004), Bound to set to Store North, and the Approve button
    Bound to set to the branch Store North; then Approve.
    A role the plan addresses nothing to (for example head office's own role) shows no Bound to, and an office team never shows it. A device bound to nothing is sent nothing. In the Team panel's People list ("Who is on what") each bound device shows its record's name after its role.
    The People list with each bound device's record shown by name
    The People list: each bound device shows its branch or customer.
  6. Why tills and borrowers use Web Service Execution. It is the classic client's own role for an outside system that only deposits import rows: it has no windows, only two processes, and no Document Action Access, so it is offered no Complete. What tells one till from another, or a till from a borrower, is the record it is bound to, not its role.

2. The till's day, including offline

▶ Prior art: POS to ERP integration fast demo from scratch (2019) · Sistem ERP iDempiere sepadu dengan POS Unicenta (2019, Malay)

  1. Each sale is saved on the till itself: its lines as Import Order rows (the ticket number is the Document No, for example POS1/2026-10-28/0101: station, date, number, so it is unique) and its tenders as Import Payment rows. A return is a line with quantity −1. These are plain saved rows; nothing waits for a connection.
  2. Nothing leaves the till until you press Visit on the Team bar. A Visit sends only what this till wrote, and brings back only what the plan declares for it (below).
  3. No connection: the Visit does not go through. Nothing is sent and nothing is lost; the tickets stay on the till, and head office sees none of them. When the connection is back, one Visit sends them all, once; the Visits after that send nothing more.
  4. What comes back: only the stock movement that head office made for that till's branch. The till is not sent its completed orders, or any other branch's movement.

There is no standalone till program yet: a till today is a device that deposits these rows.

3. Head office's day

Sign in as a head-office role (in the sample: GardenAdmin, role GardenWorld Admin). Everything below is in the menu, under the classic client's own names.

  1. Look at what arrived. Menu Data Import lists the import windows. Import Order shows the tills' ticket lines; its columns Imported (N or Y) and Import Error Message tell you what is waiting and what could not be made. Import POS Sale shows one row per ticket with Lines, Tenders, Lines Total, Tenders Total and Difference (Tenders - Lines), so a ticket whose money does not add up is visible before you import it. (The two POS entries appear when the System Administrator has started the POS integration plugin, see section 5.)
    The Data Import menu with Import Order, Import Payment, Import POS Sale and Import POS Sales
    The Data Import menu.
  2. Import POS Sales (or Import Orders). For POS sales open Import POS Sales: Tenant, Organization, Bank Account (required) and Ticket No (one ticket only), then Run. Each ticket is made all or none: one completed order, its invoice, and its receipts allocated to it, so nothing is left open. A ticket whose tenders do not match its lines is left whole, marked E with a message that names both totals. The answer reads OK #1/0: tickets made / tickets left whole.
    The Import POS Sales dialog
    The Import POS Sales dialog.
    For plain orders open Import Order, press the gear in the toolbar, choose Import Orders, set Tenant, Organization and Document Action (choose Complete; the dialog starts at Prepare), and press Run. The answer OK #1/3 means one order with three lines.
    The Import Orders dialog
    The Import Orders dialog.
    The Import Orders answer OK #1/3
    The first run: one order, three lines.
  3. The error column. A line that cannot be made stays in Import Order with Imported N and the reason in Import Error Message, for example ERR=Invalid Product,. Correct the row and run the import again.
    The Import Order grid: three lines imported (Y) and one line not imported (N) with ERR=Invalid Product, in the error column
    Three lines imported, one left with its reason.
  4. Run it twice and nothing new is made. Running Import Orders again answers OK #0/0: rows already imported are never made again.
    The Import Orders answer OK #0/0
    The second run: nothing new.
  5. Replenish. The person who looks after stock opens Replenish Report (menu, or type in Filter menu…), chooses the branch's Warehouse and, to make the movement, Create = Inventory Movement. The movement is shared at the next Visit and goes back to the till of that branch only. Today a person runs it; the plan names a daily schedule, but nothing starts it by itself.
    The Replenish Report dialog
    The Replenish Report dialog.
  6. End of day: posting. Whether the books are posted at once or at day's end is the tenant's own setting, CLIENT_ACCOUNTING. The GardenWorld sample posts at once. To post at day's end, open System Configurator and add a record for the tenant with Name CLIENT_ACCOUNTING and Configured Value Q. At the day's end run Tenant Accounting Processor from the menu; it posts what was queued.
    The Tenant Accounting Processor dialog
    The Tenant Accounting Processor dialog.

4. Micro Finance

▶ Watch: Micro Financing local first payment mobile UI with ERP admin (an earlier mock-up, ThaiGoldPawn; the steps below use the GardenWorld borrower page)

Customers' instalments on the GardenWorld books. It follows the same spine as the POS: the phone declares a payment row, head office imports it, the books are posted at the end of the day.

  1. The System Administrator starts it once. Sign in as System / System, press ⋯ then the Plugin Engine pill, and press Start beside org.kernel.mf-lens (and org.kernel.pos-integration for the POS windows). They are installed but stopped until then.
    The Plugin Engine card as the System Administrator, with Start beside the stopped bundles
    The Plugin Engine as the System Administrator.
  2. Sign in as the GardenWorld admin. The home page now has a Micro Finance box with six links: Customer Invoice, Recurring, Recurring Run, Import Payment, Tenant Accounting Processor and Open Items. Each opens that window or process. Only the GardenWorld admin role sees the box; stopping the plugin removes it.
    The Micro Finance box on the home page with its six links
    The Micro Finance box on the home page.
  3. Bind the borrower's phone before you issue the loan. On the phone open https://red1oon.github.io/bim-ootb/erp/borrower.html, open Phone set-up, type the team's 64 characters (the part after #join= in the invite link) into Join a team (space id) and press Join. The phone shows This phone: …. At head office do Check join requests, choose Web Service Execution (50004), and under Bound to choose the customer (a Business Partner), as in section 1 step 5. Until it is bound the phone says This phone is not bound to a customer yet. If you bind after the loan was issued, the loan reaches the phone anyway, once, when you bind.
  4. Set up the slip check on the phone, once. In Phone set-up fill Name, Adapter class, Host, Branch id and Key and press Save the service; the phone then says Using SlipOK (org.kernel.slipverify.SlipOK). This stays on that phone. SlipOK is only the sample service; another provider is another adapter and the same page.
  5. Issue the loan. From the box open Customer Invoice and make an invoice for the customer on an instalment payment term (the sample has 50% Immediate - 50% in 30 days), add its line and Complete it. At the next Visit it reaches that borrower's phone, and only that phone: Loan, the Open (per head office books) amount and the due dates. The open amount is worked out from what head office has allocated; the phone never stores a balance.
    The borrower's phone showing a loan with its open amount and two due dates
    The loan on the borrower's phone.
  6. The borrower pays. After a bank transfer, under Pay with a bank transfer slip choose the Loan, paste the Slip QR code (text), enter the Amount you paid and press Check the slip and save. Three things can happen:
    The phone with three slips: Payment received, Waiting with its To do note, and Not accepted
    All three on one phone: the banner for the last slip, the To do note for the waiting one, and My slips listing Payment received, Waiting: … and Not accepted.
    Only approved slips are ever sent to head office. A slip that is waiting stays on the phone; a refused slip never leaves it. The messages in the pictures are the sample service's recorded replies.
  7. Visit. Press Visit head office on the phone: approved slips go up, and the phone shows Last visit: …. At head office open Import Payment (from the box); the slips are there as rows. Run its process (Import Payments: Organization, Bank Account, Document Action, Delete old imported records) to make the receipts, allocated to the loan. The next Visit brings the new open amount back to the phone. Then post the books as in section 3, step 6. The import has no duplicate guard of its own; the phone refuses a second slip with the same bank reference.
  8. Renewals. Recurring holds the template. When a renewal is due, run Recurring Run (Recurring Group, Cut Date, Document Action, Parameter Comment): it makes the invoices that are due, and each reaches its borrower's phone at the next Visit as another loan.

5. Plugins: everyone can see them, only the System Administrator changes them

  1. Press ⋯ then the Plugin Engine pill. (The sign-in page also has a Plugins & Releases link to the same list.)
  2. Every role sees the same list: each plugin's name, version and state. A role other than the System Administrator sees this notice, and no Install, Start, Stop or remove button:
    The Plugin Engine card for a GardenWorld role: the read-only notice and the list without buttons
    The Plugin Engine for a GardenWorld role.

    Read-only: only the System Administrator can install, start, stop or remove plugins. You can see what is installed.

    On Plugins & Releases the same notice says Read-only: only the System Administrator can install, start, stop or remove bundles. You can see what is installed. A plugin's own settings are not shown to a read-only role.

  3. Only the System Administrator can install, start, stop or remove a plugin. The rule is in the plugin registry's own calls, not only in the buttons: a call from another role is refused and changes nothing, and everything the administrator does is logged with who and what.

For the team admin

▶ Watch: Team Trust and Thin Pipe in serverless local first ERP (its chapter 3 was later superseded: see Who may complete a document)

What we can and cannot see about trial use

On the trial repository we can see how many devices and spaces appeared, how many bundles and rows were sent, and when. The business content is encrypted, so we cannot read your orders. We do not receive your network address: neither GitHub nor the visit log passes it on.

Good to know