Commit Graph

12 Commits

Author SHA1 Message Date
jacobh2 6e5981d62a Pi: minimal self-contained compose project (D-125)
The Kvitt Pi runs Kvitt from /home/jacobhagstedt/kvitt: compose.yaml, .env,
secrets/ and relative bind mounts ./data, ./backups, ./import. Both containers
run as the owner's uid/gid (KVITT_UID, KVITT_GID). No install script, no /opt,
no Docker daemon or system changes; operations are plain docker compose
commands (README "Pi: what the owner does", RESTORE.md).

Removed install.sh, deploy.sh, bootstrap.sh, backup-now.sh, install-apk.sh,
lib.sh. .env holds only the keys compose.yaml reads; RCLONE_REMOTE is fixed
to gdrive: in compose.yaml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-20 19:18:53 +02:00
jacobh2 200c99f2f6 Pi bundle: drop the informational .env keys
KVITT_PI_HOST and KVITT_PI_SSH_USER were read by nothing on the Pi (D-103).
They are gone from .env.example; the README's scp, ssh and NPM steps use
<user>@<kvitt-pi-address> and the Kvitt Pi's LAN IPv4 address in words.
install.sh checks only the keys the stack reads, so an older .env that still
has the two keys installs unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-20 19:07:20 +02:00
jacobh2 3820f9c3c3 Gitea workflow: sparse checkout, diagnostic step removed
Build Kvitt images / build (push) Successful in 6m7s
Checkout is a cone-mode sparse checkout of server and infra/backup (the
two build contexts), which makes actions/checkout fetch with
--filter=blob:none. fetch-depth stays 0: with depth 1, fetch-tags only
auto-follows tags on the fetched commit, and the version step needs
every v1.0.* tag. The temporary secrets diagnostic step is gone and the
header names kvitt_cicd as the owner's user-level secret.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-19 20:37:42 +02:00
jacobh2 4852803cdb Pi bundle: Kvitt on port 443 through NPM (D-124)
Build Kvitt images / build (push) Successful in 2h51m36s
KVITT_PUBLIC_URL=https://${KVITT_PUBLIC_HOST} with no port; the health check
through NPM prints the port-less URL; publish-apk.sh's summary drops :8443.
README: no new router rule (the existing external 443 forward to the Home
Assistant Pi serves Kvitt, NPM selects by name), NPM listens on 443, the
fallback, operations and APK-abuse notes, and every :8443 URL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-19 20:23:18 +02:00
jacobh2 4b1ae0c473 publish-apk.sh: build for KVITT_PUBLIC_HOST from infra/pi/.env (D-121)
Reads KVITT_PUBLIC_HOST from infra/pi/.env without sourcing it, refuses a missing file or key, a CHANGE_ME value,
anything that is not a host name, and icehack.asuscomm.com (the checks of infra/pi/install.sh), passes it to
:app:assembleRelease as -Pkvitt.publicHost and prints the release server in the header and summary. README
publish paragraph updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-19 20:09:31 +02:00
jacobh2 9231a1d755 infra README: owner decisions list after the M-1 answer (SPEC v0.20)
Build Kvitt images / build (push) Failing after 49s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-19 19:51:10 +02:00
jacobh2 62f5279daa infra README: Nginx Proxy Manager proxy host, router to NPM, NPM fallback (D-120)
Owner checklist without the SSH add-on step: KVITT_PUBLIC_HOST placeholder, NPM's Details, SSL and
Advanced tab fields, the Custom Nginx Configuration block (security headers of D-117 at server level, its
own location / so NPM's X-Served-By does not drop them, /i/ kept out of NPM's access and error logs), what
NPM logs, the HSTS caveat, the router rule external 8443 to the Home Assistant Pi's 443, the NPM-down
fallback (no LAN path for release builds), operations and troubleshooting. RESTORE checks port 8080.
Rehearsal of 2026-10-19 recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-19 19:50:28 +02:00
jacobh2 3ef2c15764 SPEC v0.19: D-118 Android overhaul (shared test fixtures, :core:design limits and failures); HANDOFF, prompts, hash remap in plans
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 23:21:59 +02:00
jacobh2 7fb86f5524 Infra security fixes: Caddy log redaction, headers and non-root container; dev mounts only the FCM key; deploy records image digests (D-117)
- Caddyfile: access and error logs replace the /i/<code> segment and every query string with REDACTED
  (regexp filter on request>uri); Authorization stays redacted by default. Deferred response headers:
  Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-Policy.
- Pi compose: caddy as uid 10002 with group 1000, read-only root, cap_drop ALL plus NET_BIND_SERVICE
  (needed to exec the image's file-capability binary), tmpfs /config and /tmp; install.sh sets /certs
  0750 1000:1000 and Caddy's /data to 10002.
- deploy.sh and install.sh print the pulled image digests and append them to /opt/kvitt/deployed-digests,
  warning when a recorded tag changed digest; the workflow prints the pushed digests; kvitt_cicd needs
  only write:package.
- Dev stack: up.sh stages only fcm-service-account.json into infra/dev/secrets/ (git-ignored), mounted
  read-only at /secrets.
- README: restricted cert-sync key required (plain root key not acceptable), remote_ip and log checks,
  APK download note, owner decisions (backup encryption, APK limit, key form, token scope), overhaul lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 22:24:32 +02:00
jacobh2 8660b7fa16 Server gap pass: invite-partner subcommand, CLI and drain tests, push info log (D-113, D-114)
- kvitt-server invite-partner: a partner invite by the admin as E-12 does (cancels the pending one, 72 h, link with
  ?from=<admin>), exit 2 household full, 3 no admin; README lines in server/ and infra/.
- Tests: invite-partner, migrate (schema at SCHEMA_VERSION, idempotent), healthcheck (200, 503, nothing listening),
  serve SIGTERM drain (in-flight request finishes, new connections refused, exit 0; gives up after SHUTDOWN_DRAIN).
- Push sender: one info line "push sent" per message with push_type, devices_sent, devices_targeted and 8-character
  device-id tails (SPEC §8.7 aggregates); per-device line stays at debug.
- tools/contracts-check.py: stale TODO(spec) replaced by the §9.11 CS-5 citation; shapes updated for invite_kind
  (D-086), app_version_name (D-090) and fid (D-096), 134 checks pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 22:12:28 +02:00
jacobh2 2476667510 M2c-pi: Pi bundle (infra/pi), cert-sync, Drive backup upload, Gitea workflow
The owner copies infra/pi/ to the Kvitt Pi and runs it there (D-100); nothing
on the Mac connects to the Pis. compose stack of SPEC §10.2 with images
${KVITT_REGISTRY}/kvitt-{server,cert-sync,backup}, Caddyfile §10.5.2 verbatim,
.env.example with the OQ-3 values as CHANGE_ME placeholders, install.sh,
deploy.sh (backup before every deploy), bootstrap.sh, backup-now.sh,
install-apk.sh. cert-sync image and sync.sh (§10.5.1, tar stream for both
authorized_keys variants); backup.sh uploads with rclone copy --immutable and
deletes local files once both are confirmed on Drive (D-002); both sidecars
schedule with supercronic because busybox crond runs no jobs as non-root;
backup runs as uid 10001. .gitea/workflows/build-images.yaml from the owner's
example (not yet run); infra/build-images.sh and infra/publish-apk.sh (R8
mapping kept, version per §10.6) on the Mac; README checklist and RESTORE.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 21:48:35 +02:00
jacobh2 c885aba313 M2c-dev: development compose stack, backup job, Firebase setup docs
infra/dev: compose stack on the Mac (server kvitt-server:dev, on-demand backup),
.env.example, build/up/logs/backup/copy-google-services scripts. No Caddy, no TLS
(debug builds accept http to private LAN addresses, AC-2.8). Bind-mounted data.
infra/backup: alpine 3.24.2 image and backup.sh (SPEC 10.9; Drive upload skipped
when RCLONE_FOLDER_ID is empty). infra/README.md for the dev stack and Firebase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 21:18:36 +02:00