---
id: w1/m4.5/t003
title: Idle-timeout control in Settings wired to spec.idleTTLSeconds (incl. the API gap)
worker: worker1
status: done
estimate: 35m
depends_on: [w1/m4.5/t001, w1/m4/t005]
---

## Objective

A Settings-tab control to view/change the service's idle timeout, persisting to `App.spec.idleTTLSeconds`. **This is a bex extension, not Render parity** — Render's free-instance spin-down window is fixed (~15 minutes) with no user knob and no such API field; bex exposes it because sleep is first-class here. Fit the control into the existing Settings-tab layout (w5/m7 pattern) and label/document it as a bex feature. Includes the **API gap**: the GraphQL surface doesn't expose/mutate `idleTTLSeconds` yet — extend the service object + a mutation (or fold into the existing service-update mutation) in `lego/backend/internal/apps/`, three-adapter-consistent (REST PATCH accepts it too, documented as a bex extra like `percentage`).

## Context

- Settings tab: `dashboard/src/routes/services.$serviceId.settings.tsx` + `features/services` (instance-type picker from w5/m7 is the pattern to mirror).
- Backend: `lego/backend/internal/apps/{service,graphql,rest}.go`; `spec.idleTTLSeconds` exists in `lego/types` (m4 makes the operator honor it).
- Free-tier-only semantics (paid tiers never sleep, per m4) — the control should say so per tier.

## Steps

1. Backend: expose `idleTTLSeconds` on the service object; accept it in PATCH + a GraphQL mutation; authorize like every verb.
2. Dashboard: Settings section with the control, save/confirm, per-tier enable/disable + copy.
3. docs/ADR006-bex-api.md row update.

## Files

- `lego/backend/internal/apps/` (service/graphql/rest)
- `dashboard/src/routes/services.$serviceId.settings.tsx`, `dashboard/src/features/services/`
- `docs/ADR006-bex-api.md`

## Acceptance criteria

- [ ] Changing the timeout in Settings round-trips: GraphQL mutation → `spec.idleTTLSeconds` on the CR → value re-reads in the UI; paid-tier UI state matches m4's "never sleeps" contract.

## Out of scope

- The operator honoring the TTL (that's m4/t001); admin-side global defaults.
