# Application builds and scheduled delivery

## Data model

`Application` belongs to one customer and identifies a package and platform. Android signing identity is fixed when the first artifact is accepted. `AppArtifact` is an immutable binary plus parsed version name/code, minimum Android SDK, file size, SHA-256, build label, validation/release state and creator. `ArtifactModel` is the many-to-many compatibility map to the shared brand/model/OS catalog.

An application may have several artifacts for one version. For example, build A can support models A1 and A2 while build B supports A3. A deployment always selects one artifact explicitly. Overlapping model maps are therefore allowed without an ambiguous automatic selection rule. Different Android package IDs are separate application records even when their display names match.

`Deployment` records the selected artifact, customer, actor, idempotency key, UTC start and expiry. Its device set is frozen into `DeviceCommand` rows with `NotBeforeUtc`, assignment epoch and the artifact's package/version/hash metadata. Migration `003_Applications.sql` creates these tables and extends the existing command queue.

## Upload and release

1. Customer-authorized operator uploads an APK, manifest ZIP, or native signed A10 `tar.gz`, maximum 128 MiB, and selects one or more catalog models.
2. MVC streams 32 KiB chunks over authenticated gRPC. DataService writes to private artifact storage outside the web root and calculates SHA-256.
3. Archive checks reject traversal, absolute paths, unexpected links, excessive entry count and expanded size/ratio. Native A10 packages may contain only the expected relative `appl.out` link.
4. APK metadata is read in-process by bundled apk-parser; bundled Android apksig verifies signatures/integrity through IKVM .NET assemblies. One signer is required and must match the application's previous signing identity. All selected models must match the package platform.
5. Accepted artifacts enter `Validated`. Explicit operator review moves them to `Released`; only released artifacts can deploy. Failed uploads remove their temporary binary.

This is a trusted-package **development release flow**. Signature validity proves integrity/signing identity, not malware safety. A production scanner/quarantine/approval policy remains required by the architecture; the release screen states that scanning is not configured.

The Versions page permits operators with Applications write access to delete one unused package build or an entire application and all of its versions. Both actions require confirmation, remove the private stored package/icon after the catalog transaction commits, and retain an audit record of what was removed. A build referenced by any deployment is protected from deletion so deployment history and command evidence remain complete.

### Linux package catalog and A10 delivery contracts

The ZIP must contain a root `tms-package.json` with `platform: "Linux"`, `packageId`, `versionName` and positive numeric `versionCode`. Generic Linux ZIP remains a catalog contract unless a compatible Linux agent advertises `install_zip.v1`. UIC Home never advertises Linux installation.

The native A10 package is accepted without repackaging as `prodapp.tarball.tar.gz`. Its outer archive must contain only `app.tar.gz` and `app.tar.gz.sign`; the inner archive must contain a non-empty application executable through `appl.out` and `cfg/version.txt`. When present, `cfg/appname.txt` supplies the portal display name; older packages without it use the `UIC Payment` fallback. Versions such as `A10TBP.02.01.01.04P` are cataloged as the Linux `PAYMENT_APP` application with a numeric version code derived from the four version components. The portal requires the production signature payload and preserves the exact uploaded bytes. xTMSAgent checks the command hash and invokes the A10 vendor update API, which verifies the platform signature and installs into `userappl`.

## Target review and schedule

The review checks customer ownership, enabled device, exact model mapping, platform capability (`install_application.v1` / `install_zip.v1`) and Android API level. Excluded targets show a localized reason. Confirmation revalidates the submitted targets and creates durable SQL commands; no browser timer is involved.

- Blank start means immediately; a specified date/time is UTC, up to 90 days ahead.
- Delivery window is 1–168 hours after start. Offline devices may receive the command during this window.
- No package is dispatched or downloadable before the start or after expiry.
- One outstanding deployment of the same package per device avoids competing installations.
- Cancellation applies to queued targets. Already-dispatched work cannot be reliably recalled.
- Repeated confirmation with the same request ID and content returns the existing deployment.
- The deployment selector never loads the full fleet. It searches 24 terminals per page by partial serial, group/subgroup (including descendants) and tag, and keeps an explicit selected list across searches. **Add all matching** is available when the result is within the 500-terminal deployment limit; larger results must be narrowed before review. The latest 100 deployments are shown.

## Delivery and completion

The existing broker polls due commands and publishes them to the device's authenticated MQTT topic. The APK remains out of MQTT messages. The agent downloads through `https://<portal>/device-packages/<commandId>` using its provisioned credentials. The endpoint rechecks device, customer, assignment epoch, artifact/model, command state, start and expiry. HTTP requests are rejected; redirects are not followed by the agent.

UIC Home serializes commands in private storage, bounds downloads, validates size/hash/package/version/signer, rejects a lower installed version and calls the selected brand SDK. It reports success only after the installed package version and installed APK SHA-256 match the artifact. Results survive process restarts and are retried until SQL receipt confirmation. The server additionally checks that success evidence matches the command's package/version/hash. A dispatch acknowledgement is never displayed as installation success.

xTMSAgent applies the same durable command/result rules. It rejects unsafe updates while the payment application reports open transactions, downloads the exact A10 artifact over authenticated HTTPS, checks SHA-256 and calls `os_update_application`. It queues verified result evidence before requesting reboot; after restart it reports `cfg/appname.txt`/`cfg/version.txt` inventory. Uninstall coordinates payment-app shutdown, removes/recreates `userappl`, reports `absent=true` and also reboots. The development `updateTMS.sh` is not used for portal deployments.

Statuses: Scheduled → Queued → Dispatched → Succeeded / Failed, with Cancelled and Expired terminal alternatives. “Dispatched” includes download/install time; detailed percentage progress is not implemented. Repeated MQTT delivery uses the persisted command record to avoid reinstalling the same command.

## Local development

DataService requires no external APK tools. The package includes the .NET-compatible inspection libraries and runtime support. Configure `ArtifactStorage` for the host; obsolete `AndroidBuildTools` and `JavaPath` settings are ignored. The private artifact directory must be retained together with the database; database-only backup does not preserve binaries.

The portal's local HTTPS package listener is `PortalPort + 2` (15102 by default) and uses the configured local development certificate. The lab enrollment adds `packageBaseUrl: "https://localhost:15102"`; USB testing forwards 15102 and 18883 through ADB. Device credentials remain in private encrypted enrollment storage and must never appear in documentation or logs.

Build the Android test APK before running `scripts/Test-Integration.ps1`; application integration checks validate the actual signed file at `agents/uicu_home/launcher/build/outputs/apk/uicNewpos/debug/app-uic-newpos-debug.apk`.

## Physical test evidence

The current clean integration suite passes 239 checks, including multi-model logical versions, model-specific artifacts, scalable target selection, command evidence and Android/A10 package rules. The .NET solution builds without warnings. English/Spanish resources have matching keys.

BANPAIS / NEWPOS NEW9810 / label serial H3R000700069081:

| Test | Observed result |
| --- | --- |
| Immediate push of 3.1.0-dev (code 2) | Downloaded through authenticated HTTPS; exact installed APK already matched; succeeded with `already_installed_verified` |
| Scheduled push of 3.1.1-dev (code 3) | Withheld as Scheduled, dispatched when due, NEWPOS SDK installed code 3 |
| Completion after self-update | Reopening UIC Home resumed the durable command; installed SHA-256 matched and `installed_verified` receipt committed |

NEWPOS NEW9810 and NEXGO N82 both completed portal uninstall followed by one logical UIC Payment deployment that resolved each model's APK. UIC A10-T completed native payment-app upload, install, reboot/inventory refresh, uninstall and reboot through xTMSAgent. Production signing/trust, canary/rollback policy and fleet reliability remain to be qualified.
