marcuspaico 125fb7df35 feat(task): undo toast for completing — mis-taps are one tap to take back
completeTask returns an undo closure that restores status + sort slot and
trashes the occurrence a repeat spawned. One global snackbar (5s,
replace-on-new) mounted in the root layout; every checkbox and Clarify's
save-as-done go through completeWithUndo. bun tests for the store.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YE5FmDZmFnWxH6RXCZLcjj
2026-09-02 18:07:43 +10:00

GTD

Minimal Getting Things Done app. One Expo/React Native codebase for iPhone, Android, and web; data lives in Postgres on the VPS.

  • Web: https://gtd.rehbock.xyz (Expo web export, static)
  • API: https://gtd.rehbock.xyz/api → gtd-api container (Bun, server/)
  • DB: gtd database in the personal-db Postgres container (server/schema.sql)
  • Auth: single bearer token (API_TOKEN in server/.env on the VPS); enter it once in the app's Settings

Layout

  • app/ — Expo app (expo-router, TypeScript). Home shows the top 3 next actions plus a launcher menu: Today / Next / Waiting / Someday / Projects / Review. There is no inbox — every task is born fully scoped (title, priority, due date). Tap a task to clarify (list, project, context, waiting-for, due/defer dates, repeat).
    • Quick add: the title field parses tokens live — Pay rent tmr p1 @home #Sydney ~30m monthly — and mirrors them into the form.
    • Repeat: daily / weekdays / weekly / monthly / yearly; completing spawns the next occurrence (lapsed tasks catch up to today).
    • Defer: deferred tasks are hidden from action lists until their date; a footer link reveals them.
    • Weekly review: overdue, stalled (14d), aging waiting-fors (7d), someday sweep, deferred preview, stuck projects — with one-tap triage per row. Done and Trash (restorable) live at the bottom of Review.
  • server/ — Bun API + Dockerfile + compose. Deployed at ~/personal/gtd on rehbock.xyz, joined to personal-db_default + caddy_net.

Develop

cd app && npx expo start        # scan QR with Expo Go (iPhone or Pixel)
  • Node 22 only (app/.nvmrc): CI's npm 10 rejects lockfiles written by newer npm. Never run bare npm install to change deps — use npm run lock (regenerates the lock via a node:22 container), or run npm from node 22.
  • Hook: git config core.hooksPath .githooks enables a pre-push check that validates the lockfile against CI's npm before it can break a build.
  • Local Android builds need JDK 21 (AGP chokes on newer): pinned via org.gradle.java.home in ~/.gradle/gradle.properties → ~/.local/share/java/jdk-21.0.12+8.
  • expo prebuild is safe to re-run: app/plugins/withAndroidRelease.js re-injects the release signing, env-driven versionCode/Name, and gradle.properties tuning into the committed android/.

Release (Android APK → Obtainium)

Every push to main runs .gitea/workflows/release.yml on the desktop runner: fast check job (lockfile/types/lint), then a signed assembleRelease, published as Gitea release v1.<run> with the APK attached. Phones track it with Obtainium → source https://git.rehbock.xyz/marcus/gtd (Forgejo/Gitea source type). CI failures push to ntfy topic gtd-ci when the NTFY_TOKEN repo secret is set.

Deploy

# API
rsync -a server/ --exclude .env.token.local rehbock.xyz:personal/gtd/
ssh rehbock.xyz 'cd ~/personal/gtd; and docker compose up -d --build'

# Web
cd app && npx expo export --platform web
rsync -a --delete dist/ rehbock.xyz:personal/gtd/web/
Description
Minimal GTD app: Expo/RN + Bun API + Postgres
Readme 6.9 MiB
v1.24 Latest
2026-09-08 17:40:42 +10:00
Languages
TypeScript 89.4%
JavaScript 4%
Shell 2.5%
Kotlin 2.2%
HTML 1.1%
Other 0.6%