From f6397ae635953bb97bcbb7b380572a20c1fa64da Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 14 Apr 2026 23:54:32 +0200 Subject: [PATCH] docs: strip PedsHub Quiz refs from mobile-build + terser CONTRIBUTING mobile-build.md: - Removed "PedsHub Quiz" sections. That app lives in a separate repo (quiz/mobile/) and has its own build pipeline. Docs here are PedScribe-only now. - Reorganized around CI as the primary flow, local build as fallback. Added explicit secret names, JDK requirement, single- quote-password caveat, QEMU/argon2 note. - File-map section at the end so the native sources are discoverable without grepping. CONTRIBUTING.md: - Cut the narrative prose. Dev-facing tables + single-line commands only. Decision-tree removed (the table suffices). - Release pipeline and mobile build link out rather than duplicating content. --- CONTRIBUTING.md | 94 ++++++++++-------------- docs/mobile-build.md | 168 +++++++++++++++++++++---------------------- 2 files changed, 120 insertions(+), 142 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 412aa88..ee30507 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,68 +1,52 @@ -# Contributing / Release workflow +# Contributing -## Commit message format +## Commit format -This repo uses [Conventional Commits](https://www.conventionalcommits.org/). -The `.github/workflows/auto-version.yml` workflow reads your commit -messages and decides whether to cut a release automatically. +[Conventional Commits](https://www.conventionalcommits.org). `.github/workflows/auto-version.yml` +parses messages since the last semver tag and decides whether to bump. -### Cheat sheet - -| Prefix | Release type | Example | +| Prefix | Bump | | |---|---|---| -| `fix:` | patch (6.1.1 → 6.1.2) | `fix: correct age parser off-by-one for "4y 11m"` | -| `feat:` | minor (6.1.1 → 6.2.0) | `feat: add vitals quick-copy button` | -| `feat!:` (or `BREAKING CHANGE:` in body) | major (6.1.1 → 7.0.0) | `feat!: require re-login after argon2 migration` | -| `docs:` | no release | `docs: update mobile build guide` | -| `refactor:` | no release | `refactor: split audit queue into its own module` | -| `chore:` | no release | `chore: bump eslint dep` | -| `test:` | no release | `test: add encounter version-lock test` | -| `style:` | no release | `style: prettier pass on calculators.js` | -| `ci:` | no release | `ci: cache node_modules in Actions` | -| `build:` | no release | `build: add DATA_ENCRYPTION_KEY to .env.example` | +| `fix:` | patch | bug fix | +| `feat:` | minor | new feature | +| `feat!:` / `fix!:` / `BREAKING CHANGE:` in body | major | breaking change | +| `docs:` `refactor:` `chore:` `test:` `style:` `ci:` `build:` | none | no release | -**Only `fix:`, `feat:`, and `!:` / `BREAKING CHANGE` trigger a version bump and a release.** -Everything else is committed and pushed but doesn't tag. +Append `[skip ci]` to suppress the run for that commit. -### Decision tree +## Manual release -Ask yourself: - -1. **Did behavior change for the user?** - - No → `docs:`, `refactor:`, `chore:`, `test:`, `style:`, `ci:` (no release) -2. **Yes. Is it a bug fix?** - - Yes → `fix:` (patch) -3. **New feature or enhancement?** - - Yes → `feat:` (minor) -4. **Does it break existing behavior** (users have to log out, re-configure, migrate data, etc.)? - - Yes → `feat!:` or `fix!:` (major) - -### Skip the workflow entirely - -Append `[skip ci]` anywhere in the commit message to suppress the -auto-version run for that commit (e.g., for emergency one-off fixes -you want to batch under a later release). - -## Manual release (emergency override) - -From the Actions tab → **Version bump & release** → Run workflow → -pick patch / minor / major (or type exact version) → Run. Skips -commit-message parsing and bumps exactly as requested. - -Or locally: ```bash -scripts/release.sh 6.1.2 --push +scripts/release.sh 6.2.0 --push # local ``` -## After a release is cut +or Actions tab → **Version bump & release** → Run workflow → pick bump type. -The tag push (whether from auto-version, manual dispatch, or local -script) fires two parallel workflows: +## What a tag push triggers -| Workflow | Output | Time | -|---|---|---| -| `android-release.yml` | signed `pedscribe-X.Y.Z.apk` on the GitHub release | ~8 min | -| `docker-publish.yml` | `danielonyejesi/pediatric-ai-scribe-v3:X.Y.Z` + `:latest` on Docker Hub | ~4 min | +| Workflow | Output | +|---|---| +| `android-release.yml` | signed APK on GitHub release, `make_latest=true` | +| `docker-publish.yml` | `danielonyejesi/pediatric-ai-scribe-v3:{version,latest}` on Docker Hub (amd64) | -Obtanium users, Docker Hub subscribers, and the login page's -"Download APK" link all update without further action. +## Local dev + +```bash +docker compose up -d # Postgres + app +docker logs -f pediatric-ai-scribe +``` + +Web changes hot-reload via browser refresh (JS/CSS cached 1h — add `?v=` query +or clear cache; the build-ID server-side cache-buster appends `?v=` +automatically on fresh page loads). + +Server code changes require `docker compose build pediatric-scribe && docker compose up -d`. + +## Mobile + +See `docs/mobile-build.md`. + +## DB migrations + +`src/db/database.js` is the baseline (idempotent CREATE-IF-NOT-EXISTS). New +changes go in `migrations/` via `node-pg-migrate`. See `docs/migrations.md`. diff --git a/docs/mobile-build.md b/docs/mobile-build.md index f122fd2..710c1ec 100644 --- a/docs/mobile-build.md +++ b/docs/mobile-build.md @@ -1,115 +1,109 @@ -# Mobile App Build & Release +# Mobile build & release -Capacitor wrappers for **PedScribe** (this repo) and **PedsHub Quiz** -(`/home/danvics/docker/quiz`). Both ship as Android APKs and iOS builds. +Capacitor 6 wrapper. Android only today; iOS project exists but requires macOS ++ Xcode to produce an `.ipa`. ## 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 +### Keystore ```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 +keytool -genkeypair -v -keystore ~/pedscribe-release.jks \ + -keyalg RSA -keysize 2048 -validity 10000 -alias pedscribe ``` -## Release build — PedsHub Quiz +Store the password in a password manager. Back up the `.jks` file off the +machine. Losing it = can't sign updates; Play Store requires signature +continuity (unless you're on Play App Signing). + +### Android Studio (optional, IDE workflow only) ```bash -cd /home/danvics/docker/quiz/mobile +export CAPACITOR_ANDROID_STUDIO_PATH="/snap/android-studio/current/bin/studio.sh" +npx cap open android +``` + +## CI build (preferred) + +Tag-triggered. Push any `vX.Y.Z` tag → `.github/workflows/android-release.yml` +builds a signed APK on a GitHub runner and attaches it to the matching release. + +Required repo secrets (set once, via Settings → Secrets and variables → Actions +or `gh secret set`): + +- `ANDROID_KEYSTORE_BASE64` — `base64 -w0 ~/pedscribe-release.jks` +- `ANDROID_KEYSTORE_PASSWORD` +- `ANDROID_KEY_ALIAS` — `pedscribe` +- `ANDROID_KEY_PASSWORD` + +Tag a release: + +```bash +# conventional-commits prefix auto-tags (see CONTRIBUTING.md) +git commit -m "feat: ..." && git push # auto-version workflow bumps minor +git commit -m "fix: ..." && git push # auto-version workflow bumps patch + +# or force an exact version +scripts/release.sh 6.2.0 --push +``` + +APK lands at the GitHub release; `/releases/latest` link in the login page +resolves to it automatically. Obtanium subscribers (`github.com//`) +pick up the update on next poll. + +## Local build (fallback / debugging) + +```bash +cd 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.store.password='' \ -Pandroid.injected.signing.key.alias=pedscribe \ - -Pandroid.injected.signing.key.password=YOUR_KEY_PASSWORD + -Pandroid.injected.signing.key.password='' ``` -## Publish APK on GitHub Releases +Output: `android/app/build/outputs/apk/release/app-release.apk` +For Play Store, swap `assembleRelease` → `bundleRelease`; output: `.aab` under +`bundle/release/`. -The login page links to `github.com///releases/latest` (see -`public/index.html` around line 114). Publishing a tagged release updates the -download link automatically — no site redeploy needed. +### Single-quote the password -```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." -``` +Keystore passwords with shell metacharacters (`)`, `$`, `!`, space, etc.) must +be single-quoted. Backslash line continuations get eaten by some terminal +paste handlers — prefer one-line commands. -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 +## Reinstall on device ```bash adb install -r android/app/build/outputs/apk/release/app-release.apk ``` -`-r` preserves app data (saved server URL, cached sessions). +`-r` keeps app data (saved server URL, auth token in Keystore, IndexedDB). -## Troubleshooting +## Gotchas -- **`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`. +- **JDK 17 only.** Newer JDK (21/25) breaks Android Gradle Plugin. Set + `org.gradle.java.home=/usr/lib/jvm/java-17-openjdk-amd64` in `~/.gradle/gradle.properties` + if the system default is different. +- **QEMU multi-arch Docker builds fail** with SIGILL on native modules (argon2). + Docker Hub workflow is x86-only. Use a native ARM runner if you need ARM64. +- **`npx cap` must run inside `mobile/`**, not repo root. +- **Foreground recording on Android 14+** requires `foregroundServiceType="microphone"` + in `AndroidManifest.xml` plus the 3-arg `startForeground(id, notif, TYPE_MICROPHONE)`. + Already applied. +- **Mic "denied" after permission grant** — WebView intercepts the prompt. + Fix: long-press app icon → App info → Permissions → Microphone → Allow. + +## Files + +| Path | Purpose | +|---|---| +| `mobile/capacitor.config.json` | app ID, name, WebView config, plugin opts | +| `mobile/src/` | launcher HTML (server URL entry) | +| `mobile/android/app/src/main/java/com/pedshub/scribe/MainActivity.java` | JS bridge + WebView mic permission | +| `mobile/android/app/src/main/java/com/pedshub/scribe/AudioRecordingService.java` | foreground service for background recording | +| `mobile/android/app/src/main/AndroidManifest.xml` | permissions, intents, backup rules | +| `.github/workflows/android-release.yml` | CI build |