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.
This commit is contained in:
parent
6365790e4b
commit
f6397ae635
2 changed files with 120 additions and 142 deletions
|
|
@ -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=<git SHA>`
|
||||
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`.
|
||||
|
|
|
|||
|
|
@ -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/<owner>/<repo>`)
|
||||
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='<pass>' \
|
||||
-Pandroid.injected.signing.key.alias=pedscribe \
|
||||
-Pandroid.injected.signing.key.password=YOUR_KEY_PASSWORD
|
||||
-Pandroid.injected.signing.key.password='<pass>'
|
||||
```
|
||||
|
||||
## 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/<owner>/<repo>/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 |
|
||||
|
|
|
|||
Loading…
Reference in a new issue