The auto-update system keeps desktop (Tauri) and Android (sideloaded APK) clients up to date. Desktop uses a Cloudflare Worker that proxies GitHub Releases from the private repo. Android uses an Odoo backend endpoint.Documentation Index
Fetch the complete documentation index at: https://docs.laportenard.com/llms.txt
Use this file to discover all available pages before exploring further.
Architecture
CI builds and publishes to GitHub Releases
The
release.yml workflow triggers on v* tag push, builds the signed NSIS installer, and creates a GitHub Release with the installer .exe and its .sig signature file.Client checks for updates on launch
An
UpdateGate component wraps the app and blocks rendering until the update check completes. On web, it passes through immediately.Worker proxies GitHub API
The Tauri updater plugin calls the Cloudflare Worker at
/update/check. The Worker authenticates with the GitHub API using a server-side PAT, fetches the latest release metadata, resolves pre-signed download URLs, and returns Tauri-format JSON.Desktop downloads and installs
Tauri downloads the installer from the pre-signed URL (no auth needed), verifies the Ed25519 signature, installs, and relaunches.
Desktop update endpoint
The desktop client does not talk to GitHub directly. A Cloudflare Worker (workers/update-proxy/) acts as a proxy that handles authentication for the private repo.
How the Worker proxy works
- Fetches the latest release from the GitHub API using a server-side PAT
- Maps installer filenames to Tauri platform keys (e.g.
*_x64-setup.exe→windows-x86_64) - Resolves pre-signed CDN download URLs for each asset (no auth needed to download)
- Reads
.sigfile contents inline - Returns Tauri-format JSON with version, notes, platforms, and signatures
No PAT or auth token is embedded in the app binary. The Worker stores the GitHub PAT as a Cloudflare secret.
Endpoint URL
The updater plugin reads the endpoint fromtauri.conf.json:
Fallback endpoint
If the Worker endpoint is unreachable, the desktop client falls back to a dynamic Odoo endpoint (ifPOS_API_BASE_URL is configured):
Android update endpoint
Android uses the Odoo endpoint directly (the Tauri updater plugin does not support mobile):| Response | Meaning |
|---|---|
200 with JSON body | Update available |
204 No Content | No update available |
Release workflow
Publishing a new version
- Bump
version.jsonand runnpm run version:sync - Commit and tag:
git tag v1.1.0 && git push origin main --tags - CI builds, signs, and creates a draft GitHub Release
- Review the draft on GitHub, edit release notes, then Publish
- The Worker picks up the new release within 5 minutes (cache TTL)
- Existing installations detect the update on next launch
CI configuration
Therelease.yml workflow:
- Validates (Ubuntu): lint, typecheck, unit tests
- Builds (Windows): Tauri NSIS installer with
tauri-apps/tauri-action - Signs with
TAURI_SIGNING_PRIVATE_KEYfrom GitHub secrets - Uploads installer + signature to GitHub Release
cache-warm.yml workflow runs cargo check on main branch pushes to warm the Rust build cache for faster release builds.
Required GitHub secrets
| Secret | Purpose |
|---|---|
TAURI_SIGNING_PRIVATE_KEY | Ed25519 private key for signing update artifacts |
TAURI_SIGNING_PRIVATE_KEY_PASSWORD | Password for the signing key |
Required Cloudflare secrets
| Secret | Set via | Purpose |
|---|---|---|
GITHUB_PAT | wrangler secret put GITHUB_PAT | Fine-grained GitHub PAT with Contents: read on the repo |
Signing
Tauri requires Ed25519 signatures to verify update artifacts. Generate a signing keypair:tauri.conf.json under plugins.updater.pubkey. The private key is stored as a GitHub secret for CI builds.
Updater artifacts
tauri.conf.json has "createUpdaterArtifacts": true, which tells the bundler to generate signed .exe installers with companion .sig signature files during CI builds.
Worker proxy
Source code
The Worker lives inworkers/update-proxy/ in the repo:
Endpoints
| Path | Method | Response |
|---|---|---|
/update/check | GET | Tauri-format JSON with version, platforms, pre-signed URLs, and signatures |
/health | GET | {"ok": true} |
Caching
The Worker returnsCache-Control: public, max-age=300 (5 minutes). After publishing a new release, it takes up to 5 minutes for the Worker to serve the new version.
Deploying changes
Frontend components
UpdateGate
src/features/updates/UpdateGate.tsx wraps the entire app outside AuthProvider. It:
- Detects the platform via
getPlatformInfo()from runtime config flags (IS_DESKTOP,IS_ANDROID) - On web: passes through immediately (no update check)
- On desktop: tries the Tauri updater plugin first (Worker proxy endpoint), falls back to the Odoo endpoint only if the plugin check fails
- On Android: calls the Odoo endpoint directly, then prompts to download
- On error: shows “Continue Anyway” (the
min_client_versionsystem parameter acts as a backstop)
UpdateScreen
src/features/updates/UpdateScreen.tsx is a full-screen blocking component with i18n support (updateScreen namespace in en.json/es.json):
| Phase | What the user sees |
|---|---|
checking | Spinner with “Checking for updates…” |
available | Version info + “Install Update” + “Later” buttons |
downloading | Progress bar with percentage |
installing | Spinner with “Installing…” + restart message |
android-prompt | Version info + “Download Update” button |
error | Error message + “Retry” and “Continue Anyway” buttons |
Platform detection
src/lib/updater.ts exports getPlatformInfo() which reads window.__POS_RUNTIME_CONFIG__:
| Flag | Set by | Purpose |
|---|---|---|
IS_TAURI | lib.rs | App is running in Tauri shell |
IS_DESKTOP | lib.rs | Desktop platform (macOS, Windows, Linux) |
IS_ANDROID | lib.rs | Android platform |
Testing
Manual testing checklist
Desktop
Run
npm run desktop:dev. Verify the update check runs on launch. If a newer version is published, the overlay should appear.Local test server
Build with version
0.0.1, create a fake update JSON for 0.0.2, serve with npx serve, and temporarily point the endpoint to localhost. See AUTO_UPDATE_GUIDE.md for details.Android
Run
npm run tauri android dev. Verify the “Download Update” prompt appears and opens the URL in the browser.Unit tests
Error handling
The update system is designed to be non-blocking on failure:- Network errors during the update check show an error screen with “Continue Anyway”
- The existing
min_client_versionsystem parameter in Odoo acts as a backstop — clients below that version get aCLIENT_OUTDATEDerror after login - Signature verification failures on desktop prevent installation (security requirement)
- Android download failures are handled by the system browser, not the app
File map
| File | Purpose |
|---|---|
workers/update-proxy/src/index.ts | Cloudflare Worker: proxies GitHub API, returns Tauri-format JSON |
workers/update-proxy/wrangler.toml | Worker config (name, repo, GITHUB_PAT secret) |
.github/workflows/release.yml | CI: build, sign, create GitHub Release |
.github/workflows/cache-warm.yml | CI: warm Rust build cache on main pushes |
nu_pos_react/src-tauri/tauri.conf.json | Updater endpoint URL (Worker), pubkey, createUpdaterArtifacts |
nu_pos_react/src-tauri/src/lib.rs | Plugin registration, fallback check_for_update command |
nu_pos_react/src-tauri/capabilities/default.json | Plugin permissions |
nu_pos_react/src/lib/updater.ts | Platform detection, version comparison, update checks |
nu_pos_react/src/features/updates/UpdateGate.tsx | App-level update gate wrapper |
nu_pos_react/src/features/updates/UpdateScreen.tsx | Full-screen update UI (i18n) |
nu_pos_react/src/i18n/locales/{en,es}.json | updateScreen namespace translations |
nu_restaurant_pos/models/app_release.py | nu.pos.app.release model (Android fallback) |
nu_restaurant_pos/controllers/api_v1.py | Odoo update check endpoint (Android + desktop fallback) |