Files
QMAX/README.md
T

4.7 KiB

QMAX

QMAX is a multi-user Android messenger client backed by a self-hosted bridge server. Each Android user verifies a separate MAX account, while one QMAX server and one PyMax worker can serve all accounts.

Current shape:

  • server/QMax.Api - ASP.NET Core API, SQLite cache, JWT pairing auth, SignalR hub, attachment storage, APK update catalog.
  • pymax-worker - Python/PyMax worker with an isolated persistent MAX mobile API session per QMAX user.
  • android - Kotlin + Jetpack Compose Android client pointed at https://qmax.kusoft.xyz.
  • deploy - Docker Compose + Caddy for Raspberry Pi 5.

Local Checks

dotnet test QMax.slnx
python -m py_compile pymax-worker/src/server.py
cd android
.\gradlew.bat :app:assembleDebug :app:assembleRelease --console=plain --no-daemon

Raspberry Pi Deployment

  1. Point DNS qmax.kusoft.xyz to the Raspberry Pi public IP.
  2. Install Docker Engine and the Docker Compose plugin on the Pi.
  3. Copy the repository or the archive produced by scripts/deploy-rpi.ps1.
  4. On the Pi:
cd ~/qmax/deploy
cp .env.example .env
nano .env
docker compose up -d --build

This compose publishes QMAX API on 127.0.0.1:18080. The existing system Caddy should contain:

qmax.kusoft.xyz {
    encode zstd gzip
    reverse_proxy 127.0.0.1:18080
}

Set strong values in .env:

  • QMAX_JWT_SECRET - at least 32 random characters.
  • QMAX_PAIRING_CODE - optional server registration code shared with allowed users; leave it empty for open registration.

Secrets must stay in .env, not in git.

MAX Login

On the Android login screen enter the QMAX server URL, the user's MAX phone number and, when configured, QMAX_PAIRING_CODE. QMAX asks PyMax to start MAX authorization. Enter the code delivered by MAX in the app; only after PyMax reports an authorized session does QMAX issue that user a JWT and refresh token.

The worker stores sessions under accounts/<QMAX user id>/ in the qmax-pymax-session Docker volume. Session files and imported-contact mappings are not shared between users.

Android Pairing

Build or install:

cd android
.\gradlew.bat :app:assembleRelease --console=plain --no-daemon

On first launch:

  • Server: https://qmax.kusoft.xyz
  • Phone: the user's MAX phone number
  • Registration code: QMAX_PAIRING_CODE from .env, if the server owner configured one
  • MAX code: the confirmation code sent by MAX after the first step

The first screen after pairing is the chat list.

APK Update Catalog

Create a release package:

.\scripts\package-android-release.ps1 -Version 0.1.4 -VersionCode 5

The compose file mounts deploy/releases as /data/releases, so files generated by the packaging script are served automatically after docker compose up -d. The server exposes:

GET /api/app-updates/android/latest
GET /api/app-updates/android/download/{fileName}

Use one stable release key for production APKs. Do not install a new APK signed by a different key over an already installed QMAX app.

Push Notifications

The server has an FCM HTTP v1 dispatcher. To enable real push delivery on the Raspberry Pi, put a Firebase service account JSON under deploy/secrets/ and set:

QMAX_FIREBASE_PROJECT_ID=qmax-29df6
QMAX_FIREBASE_SERVICE_ACCOUNT_PATH=/run/secrets/qmax/firebase-service-account.json

The Android app registers its FCM token after pairing. It uses the Google Services Gradle plugin with android/app/google-services.json for the package xyz.kusoft.qmax. FirebaseBootstrap still supports asset-based firebase.android.json or google-services.json as a fallback for custom local builds.

Argus Publication

QMAX is published in Argus with:

  • base URL: https://argus.kusoft.xyz
  • slug: qmax
  • platform: android
  • channel: stable

Manifest:

https://argus.kusoft.xyz/api/apps/qmax/manifest?platform=android&channel=stable

Latest APK:

https://argus.kusoft.xyz/api/apps/qmax/download/latest?platform=android&channel=stable

The Android app checks this manifest, compares semantic versions, downloads the APK to a temporary file, verifies SHA-256, and only then opens Android's package installer.

Implemented MAX Mapping

The worker code maps:

  • chat list and message history through PyMax;
  • text sending through PyMax;
  • attachment upload through PyMax file/photo/video models;
  • image, video, file and voice attachment projection through the API;
  • Android image attachment caching with .part downloads before a file is shown from local storage;
  • explicit per-user session status and phone-code re-login from Android settings.

An end-to-end login against the live MAX service was not run in this workspace; it must be verified on the target Raspberry Pi with real accounts.