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 athttps://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
- Point DNS
qmax.kusoft.xyzto the Raspberry Pi public IP. - Install Docker Engine and the Docker Compose plugin on the Pi.
- Copy the repository or the archive produced by
scripts/deploy-rpi.ps1. - 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_CODEfrom.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
.partdownloads 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.