---
id: w1/m4/t001
title: Idle → scale Deployment to 0 (per idleTTLSeconds)
worker: worker1
status: done
estimate: 30m
depends_on: []
---

## Objective

Detect inactivity per `App.spec.idleTTLSeconds` and set the Deployment's replicas to 0 (the _idle→0_ half already exists as an idea; wire it). Pairs with the allocator's idle-evict.

## Context

- `App.spec.idleTTLSeconds` (existing field). Free tier only.
- Inactivity signal: request metrics / last-access; assumption is a simple last-request timestamp to start.

## Files

- `operator/internal/controller/app_controller.go` (scale-to-0 on idle)

## Acceptance criteria

- [x] An idle free App's Deployment goes to 0 replicas after `idleTTLSeconds`.

## Implementation

Added to `app_controller.go`:
- `annotLastActive = "app.bex.co/last-active"` annotation tracks last traffic time (RFC3339).
- `shouldAutoHibernate()`: returns true when free tier, TTL > 0, not manually suspended, and `now - lastActive >= idleTTLSeconds`.
- `idleRequeueAfter()`: schedules the next idle check via `ctrl.Result{RequeueAfter}`.
- `isFreeApp()`: gates the feature to `tier == ""` or `tier == "free"`.
- On first Running reconcile: stamps `annotLastActive = now`, schedules recheck after TTL.
- On recheck: if TTL elapsed, sets `deployment.replicas = 0` and switches Ingress to activator.
- Operator sets `ActivatorService` from `BEX_ACTIVATOR_SERVICE` env; empty = feature off.
