Files
app-catalog-felhom.eu/REPORT.md
T
admin 5d42ca18bf docs: SparkyFitness (v0.17.2) — CHANGELOG + README rows + REPORT
Live-validated on guest 9201 / controller v0.87.0: synced, deployed via the
real dashboard flow, all 3 containers healthy, /api/health UP through the public
edge. Records §1.3 image-probe findings and the deferred interactive-login item.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 15:06:50 +02:00

6.3 KiB

REPORT — Add SparkyFitness to the app catalog (+ live deploy & health check)

Date: 2026-06-28 Task class: Implementation — pure catalog addition (no Go/controller/agent/hub code change). Outcome: Template added, synced, deployed live on guest 9201, all 3 containers healthy, end-to-end /api path verified through the public edge. One acceptance item (interactive account register/login) was deliberately left for a human — see "NOT validated" below.


1. Confirmed baselines

Repo Baseline After
app-catalog-felhom.eu main @ d7a6a17 (working tree clean; templates/sparkyfitness/ was 404) template commit 4351d08, docs commit (this push)
felhom-controller (running on demo) v0.87.0 (gitea.dooplex.hu/admin/felhom-controller:0.87.0, healthy on guest 9201) unchanged — template proven-compatible against 0.87.0

The running controller renders this template's type: subdomain + data_key fields correctly (deploy screen showed Domain auto-filled, Subdomain sparky, and all 4 auto-secrets) — so no STOP condition; no controller patch was needed.

2. Files created

  • templates/sparkyfitness/docker-compose.yml
  • templates/sparkyfitness/.felhom.yml

Commits on main:

  • 4351d08 — the two template files (after lint + image probes).
  • (this push) — CHANGELOG + README + REPORT docs.

templates.json (legacy Portainer index) intentionally left untouched. No other catalog apps modified.

3. §1.3 image healthcheck-tooling findings (verified on build server 192.168.0.180, v0.17.2)

Image Probe authored Finding Final probe kept
codewithcj/sparkyfitness_server:v0.17.2 node -e GET /api/health NODE_OK (node on PATH via --entrypoint node) kept the node-exec probe
codewithcj/sparkyfitness:v0.17.2 (frontend) wget --spider both present: /usr/bin/wget and /usr/bin/curl kept the wget --spider probe

No probe changes were required. Compose lints clean (docker compose config -q with the 4 ${...} vars set to dummies → LINT_OK).

4. Deploy method + evidence

Method: real UI flow via claude-in-chrome (no hand-written app.yaml).

  1. https://felhom.demo-felhom.eu → Alkalmazások → "Sablonok frissítése" (sync). App count 55→56, Telepíthető 52→53; SparkyFitness card appeared (/stacks/sparkyfitness/deploy).
  2. Deploy screen: Domain auto = demo-felhom.eu; Subdomain default sparky; 4 secrets shown "Automatikusan generálva"; memory gate 696 MB / 1664 MB (41%) → fits, not refused (Scenario C did not trigger). Clicked "Telepítés indítása" → "Konfiguráció mentve" → containers started.

docker ps (guest 9201):

sparkyfitness-frontend  codewithcj/sparkyfitness:v0.17.2         Up (healthy)
sparkyfitness-server    codewithcj/sparkyfitness_server:v0.17.2  Up (healthy)
sparkyfitness-db        postgres:15-alpine                       Up (healthy)

Server log excerpts (clean — Scenario A):

[INFO] Successfully applied migration: ...20260622120000_add_water_estimated_to_exercise_entries.sql
[INFO] Ensuring permissions for role: "sparkyapp"
[INFO] Successfully ensured permissions for role: "sparkyapp"
[INFO] Permissions granted to application user.
[INFO] Successfully applied all RLS policies.
[AUTH] Better Auth handler successfully mounted.
[INFO] SparkyFitnessServer listening on port 3010
[INFO] Incoming request: GET /api/health

No crash loop; no EACCES on /app/SparkyFitnessServer/uploads. Both DB roles confirmed present in the DB (SELECT rolname ... → sparky, sparkyapp).

Secrets (Scenario B) — verified without exposing values (from docker inspect env of the server):

  • SPARKY_FITNESS_API_ENCRYPTION_KEY length = 64 (hex:32 ✓)
  • BETTER_AUTH_SECRET length = 64 (✓)
  • SPARKY_FITNESS_FRONTEND_URL = https://sparky.demo-felhom.eu (public https ✓ — CORS/Better-Auth origin)
  • SPARKY_FITNESS_DB_USER = sparky, SPARKY_FITNESS_APP_DB_USER = sparkyapp (two distinct roles ✓)
  • SPARKY_FITNESS_DISABLE_SIGNUP = false (household can register ✓) All four secrets are locked_after_deploy; the two crypto keys carry data_key: true.

Browser checks:

  • https://sparky.demo-felhom.eu/login → SparkyFitness native email/password login + Sign Up page loads over a valid TLS cert (no warning). No OIDC buttons (correct for the customer template).
  • https://sparky.demo-felhom.eu/api/health (through the public Cloudflare edge → Traefik → frontend nginx /api proxy → server) → {"status":"UP"}. This proves the frontend→server proxy + public routing + TLS end-to-end.

5. NOT yet validated (explicit)

  • Interactive account register + login. Deliberately not performed by me: creating an account / entering credentials to authenticate falls under a browser-safety guardrail (prohibited even on request). Everything up to the authenticated API path is proven (healthy server, /api/health proxied through the public edge, CORS origin correctly set). Recommended human step: open https://sparky.demo-felhom.eu, click Sign Up, register a throwaway account, confirm login reaches the dashboard (≈30s). Expected to pass given the verified config.
  • Backup / restore of this app (incl. the data_key recovery path for the two crypto keys) — not exercised here.
  • Upload body-size limits for profile/exercise images (the k3s ingress set proxy-body-size: 50m; the Felhom Traefik path was not size-tested).
  • Garmin / MCP integrations — out of scope (commented out upstream; not enabled).

6. Observations (noticed, not acted on)

  • Upstream's compose uses postgres:18 + :latest; per the validated k3s manifest we pinned postgres:15-alpine with an explicit PGDATA subdir — kept that proven path.
  • The frontend image ships both wget and curl; the server image runs node as a valid exec entrypoint — both healthchecks are robust without extra tooling.
  • Demo guest 9201 has only 2 GB total RAM; SparkyFitness mem_limit is 1792M. The mem_request (400M) gate passed and real usage is far below the limit, but on a 2 GB box co-tenancy headroom is thin — worth noting for nodes running several heavier apps.