## Problem
Auth observability charts always queried the legacy logs.all endpoint,
even when the OTEL reports rollout was enabled. The existing OTEL SQL
also had ClickHouse correctness and parity gaps around timestamp
aliasing, JSON types, provider paths, missing values, and error-code
attributes.
## Fix
Route the ten Auth-specific charts through the OTEL query builders and
logs.all.otel endpoint when otelReports is enabled. Preserve the
BigQuery fallback, partition React Query caches by backend, and leave
the shared API gateway charts on the legacy endpoint.
Correct the OTEL queries by qualifying source timestamps, using typed
and nullable JSON extraction, preserving missing actor and duration
semantics, selecting the right provider path for each event shape,
preferring the canonical Auth error-code attribute with a legacy
fallback, and applying bounded result limits. Two-minute report
intervals now use minute-level SQL buckets instead of falling through to
hourly buckets.
## How to test
- Run `CI=1 pnpm --filter studio exec vitest run
data/reports/v2/auth.config.otel.test.ts
hooks/misc/__tests__/useReportDateRange.test.ts`
- Run `pnpm --filter studio run lint:ratchet`
- Run `pnpm --filter studio run typecheck`
- Expected result: all checks pass and generated OTEL SQL preserves
legacy report semantics.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Auth observability charts can now use OpenTelemetry data when enabled,
while retaining the existing reporting source otherwise.
- Switching the data source automatically refreshes the relevant charts.
- **Bug Fixes**
- Improved Auth observability accuracy for provider, duration, actor,
and error-code reporting.
- Added safeguards to keep report queries within the supported result
limit.
- Corrected minute-level grouping for two-minute analytics intervals and
three-hour date ranges.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
Part of DEBUG-73 (migrate reports queries to the OTEL/ClickHouse
endpoint).
The Auth report's v2 metrics (ActiveUsers, SignInAttempts,
PasswordResetRequests, TotalSignUps, sign-in/sign-up processing time,
error breakdowns) currently only query the BigQuery-backed logs.all
endpoint.
## Fix
Adds `AUTH_REPORT_SQL_OTEL`, a ClickHouse-dialect mirror of the existing
`AUTH_REPORT_SQL`, covering all 10 metrics. Threads a `useOtel`
parameter through `fetchLogs` and the three report config creators
(`createUsageReportConfig`, `createErrorsReportConfig`,
`createLatencyReportConfig`), defaulting to `false` everywhere.
This PR is inert on its own: nothing yet passes `useOtel: true`, so it
changes no runtime behavior. The follow-up PR (stacked on this one)
wires the `otelReports` feature flag through the Auth report page to
actually select the OTEL SQL.
Also includes: one dataProvider now validates its raw rows with a Zod
schema instead of casting to `any`, and removal of a few functions in
this file that had zero callers (`AUTH_ERROR_CODE_VALUES`,
`createAuthReportConfig`, an exact duplicate of a status-code color map,
an unused hook).
## How to test
- Unit: `cd apps/studio && npx vitest run
data/reports/v2/auth.config.otel.test.ts`
- No manual testing needed for this PR alone since it changes no runtime
behavior (useOtel defaults to false, unwired). The follow-up PR covers
manual testing of the actual flag-gated behavior.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added OpenTelemetry-backed authentication reports.
* Authentication reports now include usage, errors, latency, sign-ins,
sign-ups, and edge-log metrics.
* Added filtering by provider, status code, action, and time range.
* Added selectable telemetry sources for retrieving report logs.
* **Bug Fixes**
* Improved validation of authentication error codes.
* Improved handling of missing report data with consistent empty
results.
* Improved report formatting for more consistent attribute display.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
PR 10 of the analytics SQL safety series. Migrates the last surface of
analytics queries that flowed through plain
`get(.../analytics/endpoints/logs.all, { query: { sql } })` or the
`fetchLogs(projectRef, sql: string, ...)` helper over to
`executeAnalyticsSql` with branded `SafeLogSqlFragment` inputs.
After this PR, every analytics SQL call site builds its query through
the safe-analytics-sql helpers and hits the wire through the single
`executeAnalyticsSql` boundary. User-controlled values (filter
operators, numeric thresholds, function IDs, regions, provider names)
all flow through `analyticsLiteral` / branded operator maps; static
fragments are wrapped in `safeSql`. PR 11 (ESLint / vitest rule
forbidding direct analytics-endpoint POST/GET outside
`executeAnalyticsSql`) is the next and final step.
## Changes
- **`hooks/analytics/useProjectUsageStats.tsx`** — route the
already-branded `genChartQuery` output through `executeAnalyticsSql`
(parallels `useLogsPreview`).
- **`data/reports/report.utils.ts`** — tighten `fetchLogs(sql)` from
`string` to `SafeLogSqlFragment`; the wire boundary is now the same
single `executeAnalyticsSql` wrapper used by the rest of the analytics
path. Adds two pre-branded fragment maps reused by the report configs:
- `SAFE_GRANULARITY_SQL` — closed set returned by
`analyticsIntervalToGranularity`.
- `SAFE_COMPARISON_OPERATOR_SQL` — closed set on
`NumericFilter.operator`.
- **`components/interfaces/Auth/Overview/OverviewErrors.constants.ts`**
— wrap the two static `AUTH_TOP_*_SQL` fragments in `safeSql` (no
interpolation, but the type now flows).
- **`data/reports/v2/edge-functions.config.ts`** — `filterToWhereClause`
and every entry in `METRIC_SQL` now return `SafeLogSqlFragment`.
User-controlled values (`status_code.value`, `execution_time.value`,
function IDs, regions) pass through `analyticsLiteral`; operators look
up the branded map; the granularity uses the branded map. The
wire-format strings are unchanged, so the existing
`edge-functions.test.tsx` exact-string expectations still hold.
- **`data/reports/v2/auth.config.ts`** — same shape applied to all ten
`AUTH_REPORT_SQL` entries. The legacy `whereClause.replace(/^WHERE\s+/,
'')` pattern is replaced by two helpers that emit `AND`-prefixed
predicate fragments directly (`authFiltersToAndPredicates`,
`edgeLogsFiltersToAndPredicates`). Static provider SELECT / GROUP BY
fragments are pre-branded.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Enhanced security for analytics and reporting queries by updating
query construction methods across auth, edge functions, and project
usage reports.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46476?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Changes
- Replaces plan ID-based chart gating with entitlement-based checks
across all observability pages (database, auth, realtime,
edge-functions)
- Adds requiredPlan display field so the upsell shows the correct target
plan (e.g. "Upgrade to Team" for disk throughput, not just "Upgrade")
- Decouples database-charts.ts from Organization Plan, now accepts
pre-computed entitlement flags instead
### Note on `requiredPlan`
The entitlement system currently tells us whether a user has access, but
not what plan they need to get access. `requiredPlan` is a frontend-only
display hint. Ideally the backend entitlement response would include a
minimumPlan field so we can remove this hardcoded mapping. For now, this
is a pragmatic workaround to avoid misleading upsell copy (e.g. a Free
user seeing "Upgrade" for a Team-only feature and landing on Pro).
## Testing
### Database
- Head to `/project/_/observability/database` with an Org on the Free
Plan and assert that the Disk throughput is gated.
<img width="1402" height="682" alt="image"
src="https://github.com/user-attachments/assets/b783d866-774d-44dc-88d1-797d26502f02"
/>
### Auth
- Head to `/project/_/observability/auth` with an Org on the Free Plan
and assert that the following metrics are gated:
<img width="1402" height="682" alt="image"
src="https://github.com/user-attachments/assets/cb062dd7-5864-4e40-a11f-ad6be1f7fd41"
/>
### Edge Functions
- Head to `/project/_/observability/edge-functions` with an Org on the
Free Plan and assert that the following metrics are gated:
<img width="1402" height="320" alt="image"
src="https://github.com/user-attachments/assets/517b5483-4575-493c-9401-2c67ac9e684c"
/>
### Realtime
- Head to `/project/_/observability/realtime` with an Org on the Free
Plan and assert that the following metrics are gated:
<img width="1402" height="722" alt="image"
src="https://github.com/user-attachments/assets/0c2757a2-8482-43f4-a65c-c0dde3d878c7"
/>