Files
unpoller/CLAUDE.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

6.8 KiB

UnPoller - Claude Code Context

Project Overview

UnPoller is a Go application that collects metrics and events from UniFi network controllers and exports them to various time-series databases and monitoring systems. The application uses a plugin-based architecture where input plugins collect data and output plugins export it to different backends.

Architecture

Core Design Principles

  1. Plugin-Based Architecture: The core pkg/poller library is generic and provides interfaces for input and output plugins. It has no knowledge of UniFi, InfluxDB, Prometheus, etc.

  2. Automatic Plugin Discovery: Plugins are loaded via blank imports in main.go. The poller automatically discovers and initializes all imported plugins.

  3. Flexible Configuration: Supports TOML (default), JSON, and YAML configuration files, plus environment variables with UP_ prefix.

  4. Multiple Backends: Supports InfluxDB, Prometheus, Loki, DataDog, and MySQL as output backends.

Package Structure

pkg/
├── poller/          # Core plugin system - generic, no UniFi/backend knowledge
├── inputunifi/      # UniFi controller input plugin
├── influxunifi/     # InfluxDB output plugin
├── promunifi/       # Prometheus output plugin
├── lokiunifi/       # Loki output plugin
├── datadogunifi/    # DataDog output plugin
├── mysqlunifi/      # MySQL output plugin
└── webserver/       # Web server for health checks and metrics

Key Interfaces

Input Interface (pkg/poller/inputs.go):

  • GetMetrics() - Returns aggregated metrics
  • GetEvents() - Returns events/logs
  • Plugins must implement this to provide data

Output Interface (pkg/poller/outputs.go):

  • WriteMetrics() - Writes metrics to backend
  • WriteEvents() - Writes events to backend
  • Plugins must implement this to export data

Code Style Guidelines

Go Conventions

  • Go Version: 1.25.5+
  • Formatting: Use gofmt standard formatting
  • Linting: Follow .golangci.yaml configuration
    • Enabled: nlreturn, revive, tagalign, testpackage, wsl_v5
    • Use //nolint:gci for import ordering exceptions

Naming

  • Packages: Lowercase, single word
  • Exported: PascalCase (types, functions, constants)
  • Unexported: camelCase
  • Errors: Always named err, checked immediately

Error Handling

// Good: Check and return errors
if err != nil {
    return fmt.Errorf("operation failed: %w", err)
}

// Bad: Ignoring errors
_ = someFunction()

Configuration Pattern

type Config struct {
    URL      string `json:"url" toml:"url" yaml:"url"`
    Interval string `json:"interval" toml:"interval" yaml:"interval"`
    Timeout  string `json:"timeout" toml:"timeout" yaml:"timeout"`
}
  • Always include json, toml, xml, yaml tags
  • Environment variables use UP_ prefix automatically
  • Use golift.io/cnfg for configuration management

Testing

  • Tests in separate _test packages (enforced by testpackage linter)
  • Use github.com/stretchr/testify for assertions
  • Integration tests use integration_test_expectations.yaml

Common Tasks

Adding a New Output Plugin

  1. Create Package Structure:

    package myoutput
    
    import (
        "github.com/unpoller/unpoller/pkg/poller"
    )
    
    type Output struct {
        // Configuration fields
    }
    
    func (o *Output) WriteMetrics(m *poller.Metrics) error {
        // Implementation
    }
    
    func (o *Output) WriteEvents(e *poller.Events) error {
        // Implementation
    }
    
    func init() {
        poller.RegisterOutput(&Output{})
    }
    
  2. Add Blank Import to main.go:

    _ "github.com/unpoller/unpoller/pkg/myoutput"
    
  3. Add Configuration to config structs with proper tags

  4. Create README.md documenting usage

Adding Device Type Support

Each output plugin has device-specific files:

  • uap.go - Access Points
  • usg.go - Security Gateways
  • usw.go - Switches
  • udm.go - Dream Machines
  • uxg.go - Next-Gen Gateways
  • ubb.go - Building Bridges
  • uci.go - Industrial devices
  • pdu.go - Power Distribution Units

Follow the pattern in existing files:

func (r *Report) UAP(uaps []*unifi.UAP) {
    // Convert UniFi device data to output format
}

Working with UniFi Data

  • UniFi library: github.com/unpoller/unifi/v5 (local replace at /Users/briangates/unifi)
  • Device types come from the UniFi controller API
  • Data includes: sites, clients, devices, DPI data, speed tests, country traffic
  • Events include: system logs, alarms, IDS events, anomalies

Dependencies

Core

  • github.com/unpoller/unifi/v5 - UniFi API client
  • golift.io/cnfg - Configuration management
  • golift.io/cnfgfile - Config file parsing
  • github.com/spf13/pflag - CLI flags

Output Backends

  • InfluxDB: github.com/influxdata/influxdb1-client (v1) and github.com/influxdata/influxdb-client-go/v2 (v2)
  • Prometheus: github.com/prometheus/client_golang
  • DataDog: github.com/DataDog/datadog-go/v5
  • Loki: Custom HTTP client implementation

Important Patterns

Plugin Registration

func init() {
    poller.RegisterInput(&Input{})
    // or
    poller.RegisterOutput(&Output{})
}

Configuration Loading

Configuration is automatically loaded from:

  1. Config file (TOML/JSON/YAML) - path specified via --config flag or defaults
  2. Environment variables with UP_ prefix
  3. CLI flags

Metrics Structure

type Metrics struct {
    TS             time.Time
    Sites          []any
    Clients        []any
    SitesDPI       []any
    ClientsDPI     []any
    Devices        []any
    RogueAPs       []any
    SpeedTests     []any
    CountryTraffic []any
}

Events Structure

type Events struct {
    Logs []any
}

Build & Deployment

  • CI/CD: GitHub Actions
  • Build Tool: goreleaser for multi-platform builds
  • Platforms: Linux, macOS, Windows, FreeBSD
  • Docker: Images built automatically to ghcr.io
  • Homebrew: Formula for macOS users
  • Packages: Debian, RedHat packages via goreleaser

When Writing Code

  1. Keep it Generic: The pkg/poller core should remain generic
  2. Follow Patterns: Look at existing plugins for examples
  3. Error Handling: Always check and return errors
  4. Cross-Platform: Consider Windows, macOS, Linux, BSD differences
  5. Context Usage: Use context.Context for cancellable operations
  6. Timeouts: Respect timeouts and deadlines
  7. Documentation: Document exported functions and types
  8. Testing: Write tests in separate _test packages

Configuration Examples

Configuration files support multiple formats. See examples/ directory:

  • up.conf.example - TOML format
  • up.json.example - JSON format
  • up.yaml.example - YAML format

Environment variables use UP_ prefix:

  • UP_INFLUX_URL=http://localhost:8086
  • UP_UNIFI_DEFAULT_USER=admin
  • UP_POLLER_DEBUG=true