Skip to content

Reference app behaviour

This page collects how the reference implementations behave where it matters for interoperability. Items marked deviation are cases where an implementation does not follow this specification; they are listed so that other implementations can work around them until they are fixed.

  • Payloads are decoded leniently with the documented defaults. A record is not shown when a required field is missing or any known field has a value of the wrong type. Required fields per entity are marked required or server in the entity reference.
  • Dates must be RFC 3339 with seconds and a time zone; fractional seconds are ignored. 2026-10-12 or 2026-10-12T08:15Z make the record invisible.
  • Numbers must be JSON numbers and booleans JSON booleans; numeric strings make the record invisible.
  • A movement whose article is unknown is kept but does not count towards stock and is not shown until the article arrives.
  • Unknown columns values in templates are dropped; unknown signature roles are not shown; unknown recipient kinds read as customer, unknown or missing borrower_kind as employee.
  • Optional fields without value are left out of the payload rather than written as null.
  • When it writes a new version, the app keeps the top-level keys of the previous version that it does not know itself (it finds them by decoding and encoding the previous version). Known fields it leaves out are cleared. Unknown nested keys (inside items, returns, signatures) are lost when the app rewrites a record.
  • Dates are written in UTC with whole seconds.
  • Ids are written in upper case; stamps in upper case.
  • Writes created_at on articles, locations and recipients when it creates them.
  • Writes items[].barcode on delivery notes.
  • Does not read or write document_template.numbering.next; the device counter lives on the device.
  • Delivery note title is printed as written; {number}, {date} and {recipient} are replaced only in intro, closing and footer.
  • Syncs one round at a time: at start, 1.5 seconds after local changes, every 60 seconds and when the network returns.
  • Reads info on every round, also while paused, to pick up licence changes.
  • Does not read auth or features; offers both sign-in methods and requests number reservations whenever the delivery note template is in server mode, ignoring failures.
  • Matches push results to changes by position; results[].id and results[].entity may be null.
  • Stores the message (or, without one, the reason) of a rejected change and stops sending it until the user retries or discards it.
  • Persists the pull cursor after every merged page. On invalid_cursor it forgets the cursor and starts over with a full pull in the same round.
  • Downloads missing attachments after the pull; failed downloads are retried in the next round.
  • Uploads only attachments it holds, before each push batch.
  • Uses request timeouts of 15 seconds (start of response) and 120 seconds (whole request).
  • Does not compare inventory.id with an earlier connection.

Reference app: derived values and documents

Section titled “Reference app: derived values and documents”
  • Stock rows with an absolute value up to 0.0005 are hidden; quantity comparisons use a tolerance of 0.0005.
  • Serial numbers are matched case-insensitively, for stock as well as for the outstanding serials of a loan.
  • Overdue days are computed in the device's time zone.
  • Loans are numbered on the device (UE-{YYYY}-{DEV}-{SEQ:4}); there is no server number range for loans.
  • Device numbering appends the counter when the format has no {SEQ} and replaces only the first {SEQ}.
  • Builds the CloudKit record from the current version of a record, not from the outbox entry. A saved version acknowledges every queued entry of that record with the same or an older stamp, so a record written twice before the next iCloud sync does not stay pending.
  • Does not enforce locked templates on other iCloud devices (there is no server); a locked template is only shown read-only.
  • Validates payloads with Laravel rules that accept looser forms than clients read: numeric strings, "0"/"1" booleans, any date PHP can parse. Writers must not rely on this.
  • Rejects unknown values of closed sets (template columns, movement type, return condition), which readers would ignore.
  • Does not check the location fields per movement type, references between records, the due date of external loans, or signatures.
  • Formats reserved numbers without {DEV} support and without appending a counter when {SEQ} is missing; restarts the counter every calendar year regardless of the format.
  • Applies the template lock to any document_template whose stored version has locked: true, not only to the loan template.
  • Accepts any numeric cursor of up to 18 digits, also beyond the end of its log.
  • Rate-limits only the sign-in endpoints.
  • Accepts any attachment content type.
  • Projects articles (with prices and accessories), locations, recipients, movements, delivery notes, loans and serial numbers into its read model for the admin panel; lve:project --fresh rebuilds it.