# Beacon Observe — Product Requirements (v1.0)

An observability service for engineering teams: metric time series for services and environments, stat panels, deploy annotations, a searchable log explorer with level facets, and alert rules that evaluate live, with silences. This release exposes the service as an HTTP API over a frozen synthetic dataset whose clock stands at 30 Sep 2026 12:00 UTC.

**Problem.** During an incident, on-call engineers need to see quickly what changed, when and where, and trust that charts, stats, logs and alerts all tell the same story on the same time axis.

## Users
- **On-call engineer** — See the error spike, the deploy that preceded it and the logs that explain it, then confirm the alert and its state.
- **Service owner** — Define alert rules that fire only on sustained breaches and silence them during maintenance.
- **Dashboard builder** — Pull series with a sensible resolution for any time range.

## Goals
- Time series are aligned to the requested window and use a resolution that keeps each series to a few hundred points.
- Alerts fire only when the whole for-window breaches the threshold, and silences hide only active alerts.
- Log facets always describe the whole result set for the other filters, not just the visible level.
- Each caller session keeps its own rules, silences and dashboards.

## Environment metadata (META)

Published facts the client needs to build its controls.

- **FR-META-01** (Must) The meta endpoint publishes the clock, services, environments, metrics, ranges and the incident window.
  - The frozen now is 1790769600000 (30 Sep 2026 12:00:00 UTC)
  - Services are api-gateway, checkout, search and auth; environments production and staging; metrics latency_p95, rps, error_rate and cpu
  - There are 8 relative ranges from 15m to 7d
  - The incident is on service "checkout" from 09:40Z to 10:05Z on that day

## Time series (SER)

Metric values over a time window, per service and environment.

- **FR-SER-01** (Should) The resolution step adapts to the range so a series has at most about 720 points.
  - 15m: step 15000 ms and 61 points
  - 1h: step 15000 ms and 241 points; error_rate carries unit "%"; the last checkout value is 0.61
  - 6h: step 60000 ms; without a service filter four series come back, one per service, 361 points each
  - 7d: step 900000 ms and 673 points
  - Steps are 15 s up to 3 h, then 1 m, 5 m, 15 m and 1 h as the range grows
- **FR-SER-02** (Must) Series timestamps are aligned to the window: the first point is at from and the last is at to, never beyond now.
  - For range 1h the first timestamp is now minus 3,600,000 ms and the last timestamp is now (1790769600000)
  - Every timestamp is a whole number of steps after the first, so a spike plots at its real time
- **FR-SER-03** (Should) The checkout incident shows in the error rate only inside its window and only in production.
  - Before 09:40Z values are about 0.5-0.7; from 09:40Z to 10:05Z every value is between 7.5 and 11.5 (peak 11.42); after 10:05Z they return to about 0.5-0.7
  - In staging there is no spike (maximum 0.62)
- **FR-SER-04** (Should) An unsupported metric, an unknown service or an inverted window is rejected with 422.
  - Metric mem: 422 "metric must be one of latency_p95, rps, error_rate, cpu"
  - Service billing: 422 Unknown service "billing"
  - from after to: 422 "from must be before to"
- **FR-SER-05** (Should) The window is clamped: the end never exceeds now and the start never goes back more than 7 days.
  - An end in the future is returned as now (1790769600000)
  - A start earlier than 7 days before now is returned as now minus 7 days

## Stat panels (STA)

Current, average and maximum of a metric per service over a range.

- **FR-STA-01** (Should) Stats report current, average and maximum per service for the chosen range.
  - error_rate over 6h (current / avg / max): checkout 0.61 / 1.24 / 11.42; api-gateway 0.37 / 0.4 / 0.46; search 0.32 / 0.3 / 0.34; auth 0.19 / 0.2 / 0.23
  - Over 1h checkout is 0.61 / 0.59 / 0.68 because the incident is outside the window; other services are unchanged

## Deploy annotations (ANN)

Deploy markers to overlay on charts.

- **FR-ANN-01** (Could) Annotations list the deploys within the range, bracketing the incident.
  - Over 6h there are two deploys, both of checkout: one by release-bot at 09:38Z and a rollback fix by m.ito at 10:02Z
  - Over 7d there are four deploys, adding one for search on 29 Sep and one for auth on 28 Sep

## Log explorer (LOG)

Search logs by service, time, level and text, with level facets.

- **FR-LOG-01** (Should) Logs for a service and window come back newest first and expose the root cause of the incident.
  - Checkout logs from 09:40Z to 10:05Z: 68 items, facets DEBUG 0, INFO 0, WARN 0, ERROR 68
  - The first item is level ERROR, message "NullPointerException in CartPricer.apply", traceId "9cfe2913"
- **FR-LOG-02** (Should) A level filter narrows the items but the facets still count every level; text search matches message or trace id; limit caps the items.
  - Last hour, level ERROR: 15 items, all ERROR; facets DEBUG 135, INFO 510, WARN 61, ERROR 15
  - Text "502" in the last hour: 2 items; facets INFO 1, ERROR 1
  - Over 6h with limit 5: exactly 5 items

## Alert rules and silences (ALR)

Rules evaluated live against the series, with a for-window and silences.

- **FR-ALR-01** (Must) The seeded rules are evaluated at now and report state, current value and when they last fired.
  - AR-0001 "Checkout error budget burn": OK, current 0.61, last fired 10:05Z (1790762700000)
  - AR-0002 "Gateway latency": OK, current 134.45, never fired
  - AR-0003 "Search CPU saturation": OK, current 61.25, never fired
- **FR-ALR-02** (Could) An unsaved rule can be previewed without being stored; the operator is validated.
  - Checkout error_rate > 5 for 5 minutes previews as OK with current 0.61 and last fired 10:05Z
  - api-gateway latency_p95 < 1000 for 5 minutes previews as Firing with current 134.45
  - An operator other than > or < is rejected with 422 "service, metric, op (> or <) and numeric threshold are required"
  - Listing rules afterwards still shows only AR-0001 to AR-0003
- **FR-ALR-03** (Must) A rule can be created and silenced; while a silence extends beyond now the rule shows as Silenced.
  - Creating "Auth CPU low" (auth cpu < 100 for 5 minutes) answers 201 with a new id AR-NNNN and the rule is Firing
  - Creating a silence with until 2026-09-30T18:00:00Z answers 201 with an id SIL-NNNN
  - The rule then shows Silenced with silencedUntil "2026-09-30T18:00:00Z"
- **FR-ALR-04** (Should) A silence that ended before now has no effect.
  - A silence until 2026-09-30T11:00:00Z is accepted with 201
  - The rule still shows Firing and silencedUntil is null
- **FR-ALR-05** (Must) A rule fires only when every sample over its for-window breaches the threshold.
  - The rule "Auth latency creeping" (auth latency_p95 > 100 for 5 minutes) is OK with current 112.31, because the last two minutes breach 100 but the minutes 11:55 to 11:57 do not
  - The rule becomes Firing only once all samples of the 5-minute window breach
- **FR-ALR-06** (Should) Rules and silences reject missing required fields with 422.
  - A rule without service, metric, op and threshold: 422 naming the missing fields
  - A silence without ruleId and until: 422 naming the missing fields

## Session isolation (SES)

Callers can keep private rules, silences and dashboards.

- **FR-SES-01** (Should) Rules and silences created under one session identifier are not visible to another.
  - A rule created under session A does not appear under session B, which sees only AR-0001 to AR-0003

## Dashboards (DSH)

Saved collections of panels.

- **FR-DSH-01** (Could) A seeded overview dashboard has one panel per metric.
  - One dashboard, DB-0001 "Service overview", with panels latency_p95, rps, error_rate and cpu

## Non-functional requirements

- **NFR-01** (Must) The dataset is deterministic: the same request at the frozen clock always returns the same values, and times are exchanged as epoch milliseconds.

## Glossary and rules

- **For-window** — The number of minutes a threshold must be breached continuously before a rule fires.
- **Facet** — A count of log items per level.
- **Step** — The spacing between points in a series, in milliseconds.

## Out of scope

- Dashboard user interface
- Real data ingestion; data is synthetic and frozen
