2026-07-06 14:40:25 +03:00
2026-07-06 13:37:07 +03:00
2026-07-03 22:39:48 +03:00
2026-07-03 22:39:48 +03:00
2026-07-04 15:56:39 +03:00
2026-07-03 22:39:48 +03:00
2026-07-03 22:39:48 +03:00
2026-07-03 22:39:48 +03:00
2026-07-03 22:39:48 +03:00
2026-07-03 22:39:48 +03:00
2026-07-03 22:39:48 +03:00
2026-07-03 22:39:48 +03:00
2026-07-03 22:39:48 +03:00
2026-07-03 22:39:48 +03:00
2026-07-03 22:39:48 +03:00

QMAX

QMAX is a private Android messenger client backed by a personal bridge server. The Android app talks to your QMAX server, and the server keeps a browser session for https://web.max.ru.

Current shape:

  • server/QMax.Api - ASP.NET Core API, SQLite cache, JWT pairing auth, SignalR hub, attachment storage, APK update catalog.
  • worker - Node/Playwright worker with a persistent MAX Web browser profile.
  • 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
cd android
.\gradlew.bat :app:assembleDebug :app:assembleRelease --console=plain --no-daemon
cd ..\worker
npm.cmd install
node --check src/server.js

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 - one-time-ish pairing password for your Android client and /admin/max.
  • QMAX_MAX_PHONE_NUMBER - the phone number used for MAX Web login.

Secrets must stay in .env, not in git.

MAX Login

Open:

https://qmax.kusoft.xyz/admin/max?pairingCode=YOUR_PAIRING_CODE

Use Start phone login. If MAX shows a robot check, solve it manually on this page using the screenshot plus click/type forms. When MAX sends the confirmation code, submit it on the same page or from the Android app MAX panel.

The worker stores browser state in the qmax-max-profile Docker volume, so the MAX session should survive restarts.

Android Pairing

Build or install:

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

On first launch:

  • Server: https://qmax.kusoft.xyz
  • Code: QMAX_PAIRING_CODE from .env

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.

Current MAX Mapping Status

The deployed worker is authorized in MAX Web and currently maps:

  • chat list extraction from the left MAX Web dialog list;
  • visible chat history extraction when Android opens a dialog;
  • text sending through the MAX Web composer;
  • attachment upload through the MAX Web file chooser;
  • image, video, file and voice attachment projection from MAX Web;
  • Android image attachment caching with .part downloads before a file is shown from local storage;
  • manual browser inspection endpoints for future selector changes.

The bridge uses DOM selectors in worker/src/server.js, so MAX Web UI changes may require a worker redeploy without changing the Android app contract.

S
Description
No description provided
Readme 186 MiB
Languages
C# 51.1%
Kotlin 42.9%
Python 5.3%
PowerShell 0.6%