This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Terraform/OpenTofu provider for Uptrace (observability platform). It uses the Terraform Plugin Framework (ProtoV6) and auto-generates the API client from an OpenAPI specification using oapi-codegen.
-
Generated Client Layer (
internal/client/generated/)- Auto-generated from
api/openapi.yamlusing oapi-codegen - Never edit directly - regenerate with
task generate - Contains type-safe HTTP client with models
- Auto-generated from
-
Client Wrapper Layer (
internal/client/client.go)- Wraps generated client with higher-level operations
- Handles error responses consistently via
handleErrorResponse() - All methods accept
context.Contextas first parameter - ProjectID stored in client struct, passed to all API calls
-
Provider Layer (
internal/provider/)- Terraform Plugin Framework resources and data sources
- Model conversion between Terraform types and API types happens here
- Pattern:
*_resource.go(CRUD),*_models.go(conversion),*_data_source.go(read-only)
Model Conversion Flow:
Terraform Plan → *Model structs → API Input structs → HTTP Request
HTTP Response → API Output structs → *Model structs → Terraform State
Resource Structure:
- Each resource implements:
Resource,ResourceWithConfigure,ResourceWithImportState - CRUD methods:
Create(),Read(),Update(),Delete(),ImportState() - Models use Terraform types (
types.String,types.Int64, etc.) NOT Go primitives - API models use Go primitives and pointers for optional fields
Dashboard Resource Exception:
- Dashboard uses YAML-based API instead of JSON
CreateDashboardFromYAML()andUpdateDashboardFromYAML()sendtext/yamlcontent type- YAML field is required input, all other fields computed from API response
task generate # Generate API client from OpenAPI spec
task docs # Generate Terraform provider documentationCRITICAL: Always run task generate after modifying api/openapi.yaml. The generated client is the source of truth for API types.
# Unit tests only (no external dependencies)
task test:unit
go test -short ./...
# Run specific test
go test -v -run TestPinDashboard ./internal/client/
# Acceptance tests (requires Uptrace instance)
task dev:up # Start local Uptrace with Docker
task test:acc # Run all acceptance tests
TF_ACC=1 go test -v -run TestAccDashboardResource_Basic ./internal/provider/
# Coverage
task test:coverage:unit # Unit test coverage → coverage.html
task test:coverage:acc # Acceptance test coverage → coverage-acc.html
task test:coverage:all # Both coverage reportsAcceptance Test Environment:
- Endpoint:
http://localhost:14318/internal/v1 - Token:
user1_secret_token - Project ID:
1 - Set
TF_ACC=1to enable acceptance tests
task build # Build provider binary
task lint # Run golangci-lint (strict config)
task lint:fix # Auto-fix linting issuesWhen adding/modifying API endpoints in api/openapi.yaml:
- Update OpenAPI spec with new schemas/endpoints
- Run
task generateto regenerate client - Add wrapper methods in
internal/client/client.go:func (c *Client) GetFoo(ctx context.Context, id int64) (*generated.Foo, error) { resp, err := c.client.GetFooWithResponse(ctx, c.projectID, id) if err != nil { return nil, fmt.Errorf("failed to get foo: %w", err) } if !isSuccessStatus(resp.StatusCode(), http.StatusOK) { return nil, c.handleErrorResponse(resp.StatusCode(), resp.Body) } if resp.JSON200 == nil { return nil, fmt.Errorf("unexpected empty response") } return &resp.JSON200.Foo, nil }
- Add unit tests in
internal/client/client_test.gousinghttptest.NewServer() - Create/update provider resources in
internal/provider/
Every new feature MUST include:
- Unit tests - Test client methods with mock HTTP servers
- Acceptance tests - Test resources against real Uptrace instance
- Both unit and acceptance test coverage tracked separately in CI
Test file naming:
*_test.go- Unit tests (run with-shortflag)*_acc_test.go- Acceptance tests (requireTF_ACC=1)
Common test helpers:
newTestClient(server)- Create client for unit testsacceptancetests.GetTestClient()- Get client for acceptance testsacceptancetests.RandomTestName(prefix)- Generate unique resource names
The golangci-lint config is strict. Common issues:
- godot: All comments must end with a period
- revive unused-parameter: Rename unused params to
_ - gocritic paramTypeCombine: Combine consecutive same-type params:
func(a, b string) - dupl: Use
//nolint:duplwith justification for acceptable duplicates
Generated code in internal/client/generated/ is excluded from linting.
CRITICAL: Never push directly to main. Always create a Pull Request.
- Create a feature branch:
git checkout -b feat/my-feature - Make commits with conventional commit messages
- Push branch:
git push -u origin feat/my-feature - Create PR:
gh pr create --title "feat: my feature" --body "Description" - Wait for CI checks to pass
- Merge via GitHub (squash or merge commit)
Commit message format (Conventional Commits):
feat: add dashboard clone functionality
fix: handle 404 errors in monitor resource
test: add unit tests for pin/unpin operations
docs: update OpenAPI spec with new endpoints
All commits must include:
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
GitHub Actions runs:
- Build - Verify compilation
- Unit Tests - With coverage upload to Codecov (flag:
unittests) - Acceptance Tests - Against local Uptrace (flag:
acceptancetests) - Lint - golangci-lint with strict config
- Cloud API Tests - If secrets configured
All checks must pass before merge.
- Don't edit generated code - Always modify
api/openapi.yamland regenerate - Use Terraform types in models -
types.Stringnotstring, even for required fields - Pointers in API structs - Generated API types use pointers for optional fields
- Context first parameter - All methods accepting context must have it as first param
- Dashboard YAML quirk - API enriches YAML with defaults, causing drift. Use
ignore_changes = ["yaml"]orImportStateVerifyIgnorein tests - Test isolation - Acceptance tests use random names via
RandomTestName()to avoid conflicts
api/ # OpenAPI specifications (source of truth)
openapi.yaml # Main API spec
internal/
client/
generated/ # Auto-generated client (never edit)
client.go # Client wrapper with high-level methods
client_test.go # Unit tests for client methods
provider/
provider.go # Provider configuration
*_resource.go # Resource implementations (CRUD)
*_models.go # Model conversion logic
*_data_source.go # Data source implementations
*_acc_test.go # Acceptance tests
acceptance_tests/ # Shared test utilities
acctest.go # Test configuration helpers
dev-env/ # Docker Compose for local Uptrace
examples/ # Terraform examples for documentation
docs/ # Generated provider documentation