Files
kin/docs/SCOPE.md
Marcus Rehbock ac0b82e6a0
Some checks failed
Build & Release APK / build (push) Failing after 13s
Kin: personal relationships app — server (cadence/due/migrations) + Expo Android app
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-09 00:50:06 -07:00

89 lines
4.6 KiB
Markdown

# Kin — scope & architecture
*Written 2026-08-09, at project start.*
## What this is
A personal "relational wealth" app: the single place that answers **who
haven't I talked to in too long?** and makes fixing that a two-tap action.
Inspired by Monica CRM, but deliberately thin — one user, one server, no
accounts, no social features.
## Product principles
1. **The due list is the product.** Contacts, notes, and history exist to
feed one screen: who to reach out to today. Everything else is secondary.
2. **Logging must be cheaper than not logging.** Two taps ("text, today,
done") or the log stays empty and the due list lies. The old web CRM had
44 people and 0 interactions — that's the failure mode to design against.
3. **Cadence over guilt.** Each person gets a cadence (weekly → 6-monthly)
or none at all. No global "you're behind on 30 people" — only people you
*chose* to track surface in reminders. Snooze is honest: it defers,
it doesn't fake contact.
4. **Thin client, durable data.** All state lives in the `personal` Postgres
database on the VPS. The phone caches for instant open and offline
reading; writes go straight to the API.
## Architecture
```
Pixel (Kin app, Expo RN) ──Bearer token──▶ Caddy ──▶ crm container (Bun+Hono) ──▶ personal-db (Postgres)
Browser (web UI) ──basic_auth───▶ ↑ same API, same data
```
- **Server**: the existing `crm` container, extended. Hono + porsager/postgres
on Bun. Now has boot-time SQL migrations (`schema_migrations`), a
`GET /api/due` endpoint, cadence/snooze/archive columns, relationship
create/delete, and Bearer-token auth for non-browser clients.
- **Due math** (server): `urgency = days_since_last_contact / cadence_days`,
anchored on `created_at` for never-contacted people so new adds surface
immediately. `overdue` ≥ 1.0, `due_soon` ≥ 0.75. Sorted by urgency, so a
weekly friend 3 days late outranks a yearly contact 3 days late.
- **App**: Expo SDK 57 + expo-router, structured like the GTD app (read-cache
store on `useSyncExternalStore` + AsyncStorage, refresh on
foreground/focus). Dark warm theme, Pixel 9 XL first.
- **Reminders**: local notifications only, no server push. On every sync the
app reschedules a daily digest for the next 7 days ("N people are due for a
catch-up") at the configured hour. If the app isn't opened for a week, the
notifications run out — which is itself the right nudge. Server-side
push via the existing ntfy container is the v2 escape hatch if this proves
too passive.
## Screens
| Screen | Job |
|---|---|
| **Today** (home) | Due list in sections: Reach out / Coming up / On track / Snoozed. Quick-log button on every row. Empty state doubles as onboarding. |
| **People** | Whole network, client-side search + tag filter (44 people — no server round-trips). |
| **Person** | Contact actions (Message/Call/WhatsApp/Email deep links), cadence picker, log + snooze, notes, relationships, history (long-press to delete). |
| **Log** (modal) | Type chips + today/yesterday + optional note. Two taps minimum. |
| **Add/Edit** (modal) | Name, phone, email, location, tags, notes, cadence. |
| **Settings** (modal) | Server URL, token, reminder hour. Probes the API before saving. |
## Deliberately out of v1
- **Offline write queue** — GTD's op-queue store is proven but heavy; a
relationships app tolerates "log it when you're back online". Revisit if it
annoys in practice.
- **Birthday reminders** — column exists (`people.birthday`), UI doesn't.
- **Relationship editing in-app** — API supports create/delete now; app only
displays. Add when graph curation actually matters.
- **Web UI parity** — the vanilla-JS web UI still works for bulk edits at
crm.rehbock.xyz; it doesn't know about cadence yet.
- **Contact import from the phone** — seed data came from the newsletter
subscriber list; `expo-contacts` import is a v2 candidate.
- **Multi-user / open-source hardening** — single-user by design. The repo is
structured to be open-sourceable (no secrets in git, migrations from
scratch, auth documented), but no login system until someone else needs it.
## Infrastructure facts
- VPS dir: `~/personal/crm` (container `crm`, network `caddy_net` +
`personal-db_default`). DB: `personal` in the shared `personal-db` Postgres.
- Caddy: `crm.rehbock.xyz`; Bearer requests bypass basic_auth (app validates),
everything else challenges.
- CI: Gitea Actions on the desktop runner (label `desktop`), signed APK per
push to main, released as `kin-v1.<run>.apk` for Obtainium.
- Keystore: `~/.android-keys/kin-release.jks`, alias `kin` — distinct from
GTD's so Android treats the apps independently.