Development and builds
Folder layout
Section titled “Folder layout”Keep the three repos side by side. pnpm dev:all looks for the server next to the app:
Directoryoutbrief/
Directoryoutbrief-server/ Hono server + MySQL
- …
Directoryoutbrief-app/ Tauri 2 + React 19 client
- …
Directoryoutbrief-daemon/ resident process on each computer
- …
All need Node ≥ 22.18 and pnpm 9. The app also needs Rust stable ≥ 1.85 and the Tauri prerequisites; the server needs Docker.
1. Local database
Section titled “1. Local database”The local database is a MySQL 8 container that must be named some-mysql, publishing port 3306. pnpm dev:all finds it by that name and never creates it.
-
Create the container once.
MYSQL_ROOT_PASSWORDis only for root on this machine:终端窗口 docker run -d --name some-mysql --restart unless-stopped \-e MYSQL_ROOT_PASSWORD='local-root-password' \-p 3306:3306 mysql:8.4until docker exec some-mysql mysqladmin ping -h127.0.0.1 --silent; do sleep 1; done -
In outbrief-server, create the databases and user once. At the password prompt, type the root password above:
终端窗口 docker exec -i some-mysql mysql -uroot -p < db/bootstrap.sqlThis creates
outbriefandoutbrief_testand anoutbriefuser for local use only.
If the container already exists, don’t docker run again. Start a stopped one with docker start some-mysql.
2. Run it
Section titled “2. Run it”In outbrief-app:
pnpm installpnpm dev:allIt brings up the database container, the server next door, and the desktop window. Server logs go to logs/server.log. Quit from the tray or press Ctrl+C to stop them all.
- If the server lives elsewhere, set
OUTBRIEF_SERVER_DIR=<folder>. - The script passes the claim code to the desktop app so it creates the first account. With a local daemon, it joins the daemon’s account instead.
- It closes any desktop app still running before it starts.
# outbrief-serverpnpm db:migrate # create tables (startup does this too)pnpm dev # restarts on change
# outbrief-apppnpm tauri dev # desktop window + hot reload, frontend on :1520pnpm dev # frontend only, in a browser
# outbrief-daemonnode src/cli.ts login --server http://127.0.0.1:8787node src/cli.ts runCommands
Section titled “Commands”In all three repos:
| Command | What it does |
|---|---|
pnpm lint / pnpm format |
Biome check / fix |
pnpm typecheck |
TypeScript type check |
pnpm test |
Vitest. The server tests empty the database at OUTBRIEF_TEST_DATABASE_URL, whose name must end in _test |
The app also has:
| Command | What it does |
|---|---|
pnpm build |
Build the frontend to dist/ |
pnpm tauri build |
Build the desktop installer |
pnpm tauri android init / ios init |
Generate the local Android / iOS project |
scripts/build-android.sh |
Build an installable Android APK |
The schema lives only in the server’s db/migrations/NNN_*.sql. Add a new migration for each change; never edit one that has run.
Android package
Section titled “Android package”scripts/build-android.sh builds a signed arm64 release APK at dist-android/OutBrief.apk that installs directly on a phone.
-
Install the toolchain: rustup (
rustup target add aarch64-linux-android; Homebrew’s rust has no Android target), JDK 17, the Android SDK (platforms;android-36,build-tools) and the NDK, and setANDROID_HOME,NDK_HOME, andJAVA_HOME. -
(For call pushes) In the Firebase console, add an Android app for
ai.outbrief.appand put the downloadedgoogle-services.jsonin~/.outbrief-android/firebase/, or pointOUTBRIEF_FIREBASE_CONFIG=<path>at it. -
Build. The server URL defaults to
https://api.outbriefapp.com; useVITE_OUTBRIEF_SERVER_URLfor your own:终端窗口 VITE_OUTBRIEF_SERVER_URL=https://your-server.example scripts/build-android.sh
The Chinese name is 启奏 (“presenting a memorial to the throne”): a gold-edged memorial book unfolded on vermilion, with its vertical lines drawn as sound waves. The agent reports, by voice.
The source is app-icon.svg in outbrief-app. After editing it, export a 1024×1024 app-icon.png and run pnpm tauri icon app-icon.json to regenerate every size. The Android adaptive icon has two layers, app-icon-android-bg.svg and app-icon-android-fg.svg; update both when the colors or shapes of the main icon change.