Skip to content

feat: add /api/health readiness endpoint (#47) - #61

Merged
savioruz merged 2 commits into
mainfrom
feat/health-endpoint
Aug 24, 2026
Merged

savioruz merged 2 commits into
mainfrom
feat/health-endpoint

Conversation

@savioruz

Copy link
Copy Markdown
Owner

Add an unauthenticated GET /api/health that reports whether the server is usable, not just listening. Returns "setup_required" until both the admin account and provider config exist, then "ready".

  • memayu-api: new health module (dto + service) reading the users and provider_config tables; DB errors resolve conservative to setup_required.
  • memayu-api: register /api/health on the full router outside auth and rate limiting.
  • memayu-web: register /api/health on the setup-only boot router so a fresh unconfigured instance is still healthcheckable.
  • Dockerfile: set MEMAYU_PORT=8080 to match EXPOSE 8080, and add g++ (libsql-ffi needs a C++ compiler) so the image builds.
  • README: document the endpoint as the Docker/systemd healthcheck target with example HEALTHCHECK and ExecStartPost snippets.
  • Tests: 4 service unit tests, 3 API integration tests, and a setup-only router test covering every state transition.

@savioruz savioruz self-assigned this Aug 24, 2026
@savioruz
savioruz marked this pull request as ready for review August 24, 2026 18:08
@savioruz savioruz added the priority-critical Critical priority — data integrity or core-functionality breakage label Aug 24, 2026
@savioruz savioruz added this to the v0.1.0 milestone Aug 24, 2026
@savioruz savioruz added feature New feature or capability core memayu-core domain logic api HTTP API transport/handlers self-hosted Relates to self-hosted / local-first usage priority-high Highest priority — must be done before next milestone labels Aug 24, 2026
@savioruz

savioruz commented Aug 24, 2026 •

Copy link
Copy Markdown
Owner Author

Review of PR #61 at 72581b328c0d6c0a4fd0e8fe011a9f6c1cde3523 (base main = b1841db), limited to origin/main...HEAD. Implements issue #47. Re-reviewed after head moved from d561773 → 72581b3 (squash): no logic changed since the first review (CI green: build 2m33s, clippy, fmt, test 2m38s, audit 3m17s).

🔴 Blocking

None.

🟡 Warning #1 — users_empty() used as the admin-existence proxy, not a role check

health::service::status decides ready via users_empty (non-empty users table = an account exists) + provider_configs non-empty. Fine for the "setup complete?" readiness question (memayu setup creates the first users row), but Display::fmt/doc says "admin account" which slightly overstates it. Acceptable; accurate to revisit if role-based auth lands.

🟡 Warning #2 — Dockerfile has no HEALTHCHECK directive (only documented in README)

The endpoint is documented as the Docker HEALTHCHECK / systemd ExecStartPost target via README snippets, but the Dockerfile itself does not emit a HEALTHCHECK line — a bare docker run won't get process-level checks until an operator adds one. The alpine build fix (apk add g++ for libsql-ffi) + ENV MEMAYU_PORT=8080/EXPOSE 8080 are correct. Advisory follow-up.

🟡 Warning #3 — Out-of-scope CI toolchain pin + rust-toolchain.toml mismatch (new in squash)

Between the original review commit and the squash, .github/workflows/ci.yml was changed from dtolnay/rust-toolchain@stable to @1.97.1 and a rust-toolchain.toml ([toolchain] channel = "stable") was added. Two issues: (a) pinning a specific toolchain + adding rust-toolchain.toml is infra/tooling churn unrelated to the #47 health endpoint and ideally lives in its own PR/commit; (b) rust-toolchain.toml says channel = "stable" while CI pins 1.97.1 — locally rustup will resolve stable (which may differ from 1.97.1), risking a fmt/clippy/toolchain mismatch between dev and CI. Recommend either dropping the toolchain pin from this PR (revert to @stable) or making rust-toolchain.toml also pin 1.97.1 so local and CI agree. Not a correctness bug.

Validation

Endpoint (#47) — unchanged from prior review

  • New module crates/memayu-api/src/modules/health/ (dto.rs, service.rs, mod.rs):
    • HealthStatus { SetupRequired, Ready } (snake_case), HealthResponse { status }.
    • status(db): setup_required until both users table non-empty AND provider_configs non-empty → ready; DB errors conservatively → setup_required. 4 #[tokio::test] unit tests on :memory: libsql covering all 4 state combinations.
  • Handler GET /api/health (transport/handlers/health.rs): delegates to service::status(&state.db).
  • Routes (transport/routes.rs:121): health_routes is merged in the outer router before/outside the protected auth + api_rate_limiter layers — only the outermost security_headers + cors + request_id layer applies. ✅ unauthenticated (explicit comment: "intentionally outside every auth and rate-limit layer").
  • web_services.rs: WebServices::health_status() exposed; memayu-web/src/lib.rs::health serves the same probe on the setup-only boot router so a fresh unconfigured instance is healthcheckable.
  • crates/memayu-api/src/lib.rs: re-exports HealthResponse/HealthStatus publicly.
  • 6 #[utoipa::path] route registrations; health is get only.

Docs / infra

  • Dockerfile: apk add ... g++ (libsql-ffi needs a C++ toolchain on alpine), ENV MEMAYU_PORT=8080 + EXPOSE 8080, CMD ["serve"].
  • README: documents the endpoint JSON, a Docker HEALTHCHECK snippet, and a systemd ExecStartPost readiness loop.

Tests

  • crates/memayu-api/tests/api.rs: health_is_unauthenticated_and_setup_required_on_fresh_instance (no auth header → 200, setup_required), health_is_setup_required_with_admin_but_no_providers, health_is_ready_after_setup_and_provider_config.
  • crates/memayu-web/tests/dashboard.rs: setup_router_exposes_health (setup-only router serves /api/health → setup_required).
  • Core unit tests: 4 state-machine tests in service.rs.

Migration / breaking

  • No DB schema change.
  • New public types HealthStatus/HealthResponse in memayu-api — additive.
  • Non-breaking GET /api/health (unauthenticated).

Checklist

Note: PR description was already adequate (reviewed before; unchanged by squash). Updated this comment in-place (sha → 72581b3) after re-confirming CI green and logging the out-of-scope tooling changes. Comment is updated in place per the ZeroClaw review convention; no new comment posted.

Add an unauthenticated GET /api/health that reports whether the server
is usable, not just listening. Returns "setup_required" until both the
admin account and provider config exist, then "ready".

- memayu-api: new health module (dto + service) reading the users and
  provider_config tables; DB errors resolve conservative to
  setup_required.
- memayu-api: register /api/health on the full router outside auth and
  rate limiting.
- memayu-web: register /api/health on the setup-only boot router so a
  fresh unconfigured instance is still healthcheckable.
- Dockerfile: set MEMAYU_PORT=8080 to match EXPOSE 8080, and add g++
  (libsql-ffi needs a C++ compiler) so the image builds.
- README: document the endpoint as the Docker/systemd healthcheck target
  with example HEALTHCHECK and ExecStartPost snippets.
- Tests: 4 service unit tests, 3 API integration tests, and a setup-only
  router test covering every state transition.
@savioruz
savioruz force-pushed the feat/health-endpoint branch from d561773 to e0124a5 Compare August 24, 2026 18:37
Replace dtolnay/rust-toolchain@stable and the rust-toolchain.toml
stable channel with an explicit 1.97.1 pin so CI and release builds are
reproducible across future stable releases. 1.97.1 is the version
verified locally (fmt, clippy, test all pass).
@savioruz
savioruz merged commit 637b16f into main Aug 24, 2026
5 checks passed
@savioruz
savioruz deleted the feat/health-endpoint branch August 25, 2026 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api HTTP API transport/handlers core memayu-core domain logic feature New feature or capability priority-critical Critical priority — data integrity or core-functionality breakage priority-high Highest priority — must be done before next milestone self-hosted Relates to self-hosted / local-first usage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant