Skip to content

Development and testing ​

Workspace workflow ​

go.work is the module inventory. Shared libraries live in pkg/, business and application modules in services/, and the operational CLI in tools/. Each module owns dependencies and its go.mod/go.sum. Run scoped commands such as:

sh
go test -race -short ./pkg/config/... ./pkg/email/... ./pkg/events/...
go test -race -short ./services/medicine/... ./services/api/...
test -z "$(gofmt -l -s pkg services tools)"

make test discovers module directories and runs go test -race -short -cover ./... in each, skipping modules with no Go packages. make lint uses golangci-lint and .golangci.yml; make fmt rewrites Go formatting, while the gofmt command above checks it. make tidy changes module dependencies and should be reviewed.

Root Makefile commands ​

Run these from the repository root:

CommandPurpose
make dev-upBuild and start enabled development Compose services
make dev-downStop and remove development Compose containers and networks
make dev-apiRun the API with Air using services/api/.air.toml
make testTest all discovered Go modules with race detection and coverage in short mode
make test:e2eRun integration test packages across all modules; require AUTH_TEST_DATABASE_URL for identity
make lintRun golangci-lint in every discovered Go module
make fmtFormat Go source in every discovered Go module
make tidyRun go mod tidy in every discovered Go module
make build-apiBuild the prescriptoo-api:latest Docker image
make serve-apiRun the existing API image with .env and host networking on API_PORT (default 8080)
make build-cliBuild the operational CLI at bin/pcli
make build-docsBuild the complete prescriptoo-api-docs:latest image
make serve-docsRun the existing docs image on DOCS_PORT (default 8081)

Database operations use the CLI commands directly. The console groups commands under Database, Generate, Clean, and Build. Use pcli build api, pcli build docs, or pcli build cli directly; the matching Makefile targets delegate to these handlers. The CLI can rebuild itself on Linux; restart a running console to use the new binary. Preview repository cleanup with pcli clean all --dry-run, then choose a target and pass --yes to remove it. Never edit, delete, rename, or reorder existing migration files unless the user explicitly requests it. Add a new migration for schema and data changes by default; see the migration authoring rule. Protobuf and OpenAPI generation use the CLI generation commands. Documentation generation, local previews, and validation use the Go and npm commands.

Test layers ​

Unit and contract tests run without production dependencies. Huma handler tests assert request validation, problem responses, schema examples, and current 501 behavior. Composition-root tests protect route registration, legacy route precedence, and generated/runtime OpenAPI parity.

Identity's PostgreSQL integration tests are enabled with AUTH_TEST_DATABASE_URL and skip when it is absent or -short is passed. Use a dedicated test database: those tests migrate and change data. See authentication verification. Current RabbitMQ unit tests do not require a broker; deployment-level broker checks are separate. See events.

The test Compose project uses its own PostgreSQL instance, credentials, and database on 127.0.0.1:5433. Copy the TEST_POSTGRES_* settings and matching AUTH_TEST_DATABASE_URL from .env.example into .env. These are separate from the application DATABASE_URL. Run integration test packages:

sh
make test:e2e

This target starts the test database and waits for it to become healthy before running tests. It stops and removes the test containers and network when tests finish, fail, or are interrupted, including when startup fails. It discovers packages containing *_integration_test.go under pkg/, services/, and tools/, then runs each package with race detection and without cached results. It loads .env when AUTH_TEST_DATABASE_URL is not already set in the environment. Other tests in those packages also run. It fails when the identity test database URL is missing or a package fails. New integration test packages are included automatically; no new E2E tests are added by this target. Test database storage is temporary and is cleared when the container stops. The staged Bruno API workflow remains separate; see API testing.

Adding a use case ​

Keep one operation per file (ADR-011). Define provider-owned contracts under public/, implement behavior inside the owning service, and obtain narrowly scoped capabilities through module/. Consumers must not import another service's internal packages. Wire dependencies in the API composition root, register Huma operations, and test both local validation and implemented business behavior.

After contract changes, run go run ./tools/cli generate openapi, review api/openapi.yaml, and follow documentation generation and validation. Add or update workflow guides alongside the code. A success example on a 501 route is an intended payload, not a passing functional test.

Documentation follows the source. Planned contracts are marked explicitly.