Use Go Modules: go mod tidy, go test ./...
- One API operation per file:
client_<collection>_<operation>.go - Client returns protobuf messages — see
proto/for schemas - Protobuf conversion functions live in
proto.go
The CLI is split into two layers to keep credential storage pluggable:
cli/
├── cli.go # Store interface, Credentials, FileStore, Options
└── command.go # NewCommand() — full command tree
cmd/rfms/
└── main.go # Thin wrapper: wires FileStore to XDG paths
cli.Store— interface withRead(any),Write(any),Clear()methodscli.NewCommand(...Option)— builds the Cobra command tree; receives stores via functional options (WithCredentialStore,WithTokenStore)cmd/rfms/main.go— only wiresFileStoreinstances and callscli.NewCommand()
This separation lets consumers embed the CLI in a larger tool or swap the storage backend (e.g. use an in-memory store in tests, or a keychain-backed store) without forking.
The rFMS standard is implemented by multiple OEMs, each with their own auth:
- Scania — OAuth2 client credentials (
auth login scania --client-id --client-secret). Token cached in the token store. - Volvo Trucks — HTTP Basic Auth (
auth login volvo-trucks --username --password). No token store needed.
The Credentials struct stores the active provider alongside the provider-specific fields.
The CLI can be embedded as a subcommand in a larger tool (e.g. a unified way CLI). Key design rules:
- Never use
cmd.Root()— resolves to the parent CLI's root when embedded, breaking flag lookups. Usecmd.Flags()instead (works for both persistent and local flags). WithHTTPClient— the parent injects an*http.Clientviacli.WithHTTPClient(). The SDK layers (auth, retry) stack on top of the injected client's transport.DebugTransport— exported indebug.gowith a lazyEnabled *boolfield. The parent owns the--debugflag and pointsEnabledat the flag variable. The transport checks the pointer at request time, solving the chicken-and-egg problem (transport constructed before flag parsing).
var debug bool
cmd := cli.NewCommand(
cli.WithCredentialStore(store),
cli.WithTokenStore(tokenStore),
cli.WithHTTPClient(&http.Client{
Transport: &rfms.DebugTransport{
Enabled: &debug,
Next: http.DefaultTransport,
},
}),
)
cmd.PersistentFlags().BoolVar(&debug, "debug", false, "Enable debug logging")Three separate Go modules prevent Cobra/CLI dependencies from leaking into the SDK library:
go.mod # SDK client library (no cobra, no CLI deps)
cli/go.mod # CLI commands (depends on root SDK + cobra)
cmd/rfms/go.mod # Standalone binary (depends on cli module)
Consumers who only need the Go client import the root module without pulling in CLI dependencies.
- Subcommands are organized by entity using
cobra.Group - Fully paginate results where applicable
- Flat command structure:
vehicles,vehicle-positions, notvehicles list