- 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.
115 lines
3.6 KiB
Markdown
115 lines
3.6 KiB
Markdown
# 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):
|
|
```bash
|
|
keytool -genkeypair -v -keystore ~/pedscribe-release.jks \
|
|
-keyalg RSA -keysize 2048 -validity 10000 -alias pedscribe
|
|
```
|
|
Store the password somewhere safe — losing it means rotating signing keys.
|
|
|
|
- **Android Studio path** (required when you want to open the IDE):
|
|
```bash
|
|
export CAPACITOR_ANDROID_STUDIO_PATH="/snap/android-studio/209/bin/studio.sh"
|
|
```
|
|
Put it in your `~/.bashrc` if you want it permanent.
|
|
|
|
## Release build — PedScribe
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
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:
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
adb install -r android/app/build/outputs/apk/release/app-release.apk
|
|
```
|
|
|
|
`-r` preserves app data (saved server URL, cached sessions).
|
|
|
|
## Troubleshooting
|
|
|
|
- **`npx cap` can't find the project** — you must `cd 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"` in `AndroidManifest.xml`.
|