Personal home OS web app. Rust (axum) backend + Angular frontend, own MariaDB.
Nextcloud is used only for identity (login) and calendar (CalDAV) — see
docs/design/overview.md.
CI (.github/workflows/build.yml) gates on clippy + cargo test, then builds
and pushes the single image xinutec/life:latest to Docker Hub (backend
binary + built Angular bundle + scenes, all served from one process). The
Kubernetes manifests live in the home monorepo (xinutec/pippijn →
code/kubes/life/k8s/); the image tag is the only contract between this repo
and the running deployment.
There is no image automation (no Flux/Argo image controller): the Deployment
pins xinutec/life:latest, a fixed string, so pushing a new :latest changes
nothing on the cluster by itself. Once CI is green, roll it out by hand on isis —
the restart is what pulls the fresh image (:latest ⇒ imagePullPolicy: Always):
ssh root@isis.xinutec.org \
"kubectl -n life rollout restart deploy/life-app && \
kubectl -n life rollout status deploy/life-app --timeout=180s"Manifest changes (yaml edits) additionally need a kubectl apply of
code/kubes/life/k8s/ from a monorepo checkout on the host.
A native-feeling phone wrapper — a full-screen WebView onto this site, no browser
chrome. Build & install steps: android/README.md.
nix develop # Rust toolchain + sqlx-cli
./scripts/dev-db.sh # local MariaDB on 127.0.0.1:3307 (data in .dev/, gitignored)
cp .env.example .env # then fill values; DATABASE_URL points at the dev DB
cargo run # boots, migrates, serves on $BIND_ADDRA commit must be healthy: scripts/verify.sh is the single gate (backend fmt +
clippy + generated-types drift; frontend lint + build + unit tests + ui-check;
shared dev-lint rules). It runs as a pre-commit hook — there is no separate
pre-push step. Slow by design; we optimise for healthy commits, not speed.
scripts/setup-hooks.sh # activate, once per clone (sets core.hooksPath)
git commit --no-verify # bypass for a genuine WIP commitcargo test runs offline. The DB integration test (tests/db.rs) runs only
when LIFE_TEST_DATABASE_URL is set, e.g.:
LIFE_TEST_DATABASE_URL=mysql://life:life@127.0.0.1:3307/life cargo testAngular 22 (Material 3) in frontend/. One origin: dev proxies to the backend,
prod is served by the backend.
cd frontend && npm install
npm start # ng serve on :4200, proxies /api,/login,... to :8080
npm run build # → frontend/dist/life-web/browserServe the built bundle from the backend by pointing STATIC_DIR at it:
STATIC_DIR=frontend/dist/life-web/browser cargo run| Var | Meaning |
|---|---|
DATABASE_URL |
mysql://life:<pw>@<host>/life |
SESSION_SECRET |
random string; HMAC key for session cookies |
NC_BASE_URL |
Nextcloud base URL, no trailing slash |
NC_CLIENT_ID |
OAuth2 client id (registered in NC admin) |
NC_CLIENT_SECRET |
OAuth2 client secret |
NC_REDIRECT_URI |
must match the OAuth2 client's redirect URI |
BIND_ADDR |
optional, default 0.0.0.0:8080 |
See .env.example. The two NC client values come from Settings → Security →
OAuth 2.0 in Nextcloud admin; the redirect URI must be
<app-origin>/auth/callback.
GET /login→ redirect to NC for sign-in (identity only)GET /auth/callback→ completes login, sets session cookiePOST /logoutGET /api/me→{ userId, displayName, nextcloud }POST /api/nextcloud/connect/init→ start CalDAV app-password linkGET /api/nextcloud/connect/status→active | needs_reauth | not_linkedGET /healthz
Migrations in migrations/ run automatically at boot.