pulse

Contributing to pulse

Development setup

Requirements: Go 1.25+, PostgreSQL 16+, protoc with the Go plugins (only for proto changes), Docker (optional, for the compose stack).

git clone https://github.com/bete7512/pulse && cd pulse

createdb pulse_test                      # a throwaway database for integration tests
# .env for the server:
#   DB_HOST=postgres://user:pass@localhost:5432/pulse

make migrate_up                          # apply migrations
make run                                 # run the server

The repository holds two Go modules:

modulepathcontents
github.com/bete7512/pulse/SDK (root package), server (cmd/pulsed), migrations, load generator
github.com/bete7512/pulse/cli/clithe pulse operator CLI (kept separate so SDK consumers don't inherit CLI dependencies)

Running tests

go test -race ./...                                          # unit tests only
TEST_DB_URL=postgres://user:pass@localhost:5432/pulse_test \
  go test -race ./...                                        # + Postgres integration tests
cd cli && go test ./...                                      # CLI module

Integration tests truncate the tables they use — always point TEST_DB_URL at a throwaway database, never at one with data you care about.

Conventions:

  • Tests use testify suite.Suite; mocks are gomock (make generate-mock regenerates them from the //go:generate directives). In expectations, only ctx uses gomock.Any() — match everything else precisely.
  • Concurrency-critical behavior (claims, fencing, recovery) is tested against real Postgres under -race, not mocks.

Code changes

  • make proto regenerates gRPC stubs after editing proto/pulse/v1/pulse.proto.
  • Migrations are append-only: add a new numbered file under db/migrations/, register it in migration.go, and verify up/down/up against a throwaway database.
  • Lint must pass: golangci-lint run ./... in both modules (CI enforces v2.6.2).
  • All state transitions belong in guarded SQL in internal/repos/postgres/ — invariants live in WHERE clauses, not in application-level checks.

Design decisions

Non-trivial decisions are recorded in docs/adr/. If a change alters a recorded decision, update the ADR (or add a new one) in the same PR — the reasoning is part of the codebase.

Pull requests

  • Keep PRs focused; include tests for behavior changes.
  • CI runs vet, lint, build, and the full test suite (with Postgres) on both modules — green CI is the bar for review.

On this page