Aliases []string `json:"aliases,omitempty"`
Groups  []Group  `json:"groups,omitempty"`
Rank    uint     `json:"rank,omitempty"`

}


- Hierarchical room structure with groups and aliases
- Device-to-room mapping for contextual automation
- Room-based filtering and bulk operations functionality

### Automation Engine

#### Event Processing

The gateway now runs a fully async pipeline. HTTP ingestion returns immediately so device platforms are never blocked waiting on rule evaluation:

1. HTTP ingestion returns 202 immediately (under 50ms)
2. Deduplication window (5 seconds) prevents duplicate event processing
3. Events are persisted to SQLite before processing, so no events are lost on failure
4. Worker pool processes events in parallel (currently 10 workers)
5. Enrichment stage attaches device metadata, room context, and previous state
6. Rule evaluation and action execution across relevant platforms


#### Rules Engine

Rules started as Go handlers and are moving toward declarative YAML definitions. Both coexist in the current system, with the Go approach still in place for backward compatibility.

The Go handler interface:

```go
type Rule struct {
	Name       string
	Aliases    []string
	HandleFunc Handler
}

type Handler func(Event, room.List, device.List) (handled bool, err error)

At the moment, all events flow through all rule handlers so they must handle their own filtering. The goal is smarter routing by device or event type, along with hot-reload so rules can be updated without a deployment.

YAML rule definitions are now available for basic conditions and actions, with validation enforced at load time.

Scene Management

Scenes follow a similar structure to rules but are predefined automation scenarios that coordinate multiple devices across platforms. Currently they’re defined in Go:

func pbChillHandler(_ room.List, curDevices device.List) (bool, error) {
	tableLamp := curDevices.GetDevice(registry.PrimaryBedroomTableLamp)
	ceilingLight := curDevices.GetDevice(registry.PrimaryBedroomCeilingLight)

	switch {
	case timeframe.CurrentDay().IsWeekday() && timeframe.Night().CurTimeInFrame():
		if err := tableLamp.As(device.SwitchName).SendCommand(device.OnCommand); err != nil {
			return false, err
		}
		if err := ceilingLight.As(device.SwitchName).SendCommand(device.OffCommand); err != nil {
			return false, err
		}
		return true, nil
	default:
		return false, nil
	}
}

This works but is a bit clunky. The goal is to get to declarative YAML definitions that can be created and edited without touching Go code:

scenes:
  PBRChill:
    devices:
      - room: "primary_bedroom"
        type: "switch"
        action: "dim_to_30"
      - room: "primary_bedroom"
        type: "hvac"
        action: "cool_to_68"
    window: "weekday night"

YAML scene definitions are planned alongside the dashboard UI.