Files
QSfera/PRODUCTION_READINESS.md
2026-06-13 20:07:01 +03:00

23 KiB

QSfera Production Readiness

Date: 2026-06-08.

Benchmarks Used

Completed In This Pass

  • Android release builds now fail fast when release signing variables are missing, so unsigned release artifacts cannot be published by accident.
  • Android version was raised to 1.3.12 with versionCode 40.
  • Android version was raised to 1.3.13 with versionCode 41 for the next Argus publication.
  • Android version was raised to 1.3.14 with versionCode 42 for the updated SSH-only Argus publication flow.
  • Android now has QSfera-specific Argus publishing scripts: local upload-keystore generation, signed APK staging, APK metadata verification, debug-certificate rejection, and SSH-only Argus publication through the /srv/argus-data/argus.db and /srv/argus-data/Packages workflow required by G:/Repos/Marketplace/ARGUS_PUBLICATION.md; HTTP /api/admin/* publication is not used.
  • Android Argus update and publication were realigned with G:/Repos/Marketplace/ARGUS_PUBLICATION.md on 2026-06-13: Android/scripts/publish-release.ps1 now generates and runs the SSH/SQLite/Data/Packages server-side publication block, and AppUpdateManager uses only the public read-only manifest contract for update discovery.
  • Android now has Android/scripts/verify-release-signing-material.ps1 to verify local release signing properties, keystore readability, release certificate SHA-256, and optionally the latest published Argus APK certificate without printing signing secrets.
  • Android Argus staging now enforces release git provenance by default: the work tree must be clean, the branch must have an upstream, git fetch must succeed, and HEAD must match @{u} before a stable APK is prepared for upload. The generated argus-publication.json records the verified repository root, branch, upstream, commit, and timestamp; current monorepo publication can verify the pushed root QSfera.git branch by running from Android/ with -GitProvenanceRoot ...
  • Android 1.3.9/37 was published to Argus as qsfera-mobile on 2026-06-10. Argus upload returned release id 53ecc24e-106b-43a5-a39e-ffacd72a43f8, package size 12226572, and SHA-256 cbd2c25328e395ea4da4e0f582feac39dec18d2d47b3e105d344904d8a24f017.
  • Android 1.3.10/38 was published to Argus as qsfera-mobile on 2026-06-10. Argus upload returned release id 8465ba6d-a008-45f5-9c70-e6cd2c94317a, package size 12228464, and SHA-256 ce33a73ce122de6c9c797e7cb552e5493b628c60ddc98fda6a9e230e3c1ed7fe.
  • Android 1.3.11/39 was published to Argus as qsfera-mobile on 2026-06-10. Argus upload returned release id 3dbac5ad-b19c-46e6-b24f-8f22e1c466dd, package size 12234884, and SHA-256 c9eae41bbaae421e1a69721e891d8431ce599684e0f655b71693a422aa83720a.
  • Android 1.3.12/40 was published to Argus as qsfera-mobile on 2026-06-10. Argus upload returned release id 615b58c5-b5f7-4a2a-b6de-03f821eb43a4, package size 12237552, and SHA-256 279d00c6a43072caa0b26269f547fb0dc3268088aae5cd9f4ccfbbb485c35ded.
  • Android 1.3.13/41 was published to Argus as qsfera-mobile on 2026-06-12. Argus upload returned release id 39072ada-7557-48f3-ab42-ad68703d00b0, package size 12261408, and SHA-256 f065e6584e6a09999e72ba0eeeaae903e93fb8980a0426e4b39b5e2366bf6611.
  • Android 1.3.14/42 was published to Argus as qsfera-mobile on 2026-06-13 through the SSH/SQLite/Data/Packages workflow from G:/Repos/Marketplace/ARGUS_PUBLICATION.md. The server-side publication block returned release id 4394333f-a84a-4a3b-9bc7-6a48d054d4fe, stored path qsfera-mobile/20260613170521-1.3.14-4394333FA84A4A3B9BC76A48D054D4FE.apk, package size 12262908, and SHA-256 8ddfbb9d3dbff3f7bc1030024a0f03a7928771b06cb373c8996c96fb22ad5a18.
  • Android/scripts/verify-release-signing-material.ps1 -VerifyPublishedApk passed on 2026-06-12: local Android/argus-signing.local.properties and Android/signing/argus-upload.jks are complete/readable, alias argus-upload exists, and both the keystore certificate and the latest published Argus APK report certificate SHA-256 ea5c304c78ee333f6586f54c933d986c1f865da9c4e3595f8fe0df274c1ab877.
  • Android auto-upload source paths are normalized and new/first source folders start from timestamp 0, so existing media is eligible for initial backup.
  • Android auto-upload validates persisted read permission and DocumentFile.canRead() before scanning SAF folders.
  • Android immediate auto-upload scheduling no longer blocks the caller while waiting for WorkManager state.
  • Android new auto-upload configurations default to Wi-Fi-only transfers for photos and videos.
  • Android auto-upload now exposes a no-roaming control for photo and video backup, stores it in Room schema version 50, and maps mobile backup without roaming to WorkManager NetworkType.NOT_ROAMING.
  • Android auto-upload now exposes a photo/video daily mobile-data limit, stores it in Room schema version 51, and stops queuing additional uploads on metered automatic-upload runs after the configured daily byte limit is reached while keeping skipped files eligible for the next scan period.
  • Android video backup settings now label the Wi-Fi-only control as "Never use mobile data for videos" and explain that turning it off enables metered-network limits and roaming controls.
  • Android photo/video backup settings now show a compact overall backup status: enabled state, selected phone-folder count, network/roaming/charging conditions, and last backup scan.
  • Android auto-upload now stores per-source folder sync cursors in Room schema version 52, keeps the legacy lastSyncTimestamp as a migration fallback, starts newly added source folders at timestamp 0, and preserves per-source cursors when a metered run stops at the daily mobile-data limit. :qsferaDomain:testDebugUnitTest --tests "eu.qsfera.android.domain.automaticuploads.model.FolderBackUpConfigurationTest", :qsferaApp:testOriginalDebugUnitTest --tests "eu.qsfera.android.workers.AutomaticUploadsWorkerTest", and :qsferaData:compileDebugKotlin passed on 2026-06-10.
  • Android photo/video backup status now shows per-source scan state, missing SAF folder access, and selected-account low-storage warnings in the settings summary. :qsferaApp:testOriginalDebugUnitTest --tests "eu.qsfera.android.presentation.settings.automaticuploads.AutomaticUploadStatusFormatterTest" and :qsferaApp:compileOriginalDebugKotlin passed on 2026-06-10.
  • Android photo/video backup status now also observes automatic-upload transfers live and reports uploading, queued, failed, and paused-by-network/roaming/charging states in the settings summary. :qsferaApp:testOriginalDebugUnitTest --tests "eu.qsfera.android.presentation.settings.automaticuploads.AutomaticUploadStatusFormatterTest" and :qsferaApp:compileOriginalDebugKotlin passed on 2026-06-10.
  • Android public-link rows now show the effective access mode, password state, and expiration state directly in the share list, so users can review link safety without reopening each link. :qsferaApp:testOriginalDebugUnitTest --tests "eu.qsfera.android.presentation.sharing.shares.PublicShareStatusFormatterTest" and :qsferaApp:compileOriginalDebugKotlin passed on 2026-06-10.
  • Android now keeps Graph-style internal and blocksDownload public links as server-managed custom-access states in the OCS public-link editor: list rows show Custom access, the edit dialog explains that the link is managed by the server, and saving is disabled to avoid downgrading organization-only or secure-view protection to a standard OCS link.
  • Sharing controls were audited against the Google Drive and Yandex Disk benchmarks in Server/docs/sharing-controls-production-audit.md, and scripts/verify-sharing-controls-coverage.ps1 now checks local Android UI, Graph link types, server link handling, and acceptance-feature coverage for password, expiration, access roles, internal links, secure-view/no-download behavior, and role-based resharing.
  • Server qsfera_full compose files now require explicit admin, Keycloak, and S3/MinIO secrets instead of demo defaults.
  • Server qsfera_full/env.production.example provides a tracked production-safe starting point with TLS validation enabled and demo users disabled.
  • Server qsfera_full/validate-production-env.sh checks production .env invariants before compose validation: TLS validation enabled, demo users disabled, pinned production image, required domains, required secrets, and no public-production MinIO.
  • Added scripts/validate-server-production-env.ps1 with the same qsfera_full production .env checks for the local Windows/PowerShell workflow; it validates required domains, release image pinning, disabled demo/insecure modes, required secrets, optional Keycloak/S3 blocks, COMPOSE_PATH_SEPARATOR, selected COMPOSE_FILE fragments, and backup-friendly config/data path warnings without printing secret values.
  • scripts/validate-server-production-env.ps1 was verified on 2026-06-12: it rejects Server/devtools/deployments/qsfera_full/env.production.example with placeholder values, accepts a temporary filled production-shaped env file with 0 warning(s), and rejects a temporary env file where COMPOSE_FILE omits the required qsfera.yml fragment.
  • Server now has a Raspberry Pi 5 Docker path matching the Ikar/Argus deployment style: Server/docker-compose.rpi5.yml, Server/.env.example, and Server/docs/raspberry-pi-5-docker.md.
  • Server Docker builds now accept explicit production metadata for QSFERA_VERSION, QSFERA_EDITION, and QSFERA_BUILD_DATE, and the Raspberry Pi 5 compose path defaults to pinned image qsfera-cloud-server:7.0.0-rpi5-stable.
  • Windows/Desktop update channel defaults now match the build channel: stable builds default to stable, beta builds default to beta.
  • Windows/Desktop CI now validates production release invariants before Windows packaging and requires signing variables for stable tag releases.
  • Windows/Desktop now has a configured HTTPS update feed at https://qsfera.kusoft.xyz/desktop/updates/stable.xml; the feed returned HTTP 200 on 2026-06-08 and contains the XML elements parsed by Desktop/src/gui/updater/updateinfo.cpp.
  • Windows local autostart was repaired on 2026-06-10 with scripts/repair-windows-autostart.ps1 -Launch: the HKCU Run key QSfera points to the Craft runtime bin\qsfera.exe, required Qt6 runtime DLLs are present there, and qsfera.exe started from that path.
  • Windows tray "Show" now brings the settings window to the foreground after restoring it to an available screen. The same Application::showSettings() path is used by tray menu actions and qsfera.exe --show, and Win32 window enumeration on 2026-06-10 reported Visible=True, Foreground=True, title КуСфера.
  • Windows Desktop now has repeatable local packaging and feed-publication scripts. scripts/package-windows-desktop.ps1 produced a smoke-tested 4.0.0 x64 package with Qt/MSVC runtime files; scripts/publish-windows-desktop.ps1 generated a valid local stable.xml feed for that MSI and refuses remote publication unless the MSI is Authenticode-signed.
  • Windows Desktop packaging now fails before ZIP/MSI creation if the staged app is missing critical Qt6/MSVC/OpenSSL DLLs, the Qt platform plugin, QSfera VFS plugins, QML import manifests, or qt.conf runtime path entries; it also smoke-starts the staged qsfera.exe --version from the staged working directory.
  • Added scripts/verify-production-state.ps1 as a repeatable live production endpoint gate for the public server status, Android Argus manifest/download, and Desktop update feed; the Android gate now pins the stable release id, original APK filename, content type, package size, download path, and SHA-256.
  • scripts/verify-production-state.ps1 -VerifyAndroidDownload passed on 2026-06-10: server edition=stable/productversion=7.0.0, Android 1.3.12/40, downloaded APK size 12237552, APK SHA-256 279d00c6a43072caa0b26269f547fb0dc3268088aae5cd9f4ccfbbb485c35ded, and valid Desktop no-update feed.
  • scripts/verify-production-state.ps1 -VerifyAndroidDownload passed on 2026-06-12: server edition=stable/productversion=7.0.0, Android release id 39072ada-7557-48f3-ab42-ad68703d00b0, Android 1.3.13/41, APK filename qsfera-mobile-41.apk, content type application/vnd.android.package-archive, downloaded APK size 12261408, APK SHA-256 f065e6584e6a09999e72ba0eeeaae903e93fb8980a0426e4b39b5e2366bf6611, and valid Desktop no-update feed.
  • scripts/verify-production-state.ps1 -VerifyAndroidDownload passed on 2026-06-13 against the current public Argus manifest contract: server edition=stable/productversion=7.0.0, Android release id 39072ada-7557-48f3-ab42-ad68703d00b0, Android version 1.3.13, APK filename qsfera-mobile-41.apk, content type application/vnd.android.package-archive, downloaded APK size 12261408, APK SHA-256 f065e6584e6a09999e72ba0eeeaae903e93fb8980a0426e4b39b5e2366bf6611, and valid Desktop no-update feed. The live manifest currently omits androidPackageName and androidVersionCode; the verifier treats both as optional unless strict switches are set.
  • scripts/verify-production-state.ps1 -VerifyAndroidDownload passed on 2026-06-13 after publishing Android 1.3.14: server edition=stable/productversion=7.0.0, Android release id 4394333f-a84a-4a3b-9bc7-6a48d054d4fe, Android version 1.3.14, APK filename qsfera-mobile-42.apk, content type application/vnd.android.package-archive, downloaded APK size 12262908, APK SHA-256 8ddfbb9d3dbff3f7bc1030024a0f03a7928771b06cb373c8996c96fb22ad5a18, and valid Desktop no-update feed.
  • Added Server/scripts/verify-rpi-production.sh, declared a loopback-only Pi metrics port in Server/docker-compose.rpi5.yml, and expanded the Raspberry Pi Docker runbook with local/public status checks, container/image checks, Prometheus metrics verification, backup/restore drill steps, and Docker data-root/retention planning.
  • Added systemd monitoring units for the Pi: Server/systemd/qsfera-rpi-production-check.service, Server/systemd/qsfera-rpi-production-check.timer, Server/systemd/qsfera-rpi-production-check-alert@.service, Server/systemd/rpi-production-check.env.example, plus installer Server/scripts/install-rpi-production-monitoring.sh and alert helper Server/scripts/alert-rpi-production-check-failure.sh.
  • Deployed the Pi metrics/checker update on 2026-06-09. Before upload, /mnt/data/qsfera/cloud-server/src/docker-compose.rpi5.yml was backed up to /mnt/data/qsfera/backups/docker-compose.rpi5.yml-20260609-181614.bak; docker compose -f docker-compose.rpi5.yml up -d recreated and started qsfera-cloud-server; docker compose ps reported loopback ports 127.0.0.1:9200->9200/tcp and 127.0.0.1:9205->9205/tcp.
  • Server/scripts/verify-rpi-production.sh passed on the Pi on 2026-06-09 with PUBLIC_STATUS_URL=https://qsfera.kusoft.xyz/status.php and REQUIRE_METRICS=true: image qsfera-cloud-server:7.0.0-rpi5-stable, container running/healthy, Docker root /mnt/data/docker, root free space 43.0 GiB, data free space 851.5 GiB, local and public status stable/7.0.0, and Prometheus metrics reachable.
  • Deployed the Pi systemd monitoring timer on 2026-06-09. systemd-analyze verify for the three installed unit files returned exit 0; systemctl is-enabled qsfera-rpi-production-check.timer returned enabled; systemctl is-active qsfera-rpi-production-check.timer returned active; systemctl show qsfera-rpi-production-check.service returned Result=success, ExecMainStatus=0, ActiveState=inactive; and journalctl -u qsfera-rpi-production-check.service recorded QSfera Raspberry Pi production verification passed: 0 warning(s).

Raspberry Pi 5 Check

  • Pi target checked on 2026-06-08: 192.168.0.185 reports aarch64, 64-bit Debian 13, Docker 29.4.3, Docker Compose v5.1.3, and Docker server architecture aarch64.
  • Before stable-image deployment, the old Pi server was running as local/dev image qsfera-cloud-server:rpi5-local; public /status.php reported edition: dev and productversion: 7.0.0.
  • The Pi server now runs through /mnt/data/qsfera/cloud-server/src/docker-compose.rpi5.yml with pinned image qsfera-cloud-server:7.0.0-rpi5-stable, bind-mounted config/data under /mnt/data/qsfera/cloud-server, loopback backend port 127.0.0.1:9200, loopback metrics port 127.0.0.1:9205, and Docker root /mnt/data/docker.
  • Before switching the Pi server to compose, config/data were backed up to /mnt/data/qsfera/backups/cloud-server-before-compose-20260608-200921.tar.gz. The archive was created with sudo tar, had size 213M, and tar -tzf completed successfully.
  • Before switching to the stable image, config/data were backed up to /mnt/data/qsfera/backups/cloud-server-before-stable-image-20260608-201536.tar.gz. The archive had size 213M, and tar -tzf completed successfully.
  • docker run --rm --entrypoint /usr/bin/qsfera qsfera-cloud-server:7.0.0-rpi5-stable version --skip-services returned Version: 7.0.0, Edition: stable, and Compiled: 2026-06-08 00:00:00 +0000 UTC.
  • After deployment, docker compose ps reported qsfera-cloud-server as Up and healthy; docker inspect reported IMAGE=qsfera-cloud-server:7.0.0-rpi5-stable HEALTH=healthy.
  • Local https://127.0.0.1:9200/status.php and public https://qsfera.kusoft.xyz/status.php both returned edition: stable and productversion: 7.0.0; the public request returned HTTP 200.
  • After Docker builder cache cleanup and the stable deployment, /dev/mmcblk0p2 reported 57G size, 12G used, 43G available, 21% use. /mnt/data reported 916G size, 18G used, 852G available, 3% use.

Android Argus Publication Check

  • Current public Argus manifest for https://argus.kusoft.xyz/api/apps/qsfera-mobile/manifest?platform=android&channel=stable reports release id 4394333f-a84a-4a3b-9bc7-6a48d054d4fe, version 1.3.14, channel stable, platform android, package kind apk, original file name qsfera-mobile-42.apk, content type application/vnd.android.package-archive, package size 12262908, and SHA-256 8ddfbb9d3dbff3f7bc1030024a0f03a7928771b06cb373c8996c96fb22ad5a18. It does not currently include legacy Android-specific root androidPackageName or release androidVersionCode fields.
  • Independent download verification of https://argus.kusoft.xyz/api/apps/qsfera-mobile/download/latest?platform=android&channel=stable produced a 12262908 byte APK with the same SHA-256 8ddfbb9d3dbff3f7bc1030024a0f03a7928771b06cb373c8996c96fb22ad5a18.
  • The previously published 1.3.5/33 APK matched Argus SHA-256 b7d5bdcb49527c00983a15849252fa42189dee4287754803c46cf2f32e2130f3, but apksigner reported CN=Android Debug with certificate SHA-256 b86d745cecb01ca24bda03092fe94ca7801678513b97edd1175bcabfdea4e941.
  • The current production-signed 1.3.14/42 APK is signed by CN=QSfera Argus Upload, O=QSfera, C=RU with certificate SHA-256 ea5c304c78ee333f6586f54c933d986c1f865da9c4e3595f8fe0df274c1ab877.
  • AppUpdateManager follows the public read-only Argus manifest contract from G:/Repos/Marketplace/ARGUS_PUBLICATION.md: HTTP 404 is treated as no update, release.version is compared with the installed version, downloads use ARGUS_BASE_URL + release.downloadPath, release.packageSizeBytes and release.sha256 are verified before install, and the downloaded APK package name/version/signature are checked against the installed app. Because of that local code path, devices that installed debug-signed 1.3.5 should be treated as needing reinstall or an explicit migration plan before they can move to the current production-signed stable APK.
  • The rollout policy for debug-signed 1.3.5 devices is documented in Android/docs/argus-rollout-policy.md: the app does not bypass signer mismatch; users must back up unsynced local files, uninstall the debug-signed build, then install the current stable APK from Argus. The Android app now shows a reinstall-required dialog for this certificate-mismatch path.

Remaining P0

  • Back up the gitignored Android release signing files created under Android/signing/ and Android/argus-signing.local.properties in a secure external secret store. Without this key material, future in-place Android updates from the production-signed 1.3.14 cannot be signed with the same certificate.
  • Provide CI/Argus signing secrets derived from the same release key: QSFERA_RELEASE_KEYSTORE, QSFERA_RELEASE_KEYSTORE_PASSWORD, QSFERA_RELEASE_KEY_ALIAS, and QSFERA_RELEASE_KEY_PASSWORD.
  • Fill production domains, ACME email, admin passwords, Keycloak passwords, and storage secrets from a secret manager. Do not commit real values.
  • Run ./validate-production-env.sh .env or .\scripts\validate-server-production-env.ps1 -EnvPath ... and then docker compose config for Server/devtools/deployments/qsfera_full with a filled production .env; Docker CLI is not available in this local environment, so compose rendering is not locally verified.
  • Provide real Windows signing secrets in CI: QSFERA_DESKTOP_SIGN_PACKAGE=True and QSFERA_DESKTOP_CODESIGN_CERTIFICATE with the Craft-compatible signing certificate reference. The current local MSI is intentionally not published as a production update because Get-AuthenticodeSignature reports NotSigned and Desktop/scripts/validate-production-release.ps1 -RequireSigning fails until signing is configured.
  • Publish the first signed Windows MSI with scripts/publish-windows-desktop.ps1 -RemoteHost ... and update https://qsfera.kusoft.xyz/desktop/updates/stable.xml from the current no-update XML to a concrete <version>, <versionstring>, and HTTPS .msi <downloadurl>.

Remaining P1

  • Configure QSFERA_ALERT_WEBHOOK_URL in /etc/qsfera/rpi-production-check.env if off-host alert delivery is required; the installed failure service currently logs through systemd-cat and journal without an external endpoint.