Files
unpoller-unpoller-4/AGENTS.md
brngates98 969445fade Add AI context files for major LLMs
- Add .cursorrules for Cursor AI
- Add CLAUDE.md for Claude Code
- Add AGENTS.md for universal AI agent context
- Add .github/copilot-instructions.md for GitHub Copilot

These files provide comprehensive context about the UnPoller project
architecture, coding standards, and development patterns to help AI
coding assistants understand and work with the codebase effectively.
2026-01-27 20:40:02 -05:00

271 lines
7.8 KiB
Markdown

# UnPoller - AI Agent Context
This file provides comprehensive context for AI coding assistants working on the UnPoller project.
## Project Identity
**Name**: UnPoller (UniFi Poller)
**Language**: Go 1.25.5+
**Purpose**: Collect metrics and events from UniFi network controllers and export to monitoring backends
**Repository**: https://github.com/unpoller/unpoller
**Documentation**: https://unpoller.com
## Architecture Overview
UnPoller uses a **plugin-based architecture** with a generic core that provides input/output interfaces. The core library (`pkg/poller`) has no knowledge of UniFi or specific backends - it's a generic plugin system.
### Core Components
1. **Plugin System** (`pkg/poller/`):
- Generic input/output interfaces
- Automatic plugin discovery via blank imports
- Configuration management (TOML/JSON/YAML + env vars)
- Metrics and events aggregation
2. **Input Plugins**:
- `pkg/inputunifi/` - Collects data from UniFi controllers
3. **Output Plugins**:
- `pkg/influxunifi/` - InfluxDB (v1 and v2)
- `pkg/promunifi/` - Prometheus
- `pkg/lokiunifi/` - Loki
- `pkg/datadogunifi/` - DataDog
- `pkg/mysqlunifi/` - MySQL
4. **Web Server** (`pkg/webserver/`):
- Health checks
- Metrics endpoint
- Plugin information
## Code Organization
### Directory Structure
```
unpoller/
├── main.go # Entry point, loads plugins
├── pkg/
│ ├── poller/ # Core plugin system (generic)
│ │ ├── config.go # Configuration structures
│ │ ├── inputs.go # Input plugin interface
│ │ ├── outputs.go # Output plugin interface
│ │ ├── start.go # Application startup
│ │ └── commands.go # CLI commands
│ ├── inputunifi/ # UniFi input plugin
│ ├── influxunifi/ # InfluxDB output
│ ├── promunifi/ # Prometheus output
│ ├── lokiunifi/ # Loki output
│ ├── datadogunifi/ # DataDog output
│ ├── mysqlunifi/ # MySQL output
│ └── webserver/ # Web server
├── examples/ # Configuration examples
├── init/ # Init scripts (systemd, docker, etc.)
└── scripts/ # Build scripts
```
### Plugin Interface Pattern
**Input Plugin**:
```go
type Input interface {
GetMetrics() (*Metrics, error)
GetEvents() (*Events, error)
}
```
**Output Plugin**:
```go
type Output interface {
WriteMetrics(*Metrics) error
WriteEvents(*Events) error
}
```
**Registration**:
```go
func init() {
poller.RegisterInput(&MyInput{})
// or
poller.RegisterOutput(&MyOutput{})
}
```
## Coding Standards
### Go Style
- **Formatting**: Standard `gofmt`
- **Linting**: `.golangci.yaml` configuration
- Enabled: `nlreturn`, `revive`, `tagalign`, `testpackage`, `wsl_v5`
- **Imports**: Use `//nolint:gci` when import ordering needs exception
### Naming Conventions
- Packages: `lowercase`, single word
- Exported: `PascalCase`
- Unexported: `camelCase`
- Constants: `PascalCase` with descriptive names
- Errors: Always `err`, checked immediately
### Error Handling
```go
// ✅ Good
if err != nil {
return fmt.Errorf("context: %w", err)
}
// ❌ Bad
_ = functionThatReturnsError()
```
### Configuration Pattern
All configuration structs must include:
```go
type Config struct {
Field string `json:"field" toml:"field" xml:"field" yaml:"field"`
}
```
- Environment variables use `UP_` prefix (defined in `ENVConfigPrefix`)
- Automatic unmarshaling via `golift.io/cnfg` and `golift.io/cnfgfile`
### Testing
- Tests in `_test` packages (enforced by `testpackage` linter)
- Use `github.com/stretchr/testify` for assertions
- Integration tests: `integration_test.go` with `integration_test_expectations.yaml`
## Key Dependencies
### Core Libraries
- `github.com/unpoller/unifi/v5` - UniFi API client (local: `/Users/briangates/unifi`)
- `golift.io/cnfg` - Configuration management
- `golift.io/cnfgfile` - Config file parsing
- `github.com/spf13/pflag` - CLI flags
- `github.com/gorilla/mux` - HTTP router
### Output Backends
- **InfluxDB**: `github.com/influxdata/influxdb1-client` (v1), `github.com/influxdata/influxdb-client-go/v2` (v2)
- **Prometheus**: `github.com/prometheus/client_golang`
- **DataDog**: `github.com/DataDog/datadog-go/v5`
- **Loki**: Custom HTTP implementation
## Data Structures
### Metrics
```go
type Metrics struct {
TS time.Time
Sites []any
Clients []any
SitesDPI []any
ClientsDPI []any
Devices []any
RogueAPs []any
SpeedTests []any
CountryTraffic []any
}
```
### Events
```go
type Events struct {
Logs []any
}
```
### Device Types
UniFi devices supported:
- **UAP** - Access Points (`uap.go`)
- **USG** - Security Gateways (`usg.go`)
- **USW** - Switches (`usw.go`)
- **UDM** - Dream Machines (`udm.go`)
- **UXG** - Next-Gen Gateways (`uxg.go`)
- **UBB** - Building Bridges (`ubb.go`)
- **UCI** - Industrial devices (`uci.go`)
- **PDU** - Power Distribution Units (`pdu.go`)
Each output plugin has device-specific reporting functions following the pattern:
```go
func (r *Report) UAP(uaps []*unifi.UAP) {
// Convert and export UAP data
}
```
## Common Development Tasks
### Adding a New Output Plugin
1. Create package in `pkg/myoutput/`
2. Implement `Output` interface
3. Register in `init()` function
4. Add blank import to `main.go`: `_ "github.com/unpoller/unpoller/pkg/myoutput"`
5. Add configuration struct with tags
6. Create `README.md` with usage examples
### Adding Device Type Support
1. Add device-specific file (e.g., `mydevice.go`)
2. Follow pattern from existing device files
3. Convert UniFi device struct to output format
4. Handle errors appropriately
### Modifying Configuration
1. Add fields to appropriate config struct
2. Include all format tags: `json`, `toml`, `xml`, `yaml`
3. Update example configs in `examples/`
4. Document in package `README.md`
## Build & Deployment
- **CI/CD**: GitHub Actions (`.github/workflows/`)
- **Build**: `goreleaser` (`.goreleaser.yaml`)
- **Platforms**: Linux, macOS, Windows, FreeBSD
- **Docker**: Auto-built to `ghcr.io`
- **Packages**: Debian, RedHat via goreleaser
- **Homebrew**: Formula for macOS
## Important Constraints
1. **Generic Core**: `pkg/poller` must remain generic - no UniFi/backend knowledge
2. **Cross-Platform**: Support Windows, macOS, Linux, BSD
3. **Configuration**: Support TOML (default), JSON, YAML, and environment variables
4. **Error Handling**: Always check and return errors
5. **Context**: Use `context.Context` for cancellable operations
6. **Timeouts**: Respect timeouts and deadlines
7. **Logging**: Use structured logging via logger interfaces
## Configuration Examples
**File Formats**: See `examples/up.conf.example`, `examples/up.json.example`, `examples/up.yaml.example`
**Environment Variables**:
```bash
UP_INFLUX_URL=http://localhost:8086
UP_UNIFI_DEFAULT_USER=admin
UP_UNIFI_DEFAULT_PASS=password
UP_POLLER_DEBUG=true
UP_POLLER_INTERVAL=30s
```
## When Writing Code
1. **Follow Existing Patterns**: Look at similar plugins for examples
2. **Keep Core Generic**: Don't add UniFi/backend-specific code to `pkg/poller`
3. **Error Handling**: Check all errors, return descriptive messages
4. **Documentation**: Document exported functions and types
5. **Testing**: Write tests in `_test` packages
6. **Cross-Platform**: Test on multiple platforms when possible
7. **Performance**: Consider polling intervals and data volume
8. **Security**: Don't log passwords or sensitive data
## Resources
- **Documentation**: https://unpoller.com
- **UniFi Library**: https://github.com/unpoller/unifi
- **Grafana Dashboards**: https://grafana.com/dashboards?search=unifi-poller
- **Discord**: https://golift.io/discord (#unpoller channel)