---
id: w3/m1/t003
title: Live tail — GET /v1/logs/subscribe (follow)
worker: worker3
status: done
estimate: 40m
depends_on: [w3/m1/t001]
---

## Objective

Stream new log lines live (the dashboard's live-tail) via a follow endpoint over the same `Core.Logs` backend.

## Context

- client-go `PodLogOptions{Follow: true}` yields a streaming reader per pod; fan-in across replicas into one ordered stream.
- Transport: SSE is simplest over the existing HTTP server (`operator/internal/api/server.go`); WebSocket if a bidirectional handshake is preferred to match Render's `/subscribe`.
- Must respect the same bearer auth as other routes (`operator/internal/api/auth.go`).

## Steps

1. Add a follow mode to the logs backend (t001) that opens streaming `GetLogs` readers per replica.
2. Add `GET /v1/logs/subscribe` in `rest.go`/`server.go` emitting SSE (or WS) frames of normalized lines.
3. Handle client disconnect, pod churn (new/removed replicas), and heartbeat/keepalive.

## Files

- `operator/internal/api/logs.go`, `operator/internal/api/rest.go`, `operator/internal/api/server.go`

## Acceptance criteria

- [ ] `GET /v1/logs/subscribe?resource=<app>` streams new lines as they are produced.
- [ ] New/removed replicas are picked up without restarting the stream.
- [ ] Bearer auth enforced; clean shutdown on client disconnect.

## Out of scope

- Historical query (t002), GraphQL, durable buffering/replay.
