feat(portal-shell): wire environment.ts per ADR-0018
Create `src/environments/environment.ts` holding the two SPA per-environment values referenced by ADR-0018: `bffApiBaseUrl` (default `http://localhost:3000/api`) and `otlpEndpoint` (default `http://localhost:4318/v1/traces`). The dev defaults match the current local Docker compose stack — `nx serve portal-shell` keeps working unchanged. Replace the hard-coded URLs at the two call sites: - `observability/tracing.ts` reads `environment.otlpEndpoint` for the OTLP exporter, and derives the `propagateTraceHeaderCorsUrls` regex from `environment.bffApiBaseUrl` — a future deploy-time change to the BFF origin propagates `traceparent` to the right place automatically. - `home-status.service.ts` builds the `/health` URL as `${environment.bffApiBaseUrl}/health`. Per-environment siblings (`environment.staging.ts`, `environment.prod.ts`) and the `fileReplacements` configuration in `project.json` land later — explicitly out of scope today per the ADR ("ship later"); their values are not known yet and dropping plausible-but-wrong production URLs into the repo would be worse than waiting for the infrastructure ADR.
This commit is contained in:
@@ -2,6 +2,7 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { toSignal } from '@angular/core/rxjs-interop';
|
||||
import { catchError, map, of } from 'rxjs';
|
||||
import { environment } from '../../../environments/environment';
|
||||
|
||||
export interface BackendHealth {
|
||||
status: 'ok';
|
||||
@@ -21,13 +22,12 @@ export type HomeStatus =
|
||||
* stack (CORS, OTel trace propagation, Pino log correlation —
|
||||
* everything we wired in the observability foundation PRs).
|
||||
*
|
||||
* The base URL is hard-coded for now; it moves to Angular's
|
||||
* `environment.ts` mechanism with the env-config PR (same one that
|
||||
* will host the OTLP endpoint).
|
||||
* The BFF base URL comes from `environment.ts` (per ADR-0018); the
|
||||
* per-environment build target swaps the file via `fileReplacements`.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class HomeStatusService {
|
||||
private static readonly HEALTH_URL = 'http://localhost:3000/api/health';
|
||||
private static readonly HEALTH_URL = `${environment.bffApiBaseUrl}/health`;
|
||||
private readonly http = inject(HttpClient);
|
||||
|
||||
readonly status = toSignal(
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Per-environment configuration for the SPA, per ADR-0018.
|
||||
*
|
||||
* This file holds the **dev defaults** and is the one checked in.
|
||||
* Per-environment siblings (`environment.staging.ts`,
|
||||
* `environment.prod.ts`) land alongside this file later; the
|
||||
* production / staging build configurations in `project.json` declare
|
||||
* a `fileReplacements` entry that swaps this file for the target one
|
||||
* at build time.
|
||||
*
|
||||
* Constraint: every sibling must export an `environment` object of
|
||||
* the same shape. TypeScript will catch missing keys at the
|
||||
* consuming site once a sibling exists.
|
||||
*
|
||||
* Nothing here is a secret. The SPA is a static bundle; secrets that
|
||||
* ever needed to live here would, by definition, be public. Per-user
|
||||
* / per-tenant secrets live in the BFF session payload (ADR-0010).
|
||||
*/
|
||||
export const environment = {
|
||||
/**
|
||||
* Origin + prefix of the BFF HTTP API. The SPA prepends this to
|
||||
* every backend call (`${bffApiBaseUrl}/health`, etc.) and derives
|
||||
* the OTel trace-header propagation pattern from its origin (see
|
||||
* `observability/tracing.ts`).
|
||||
*/
|
||||
bffApiBaseUrl: 'http://localhost:3000/api',
|
||||
|
||||
/**
|
||||
* OTLP/HTTP traces endpoint. Targets the Collector in
|
||||
* `infra/local/dev.compose.yml`. CORS is enabled there — see
|
||||
* `infra/local/otel-collector.yaml`.
|
||||
*/
|
||||
otlpEndpoint: 'http://localhost:4318/v1/traces',
|
||||
};
|
||||
@@ -30,12 +30,9 @@
|
||||
*
|
||||
* Endpoint configuration
|
||||
* ──────────────────────
|
||||
* The OTLP/HTTP endpoint is hard-coded for v1 because env vars do
|
||||
* not flow into the browser bundle natively (Angular's
|
||||
* `environment.ts` mechanism is the standard alternative; we'll
|
||||
* adopt it when prod build needs it). The default targets the
|
||||
* Collector that ships in `infra/local/dev.compose.yml`. CORS is
|
||||
* enabled on that Collector receiver — see `otel-collector.yaml`.
|
||||
* The OTLP/HTTP endpoint and the BFF origin both come from
|
||||
* `src/environments/environment.ts` (per ADR-0018). Per-environment
|
||||
* siblings of that file ship under `fileReplacements`.
|
||||
*/
|
||||
|
||||
import { WebTracerProvider, BatchSpanProcessor } from '@opentelemetry/sdk-trace-web';
|
||||
@@ -47,16 +44,28 @@ import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
|
||||
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load';
|
||||
import { UserInteractionInstrumentation } from '@opentelemetry/instrumentation-user-interaction';
|
||||
|
||||
import { environment } from '../environments/environment';
|
||||
|
||||
const SERVICE_NAME = 'portal-shell';
|
||||
// Static for now; a follow-up wires this to the build-time version
|
||||
// (same source as the footer's dev-only version badge).
|
||||
const SERVICE_VERSION = 'dev';
|
||||
const OTLP_ENDPOINT = 'http://localhost:4318/v1/traces';
|
||||
|
||||
// Derive the trace-header propagation pattern from the BFF base URL
|
||||
// so a deploy-time change to `bffApiBaseUrl` automatically propagates
|
||||
// `traceparent` to the right origin. RegExp special chars are escaped
|
||||
// before going into the source.
|
||||
const bffOrigin = new URL(environment.bffApiBaseUrl).origin;
|
||||
const bffOriginRegex = new RegExp(`^${bffOrigin.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/.*`);
|
||||
|
||||
const provider = new WebTracerProvider({
|
||||
resource: resourceFromAttributes({
|
||||
[ATTR_SERVICE_NAME]: SERVICE_NAME,
|
||||
[ATTR_SERVICE_VERSION]: SERVICE_VERSION,
|
||||
}),
|
||||
spanProcessors: [new BatchSpanProcessor(new OTLPTraceExporter({ url: OTLP_ENDPOINT }))],
|
||||
spanProcessors: [
|
||||
new BatchSpanProcessor(new OTLPTraceExporter({ url: environment.otlpEndpoint })),
|
||||
],
|
||||
});
|
||||
|
||||
provider.register();
|
||||
@@ -65,13 +74,10 @@ registerInstrumentations({
|
||||
instrumentations: [
|
||||
// Times the initial page load — fires once.
|
||||
new DocumentLoadInstrumentation(),
|
||||
// Wraps every `fetch` call. Propagates `traceparent` to the
|
||||
// listed origins; the BFF dev server is the one we care about
|
||||
// today. Add prod origins once they exist.
|
||||
// Wraps every `fetch` call. Propagates `traceparent` to the BFF
|
||||
// origin derived from the environment.
|
||||
new FetchInstrumentation({
|
||||
propagateTraceHeaderCorsUrls: [
|
||||
/^http:\/\/localhost:3000\/.*/, // BFF dev server
|
||||
],
|
||||
propagateTraceHeaderCorsUrls: [bffOriginRegex],
|
||||
}),
|
||||
// Auto-spans on click / keypress / submit (and a small allow-list
|
||||
// beyond that). Quiet in dev, useful in staging perf
|
||||
|
||||
Reference in New Issue
Block a user