Go API serving the 3 metrics endpoints for the Pulso health dashboard — reads from the PostgreSQL database that pulso-etl populates. Read-only: this service owns no schema and runs no migrations.
- Go 1.25, Echo v4 (HTTP), GORM +
gorm.io/driver/postgres(DB access) - testify for test assertions
- pulso-etl running locally (
docker compose up dbat minimum) — this API reads from itspulsodatabase. - Go 1.25+, or Docker.
# 1. Make sure pulso-etl's docker compose is already running (provides Postgres on localhost:5432)
# 2. Build and start the API, pointing at that Postgres:
DB_HOST=host.docker.internal docker compose up --buildAPI is then available at http://localhost:8080.
go mod download
DB_HOST=localhost go run .| Variable | Default | Description |
|---|---|---|
DB_HOST |
localhost |
PostgreSQL host |
DB_PORT |
5432 |
PostgreSQL port |
DB_NAME |
pulso |
Database name |
DB_USER |
postgres |
Database user |
DB_PASSWORD |
postgres |
Database password |
CORS_ALLOWED_ORIGIN |
http://localhost:5173 |
Allowed CORS origin |
PORT |
8080 |
HTTP listen port |
GET /api/metrics/energy-vs-goal?start=YYYY-MM-DD&end=YYYY-MM-DD— daily active energy vs goal, default last 90 daysGET /api/metrics/workout-volume?start=YYYY-MM-DD&end=YYYY-MM-DD— weekly workout count/duration/energy, default last 12 weeksGET /api/metrics/top-record-types?start=YYYY-MM-DD&end=YYYY-MM-DD— top 5 record types by volume, weekly, default last 12 weeks. Dataset labels are human-readable ("Heart Rate", not the rawHKQuantityTypeIdentifierHeartRate).
All three return {"labels": [...], "datasets": [{"label": ..., "data": [...]}], "meta": {"unit": ..., "window": ..., "last_updated": ...}}. Invalid start/end returns 400 with {"error": "..."}.
This is a byte-for-byte contract-compatible reimplementation of the Django API that used to live in pulso-dashboard — see docs/superpowers/specs/2026-07-11-django-to-go-api-migration-design.md in that repo for the full design rationale.
# Start a local Postgres for tests
docker run -d --name pulso-api-test-db -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=pulso_test -p 5432:5432 postgres:17-alpine
# Run all tests
DB_HOST=localhost DB_USER=postgres DB_PASSWORD=postgres TEST_DB_NAME=pulso_test go test ./... -p 1 -vTests apply their own minimal schema (internal/testutil/schema.sql) to pulso_test — production schema is always owned by pulso-etl. -p 1 is required: internal/handlers and internal/repository both truncate the same tables via testutil.TestDB(), and Go runs different packages' tests concurrently by default, which races one package's truncate against another's in-flight assertions.
Build and Test (.github/workflows/tests.yml) — go vet + go test ./... against a Postgres service container, on every push/PR.
Docker Build (.github/workflows/docker.yml) — builds the API Docker image, on every push/PR.