This guide documents common development workflows for contributors working on SuperAPI.
Use it as a practical checklist during daily development.
Use this when you only need process-level behavior and basic routes.
go run ./cmd/apiWhat to expect:
- API starts on configured HTTP_ADDR (default :8080)
- health and readiness routes are available
- external dependency features are disabled unless enabled via env
POSTGRES_ENABLED=true POSTGRES_URL="postgres://user:pass@localhost:5432/mydb?sslmode=disable" REDIS_ENABLED=true REDIS_ADDR="127.0.0.1:6379" AUTH_ENABLED=true RATELIMIT_ENABLED=true CACHE_ENABLED=true go run ./cmd/apiUse this mode when testing realistic route behavior.
After startup verify:
- GET /healthz
- GET /readyz
- GET /metrics (if metrics enabled)
make module name=projectsThis creates module files and updates module registry.
Before writing business logic, do these checks:
- confirm route path and package name are correct
- confirm module appears in internal/modules/modules.go
- confirm generated files compile
Scaffold output is a starting point. Update it to follow enforced flow:
- handler -> service -> repository ->
DB().Queries(ctx) - service runs no queries itself; it may only call
DB().WithTx(ctx, fn)to define write transaction boundaries - repositories must not control transaction boundaries
- repository public interface is domain-focused (no sqlc/pgx types)
For each module:
- Choose storage type (relational via
DB(), or the optional document store). - Define the repository contract in domain language.
- Implement the repository using
DB().Queries(ctx)and row->domain mapping. - Wire the repository/service in the module's dependency binding (
runtime.DB()). - Keep write paths transactional (
WithTx) and read paths direct.
Pattern:
- service calls
DB().WithTx(ctx, fn)to define the transaction boundary - service invokes repository write method(s) with the callback's
txCtx - repository runs
Queries(txCtx).<GeneratedWrite>(...), joining the tx WithTxcommits on nil error and rolls back on error/panic- the service runs no queries itself
Pattern:
- service calls the repository read method with
ctx - repository runs
Queries(ctx).<GeneratedRead>(...)on the pool - no forced tx wrapper by default
See docs/transactions.md for the full guide and the context-threading gotcha.
Create migration:
make migrate-create NAME=add_projects_tableApply migrations:
make migrate-up DB_URL="postgres://user:pass@localhost:5432/mydb?sslmode=disable"Roll back as needed:
make migrate-down DB_URL="postgres://user:pass@localhost:5432/mydb?sslmode=disable"If using sqlc-generated internals in repository implementation:
- update db/schema files
- update db/queries files
- regenerate code
make sqlc-generateImportant:
- sqlc output is implementation detail
- do not expose sqlc types in service/repository public contracts
Auth persistence uses the sqlc data layer; the goAuth boundary is unchanged.
Runtime sequence:
- app wiring creates the auth repository over the
storage.Postgresboundary - app wiring creates the sqlc-backed
StoreUserProviderfrom the repository - the goAuth engine (v0.4.0) is built with Redis + provider + tenancy settings
When testing auth routes:
- POST /api/v1/system/auth/login
- POST /api/v1/system/auth/mfa/confirm
- POST /api/v1/system/auth/refresh
- POST /api/v1/system/auth/logout
- GET /api/v1/system/whoami (requires auth)
See docs/auth-goauth.md for details.
Run standard checks:
go test ./...
go build ./...
make verifyArchitecture review checks:
- no handler bypass to the data layer
- no service running queries directly (
Queries(ctx)) or touching pgx - repositories obtain queries only via
Queries(ctx) - no repository controlling transaction boundaries (
WithTx) - one storage type per module
- policy order is valid
Likely causes:
- auth enabled without redis/postgres
- invalid duration/boolean env value
- prod fail-open configuration for cache/rate-limit
Action:
- check error message
- compare env values against docs/environment-variables.md
Likely causes:
- Postgres URL invalid/unreachable
- Redis addr invalid/unreachable
- tracing endpoint misconfiguration
Action:
- validate network connectivity
- validate startup ping timeout values
- test dependencies independently
Likely causes:
- policies attached in wrong order
- missing tenant policy for tenant route
- cache vary dimensions unsafe for authenticated route
Action:
- inspect route registration in module routes.go
- run verifier and review policy errors
- sync latest changes
- run or restart API
- implement one small module change
- run focused tests
- run full test/build/verify before push
- update docs if behavior changed