# A Health App Backend in Go on ToGO: The Health Debug Case Study

> How Health Debug keeps every timer, cooldown and window on the server, with protocol engines as ToGO plugins, an injected clock and a deny-by-default API. Real counts and honest limits.

*2026-10-19T12:49:03Z*

# A health app backend in Go on ToGO: the Health Debug case study

Health Debug is a self-care and health tracking product for people who sit at a desk all day. This case study shows how its backend, a health tracking app backend in Go, is built on ToGO: protocol engines as plugins, a server that owns all the timing, and a deny-by-default API. The repository is private, so this is architecture in prose with no code listings. Health Debug is not open source.

## 1. The problem

Health rules are fiddly: water in fixed units with a daily cap and a cooldown, no caffeine in the first part of the day, a window before sleep, a grace period for medication, cycle logic that must refuse to predict until it has enough data. If every client (web, browser extension, mobile, desktop) implements those rules, they drift apart and the user sees different answers on different devices.

Two product rules shape everything. The protocol is categorical, not quantitative: a food is safe or trigger-bearing, with no calorie maths. And the app never invents medical certainty: it does pattern analysis only and defers to a doctor.

## 2. Why ToGO

- **A microkernel with plugins.** Each protocol engine can be its own plugin with its own rules, registered at start-up.
- **API-first.** REST with OpenAPI from Huma, so every client is a thin renderer.
- **Auth and Postgres as plugins.** Sessions for the web, personal access tokens for the other clients, and a Postgres driver, without custom glue.
- **Vendoring.** The ToGO modules are private and vendored, so builds work fully offline.

Health Debug pins ToGO v0.21.0, with the auth plugin v0.8.0 and db-postgres v0.1.0 (from `go.mod`).

## 3. Architecture

**The server is the source of truth.** Every timer, cooldown, window, grace period and prediction is computed in the API. Clients render server state and submit intents or sensor events. A CI audit checks that protocol constants do not appear in client code.

**Plugins.** `internal/plugins/plugins.gen.go` imports two ToGO plugins: auth and db-postgres. The engines live under `internal/engines`, and an `enabled` package turns each one on with a blank import, so disabling an engine is deleting one line, not code. Today that package imports eight entries: caffeine block, contraceptive security, cycle, GERD window, hydration, medication grace, trigger families, and a reference engine used as a template. Each engine is split into a pure core with no I/O and a thin shim that registers it.

**Injected clock.** No core package calls the system clock. Time is passed in, which makes every window and cooldown testable, and there are purity tests that enforce the rule.

**Auth.** A deny-by-default guard sits in front of the API. A request for another user's data answers 404, not 403, so existence is not leaked. Web uses a session cookie; other clients use personal access tokens. A phone/OTP and two-factor flow is in the schema history.

**Database.** PostgreSQL 16 with versioned, expand-contract migrations. Every column is NOT NULL with a default, and a schema-lint tool in CI checks the rules.

**MCP.** `mcp/` exposes tools so an assistant can log and read data: today status, log water, list drinks, log caffeine, log wake time, engine history, list, pin and add foods, and log food.

**Clients.** Web, a Chrome extension, an Expo/React Native app and an Electron desktop shell, all consuming the same API and shared tokens and ICU message catalogs (English and Arabic, with RTL).

## 4. Code

The repository is private, so there are no snippets.

## 5. Numbers (counted from the repo)

| What | Count | How |
|---|---|---|
| ToGO plugins in `plugins.gen.go` | 2 | blank imports in `internal/plugins` |
| Engine entries enabled | 8 | blank imports in `internal/engines/enabled` |
| MCP tools | 10 | tool entries in `mcp/tools.go` |
| Database migrations | 27 | `.sql` files in `db/atlas/migrations` |
| Go test files (excluding vendor) | 67 | `*_test.go` count |
| Plan documents | 14 | `docs/plan` |

The README describes eight protocol engines, including a kinetic Pomodoro one. The tree today holds seven protocol engine packages plus the reference one, so the eighth is not in the code yet. No user numbers or performance figures are claimed here.

## 6. What was hard, and how ToGO helped

- **Keeping logic out of clients.** ToGO does not enforce this. It is a rule backed by a CI audit and a purity test, not a framework feature.
- **Engines as plugins.** The kernel's plugin model gave a natural boundary. The engine framework on top (a registry, an injected clock, schema-name tests) is ours.
- **Safe migrations.** Strict expand-contract migrations are slower to write, and necessary when a health log cannot be lost.
- **Private modules.** Vendoring keeps CI offline, and it is the reason the repository stays private.
- **ToGO is 0.x.** Pin versions and expect change.

Health Debug does not diagnose or prescribe. This article is not medical advice.

## FAQ

### Why keep health protocol logic on the server?
So every client shows the same state. Timers and windows are computed once in the API.

### How are protocol engines built on ToGO?
Each is a plugin: a pure core for the rules and a thin shim that registers it at init.

### Is Health Debug open source?
No. The repository is private.

### Does Health Debug give medical advice?
No. It never diagnoses or prescribes, and defers to a doctor.

## Links

- [Health Debug](https://healthdebug.com)
- [ToGO on GitHub](https://github.com/togo-framework/togo)
- [ToGO showcase](https://to-go.dev/en/showcase)

## Related reading

- [Expose your Go app as an MCP server with web-mcp](/en/blog/go-mcp-server-togo-web-mcp)
- [ToGO vs Gin, Echo and Fiber](/en/blog/togo-vs-gin-echo-fiber)

---

Source: https://to-go.dev/en/blog/health-debug-togo-case-study
