Development
The repository is a monorepo of separate builds, not one build graph. Build and test the component you change, plus any component on the other side of a boundary you touched.
Layout
Section titled “Layout”| Path | Stack | Purpose |
|---|---|---|
server/ |
Rust, Axum, SQLx, SQLite | Homeserver: identity, guild and media roles, federation |
web/ |
React 19, Vite, Kumo, Tailwind | Shared client and browser build |
web/electron/ |
Electron, Node | Desktop shell, native bridges, Rich Presence |
web/src-tauri/ |
Rust, Tauri 2 | Android shell |
sfu/ |
Rust, LiveKit | SFU front end and control plane (own Cargo workspace) |
telium-protocol/ |
Rust library | Signing and protocol primitives shared by server and SFU |
sdk/bot/ |
JavaScript | Bot SDK |
site/ |
Astro | Public website and server registry |
Toolchains: Rust 1.85+ for the server, Bun for the web client and site.
Homeserver
Section titled “Homeserver”cd servercargo run -- init # writes telium.tomlcargo run -- servecargo testMigrations live in server/migrations/. Never reuse a migration number that has landed. A migration makes the release impossible to roll back past (see Upgrades).
Wire-format changes (server-to-server requests, gateway frames, bundles, signed documents) follow Compatibility: adding a field is fine, removing or retyping one is not.
server/telium.example.toml is the annotated config reference. Document any new operator option there.
Web client
Section titled “Web client”cd webbun installbun run dev # http://localhost:5173bun run test # Vitestbun run buildThe dev server proxies Telium paths to TELIUM_ORIGIN (default http://localhost:8448). Set it to reach another homeserver instead of hard-coding a URL.
Tests in web/src/test/ run against a fake protocol server (fake-server.js) and fake WebRTC. For security-sensitive input handling, add focused unit tests at the validation boundary as well.
Desktop
Section titled “Desktop”cd webbun run desktop:installbun run desktop:devbun run desktop:build:linux # AppImagebun run desktop:build:windows # NSIS installerDesktop is Electron. Tauri is used only for Android.
Keep the renderer locked down (contextIsolation, sandbox, webSecurity on). If a standard browser API is enough, keep the feature in shared code. If native help is needed, expose the narrowest preload method and validate its input in the main process. A feature that works under Vite may still fail in the packaged AppImage, so test packaged builds for anything that depends on packaging. See web/electron/README.md.
Android
Section titled “Android”./build-android.sh # debug APKTELIUM_ANDROID_BUILD_TYPE=release ./build-android.sh # release, unsignedRequirements and options are on Clients. Release signing uses a key kept off workstations. To exercise signing locally, make a throwaway key with scripts/create-android-keystore.sh and sign with apksigner.
Treat Android WebView as its own runtime. Keyboard insets, resume, Back, audio focus and native permissions do not behave like a desktop browser.
SFU and protocol crate
Section titled “SFU and protocol crate”cd sfu && cargo testcd telium-protocol && cargo testChanges to signed token semantics usually need matching changes and tests in telium-protocol and the server, since the shared crate exists to stop byte-level signing drift between them. Add to telium-protocol only what several Rust components must agree on exactly. See sfu/README.md.
cd sitebun installbun run buildbun run validate # server registry validationThe site is static. Do not add trackers, remote fonts or third-party runtime requests.
Releases
Section titled “Releases”Each build has its own tag family:
| Tag | Builds | Publishes |
|---|---|---|
server-v<version> |
Server image and native x86_64/aarch64 tarballs | GitHub release, server-v<version> and server-latest image tags, a deploy/releases.json entry |
desktop-v<version> |
Electron for Linux and Windows | GitHub release with both packages, the signed client manifest, updater metadata |
android-v<version> |
Tauri Android ARM64 | GitHub release, plus the rolling android-latest |
To cut a server release:
scripts/bump-server-version.sh 0.2.0The script edits server/Cargo.toml and Cargo.lock, commits Release server 0.2.0, and prints the tag command. --security, --breaking and --notes "..." add trailers to the annotated tag. After the bump commit is on main:
git tag -a server-v0.2.0 -m "Telium Server 0.2.0"git push origin server-v0.2.0The release workflow refuses a tag whose commit is not on main or whose server/Cargo.toml version disagrees with the tag. Dispatch it with dry_run to test the build without publishing. Signing and publishing details are in Updates and Supply chain.
Conventions by boundary
Section titled “Conventions by boundary”Server and API. Add authorization tests for new or changed routes. For server-to-server routes, cover replay, signature and error behavior.
Federation. Test local and remote cases, and test an unreachable peer and retries, not only two live servers. Keep origin, audience and signature checks intact.
Client state. Decide which kind each piece of state is: server-authoritative, synced preference, device-local preference, local security checkpoint or secret, or disposable cache. Unsent content, provider credentials and machine-local settings do not belong in account sync.
User-visible text. Follow Translating.
Native bridges. Keep browser security on. Validate the calling frame and every URL, path, token, type and size. Do not expose generic fetch, filesystem or shell primitives.
Crypto and identity. Preserve domain separation and canonical encodings. Test rollback, replay and fork cases, not only success.