- JWT_SECRET fails fast at startup in production
- CORS fails closed if APP_URL + CORS_ORIGINS are both missing
- Explicit HSTS (1y, includeSubDomains, preload)
- Rate limit sensitive auth endpoints (change-password, 2FA)
- /api/health now returns {ok:true}; details gated behind admin auth
- Login enumeration removed — generic 401 + dummy bcrypt on miss
- ReDoS guard: 20KB input cap on /suggest-codes
- showToast uses textContent, no innerHTML
- clearSession() clears service worker caches on logout
- OIDC state is now HMAC-signed and stateless (survives restart)
- SSRF guard on admin-set OIDC issuer (blocks private IPs, requires HTTPS)
Adds docs/mobile-build.md covering APK build, release, git push,
keystore, and troubleshooting for both PedScribe and PedsHub apps.
3.6 KiB
Mobile App Build & Release
Capacitor wrappers for PedScribe (this repo) and PedsHub Quiz
(/home/danvics/docker/quiz). Both ship as Android APKs and iOS builds.
One-time setup
-
Keystore (reused for both apps):
keytool -genkeypair -v -keystore ~/pedscribe-release.jks \ -keyalg RSA -keysize 2048 -validity 10000 -alias pedscribeStore the password somewhere safe — losing it means rotating signing keys.
-
Android Studio path (required when you want to open the IDE):
export CAPACITOR_ANDROID_STUDIO_PATH="/snap/android-studio/209/bin/studio.sh"Put it in your
~/.bashrcif you want it permanent.
Release build — PedScribe
cd /home/danvics/docker/ped-ai/mobile
npm install # picks up any new plugins
npx cap sync android # copies web assets + plugin glue
cd android
./gradlew assembleRelease \
-Pandroid.injected.signing.store.file=$HOME/pedscribe-release.jks \
-Pandroid.injected.signing.store.password=YOUR_KEYSTORE_PASSWORD \
-Pandroid.injected.signing.key.alias=pedscribe \
-Pandroid.injected.signing.key.password=YOUR_KEY_PASSWORD
# APK lands at: android/app/build/outputs/apk/release/app-release.apk
Release build — PedsHub Quiz
cd /home/danvics/docker/quiz/mobile
npm install
npx cap sync android
cd android
./gradlew assembleRelease \
-Pandroid.injected.signing.store.file=$HOME/pedscribe-release.jks \
-Pandroid.injected.signing.store.password=YOUR_KEYSTORE_PASSWORD \
-Pandroid.injected.signing.key.alias=pedscribe \
-Pandroid.injected.signing.key.password=YOUR_KEY_PASSWORD
Publish APK on GitHub Releases
The login page links to github.com/<owner>/<repo>/releases/latest (see
public/index.html around line 114). Publishing a tagged release updates the
download link automatically — no site redeploy needed.
cd /home/danvics/docker/ped-ai
gh release create v6.0.1 \
mobile/android/app/build/outputs/apk/release/app-release.apk \
--title "PedScribe 6.0.1" \
--notes "Hardware-backed secure storage for auth token on mobile."
For the quiz app:
cd /home/danvics/docker/quiz
gh release create v1.0.0 \
mobile/android/app/build/outputs/apk/release/app-release.apk \
--title "PedsHub 1.0.0" \
--notes "Initial Android release."
Push source changes to git
Standard flow — the mobile project lives alongside the web app:
cd /home/danvics/docker/ped-ai
git add mobile/ public/ src/
git commit -m "Your message"
git push
Same for quiz at /home/danvics/docker/quiz.
iOS
iOS requires macOS + Xcode. On Linux the sync still runs but you cannot build
the .ipa:
cd /home/danvics/docker/ped-ai/mobile
npx cap sync ios
# Then on a Mac: open ios/App/App.xcworkspace and Archive.
Reinstall on device after rebuild
adb install -r android/app/build/outputs/apk/release/app-release.apk
-r preserves app data (saved server URL, cached sessions).
Troubleshooting
npx capcan't find the project — you mustcd mobile/first, not run from the repo root.Keystore was tampered with— wrong password. Do not generate a new keystore unless you are ready to rotate the signing identity on Play Store.- Microphone "denied" in the app — open system settings, long-press the app icon → App info → Permissions → Microphone → Allow. Web-side prompt does not always surface because the native layer intercepts it.
- Foreground recording stops on newer Android — the service must declare
foregroundServiceType="microphone"inAndroidManifest.xml.