Kin: personal relationships app — server (cadence/due/migrations) + Expo Android app
Some checks failed
Build & Release APK / build (push) Failing after 13s
Some checks failed
Build & Release APK / build (push) Failing after 13s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
74
README.md
Normal file
74
README.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Kin — personal relationships app
|
||||
|
||||
A self-hosted "relational wealth" tracker: who matters, when you last talked,
|
||||
and who's due for a catch-up. Monica-style personal CRM, but thin: all data
|
||||
lives in one Postgres database on your own server; the mobile app and web UI
|
||||
are both clients of the same tiny API.
|
||||
|
||||
- **`server/`** — Bun + Hono API and vanilla-JS web UI, deployed as the `crm`
|
||||
container at https://crm.rehbock.xyz (data in the shared `personal-db`
|
||||
Postgres, database `personal`).
|
||||
- **`app/`** — Expo / React Native app ("Kin"), Android APK built by Gitea
|
||||
Actions and installed via Obtainium. iOS builds from the same code.
|
||||
- **`docs/SCOPE.md`** — product scope and architecture decisions.
|
||||
|
||||
## How it works
|
||||
|
||||
Each person can have a **cadence** (contact every N days). The server computes
|
||||
`urgency = days_since_last_contact / cadence` for everyone; the app's home
|
||||
screen sorts by it (overdue → coming up → on track) and schedules a local
|
||||
daily notification ("3 people are due for a catch-up"). Logging an interaction
|
||||
takes two taps and resets the clock. Snooze pushes someone off the list for a
|
||||
week without pretending you talked.
|
||||
|
||||
## Auth
|
||||
|
||||
Two paths into the same API, split by Caddy (`~/personal/proxy/Caddyfile` on
|
||||
the VPS):
|
||||
|
||||
- **Browser** → Caddy `basic_auth` (user `admin`), then proxied to the app.
|
||||
- **Mobile app** → sends `Authorization: Bearer <API_TOKEN>`; Caddy lets
|
||||
Bearer requests through and the server validates the token itself
|
||||
(`API_TOKEN` in `server/.env` on the VPS; local copy in
|
||||
`server/.env.token.local`, gitignored).
|
||||
|
||||
Anything on the Docker networks can hit the API unauthenticated — the port is
|
||||
never published on the host. Don't change that property.
|
||||
|
||||
## Server deploy
|
||||
|
||||
The server lives at `~/personal/crm` on the VPS. Restart is NOT enough — the
|
||||
image bakes the source in:
|
||||
|
||||
```sh
|
||||
rsync -a --delete --exclude .env --exclude .env.token.local --exclude node_modules \
|
||||
server/ rehbock.xyz:personal/crm/
|
||||
ssh rehbock.xyz 'cd ~/personal/crm; and docker compose up -d --build'
|
||||
```
|
||||
|
||||
Migrations in `server/migrations/*.sql` run automatically at container boot
|
||||
(recorded in `schema_migrations`). Add a new numbered file; never edit an
|
||||
applied one.
|
||||
|
||||
## App development
|
||||
|
||||
```sh
|
||||
cd app
|
||||
npm install
|
||||
npx expo start # dev server; press a for Android
|
||||
npx tsc --noEmit # typecheck
|
||||
```
|
||||
|
||||
`app/android/` is committed (CI builds it directly; `expo prebuild` only when
|
||||
native config changes). Release signing: `~/.android-keys/kin-release.jks`
|
||||
(alias `kin`, password in `kin-release.password` next to it), or
|
||||
`KEYSTORE_FILE`/`KEYSTORE_PASSWORD` env in CI.
|
||||
|
||||
## Release pipeline
|
||||
|
||||
Push to `main` → Gitea Actions (`.gitea/workflows/release.yml`) on the
|
||||
**desktop runner** (label `desktop` — never the VPS) → signed APK →
|
||||
Gitea release `v1.<run>` with asset `kin-v1.<run>.apk` → Obtainium picks it up
|
||||
from the repo URL. Repo secrets: `KEYSTORE_B64`, `KEYSTORE_PASSWORD`.
|
||||
Version code/name come from the CI run number; `app.json`'s version is unused
|
||||
on Android.
|
||||
Reference in New Issue
Block a user