A self-hosted “operating system for your life” across Health, Finance, Faith, and Habits — built as a portable Go API with offline-first mobile sync, a spec-first typed client pipeline, and a security-conscious CLI.
LifeOS organizes personal life domains — Health, Finance, Faith, Habits & Fasting — on top of a small set of shared primitives: Notes, Tasks, People, and Places. It runs as a self-hosted system you own end-to-end: your data lives in your Postgres, your storage bucket, and (on mobile) an encrypted on-device database.
The foundation is complete: authentication, multi-tenant workspaces, CRUD for the core primitives, an offline mobile mirror, and a change-feed sync protocol. The life-domain features build on top of that kernel.
The API’s OpenAPI 3.1 spec is generated from the Go types themselves (via Huma), and the TypeScript client is generated from that spec. One source of truth per endpoint — the Go struct — consumed by web, mobile, and CLI. No hand-written, drift-prone client code.
Mobile keeps a full local SQLite mirror and reconciles through a custom last-write-wins protocol: every mutation appends a sync_log row in the same transaction, and clients drain changes past a cursor (push-then-pull). Conflicts resolve on a version column, ties broken by updated_at.
Plain Go on chi + Postgres with storage hidden behind an interface. The same Docker image runs locally, on a VM, or on Railway — and the abstraction leaves a Cloudflare Workers path open without rewrites.
The CLI stores credentials across three pluggable backends (OS keyring → encrypted file → env), the encrypted-file backend using AES-256-GCM + Argon2id, with token redaction in logs and a written threat model. The production image is distroless, non-root, ~2 MB.
Deliberate choices throughout — e.g. CI intentionally does not enable a remote build cache, keeping build data off third-party infrastructure.
A pnpm-workspace monorepo with a Go backend and TypeScript/Go clients:
packages/ api/ Go HTTP API — the system of record. chi (router) · Huma v2 (OpenAPI 3.1 from code) · pgx (Postgres) · goose (embedded SQL migrations) · chi-go-auth (sessions/auth). cli/ Go CLI (lifeos) — Cobra-based, multi-profile, secure credentials. client/ TypeScript HTTP client — types generated from the OpenAPI spec. shared/ TypeScript kernel — Zod schemas, ULID/ISO helpers, the sync protocol + reconciler, AES-GCM crypto, the SQLite schema. web/ Next.js 15 web app. mobile/ Expo SDK 52 Android app — encrypted on-device SQLite mirror.
Request / data flow: clients call the Go API → Huma validates against the generated schema → handlers read/write Postgres via pgx → every mutation writes a sync_log entry → mobile pulls those entries into its local SQLite mirror and reconciles.
| Area | Choice | Notes |
|---|---|---|
| API | Go 1.26 · chi · Huma v2 | OpenAPI 3.1 generated from code; listens on :8787. |
| Database | Postgres 16+ | Workspace-scoped, multi-tenant. |
| Migrations | goose (embedded SQL) | Applied idempotently at boot; standalone migrate binary for pre-deploy. |
| Auth | chi-go-auth | Email/password; session cookies (web), bearer tokens (mobile); sign-up gated by an owner allowlist. |
| IDs | ULID, client-side | Sortable, collision-resistant, offline-friendly. |
| Web | Next.js 15 · React 18 · Tailwind 4 | — |
| Mobile | Expo SDK 52 · RN 0.76 | op-sqlite (SQLCipher) local mirror, encrypted at rest. |
| Sync | Custom last-write-wins | Cursor-based change feed on a kernel-row contract. |
| Object storage | S3-compatible | MinIO locally; Railway Buckets / R2 / S3 in prod, behind one interface. |
| CLI | Go · Cobra | Keyring / encrypted-file / env credentials; table/json/yaml/ndjson output. |
| Deploy | Railway · Docker → distroless | Same Dockerfiles run on a plain VM. |
Every persisted table composes the same kernel columns — id, created_at, updated_at, deleted_at, version — so sync, soft-delete, and optimistic concurrency work uniformly across every entity instead of being re-implemented per table.
All monetary values are stored as amount_minor INTEGER + currency_code TEXT. Timestamps are UTC ISO 8601 on the wire, timestamptz in Postgres, TEXT in SQLite — one consistent representation across two databases.
Records set deleted_at rather than issuing DELETE, so the change feed can propagate deletions to offline clients and history is never silently lost.
A dedicated openapi-export binary derives the spec from the same Go types the handlers use — it runs in milliseconds with zero runtime dependencies (no database needed), keeping codegen decoupled from a running server.
The CLI’s threat model is documented, tokens are redacted from logs (last 6 chars only), secrets never touch the TOML config file, and the build pipeline runs govulncheck and cross-compiles release binaries with goreleaser.
Go API rebuild, auth + multi-tenant workspaces, Notes/Tasks/People/Places CRUD, the sync change feed, the offline mobile mirror, the CLI, and the spec→client codegen pipeline.
The life-domain feature layers — Health, Finance, Faith, Habits & Fasting — built on the existing kernel and sync engine.