feat: add OpenTelemetry observability, Faro frontend monitoring, remove legacy Next.js app

- Add OpenTelemetry SDK with tracing, metrics, and OTLP export for API and worker
- Integrate Grafana Faro for frontend real-user monitoring
- Instrument health checks, database, Bull queues, and HTTP exception filter
- Add Grafana dashboard JSON for service overview
- Remove deprecated apps/web-nj (Next.js) — fully replaced by Vite+React frontend
- Update nginx config with OTEL collector proxy
- Minor UI fixes in schema viewer, category components, and subscription flow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sase Dev
2026-02-16 17:20:49 +00:00
parent 87d8eea298
commit dcbeb83ccc
113 changed files with 2745 additions and 7351 deletions

View File

@@ -1,4 +1,5 @@
import { ConnectionOptions } from "bullmq";
import { isOtelEnabled } from "../telemetry";
export function getBullConnection(): ConnectionOptions {
return {
@@ -8,6 +9,17 @@ export function getBullConnection(): ConnectionOptions {
};
}
export function getBullTelemetry() {
if (!isOtelEnabled) return undefined;
try {
const { BullMQOtel } = require("bullmq-otel");
return new BullMQOtel("sase");
} catch (err) {
console.warn("[otel] BullMQ telemetry unavailable:", (err as Error).message);
return undefined;
}
}
export const QUEUE_NAMES = {
EMEX_SCRAPE: "emex-scrape",
SUBSCRIPTION_EXPIRY: "subscription-expiry",

View File

@@ -1,14 +1,16 @@
import { Provider } from "@nestjs/common";
import { Queue } from "bullmq";
import { getBullConnection, QUEUE_NAMES } from "../bull.config";
import { getBullConnection, getBullTelemetry, QUEUE_NAMES } from "../bull.config";
export const EMEX_SCRAPE_QUEUE = "EMEX_SCRAPE_QUEUE";
export const EmexScrapeQueueProvider: Provider = {
provide: EMEX_SCRAPE_QUEUE,
useFactory: () => {
const telemetry = getBullTelemetry();
return new Queue(QUEUE_NAMES.EMEX_SCRAPE, {
connection: getBullConnection(),
...(telemetry ? { telemetry } : {}),
defaultJobOptions: {
attempts: 3,
backoff: {

View File

@@ -1,14 +1,16 @@
import { Provider } from "@nestjs/common";
import { Queue } from "bullmq";
import { getBullConnection, QUEUE_NAMES } from "../bull.config";
import { getBullConnection, getBullTelemetry, QUEUE_NAMES } from "../bull.config";
export const QUERY_CLEANUP_QUEUE = "QUERY_CLEANUP_QUEUE";
export const QueryCleanupQueueProvider: Provider = {
provide: QUERY_CLEANUP_QUEUE,
useFactory: () => {
const telemetry = getBullTelemetry();
return new Queue(QUEUE_NAMES.QUERY_CLEANUP, {
connection: getBullConnection(),
...(telemetry ? { telemetry } : {}),
defaultJobOptions: {
attempts: 2,
backoff: {

View File

@@ -1,14 +1,16 @@
import { Provider } from "@nestjs/common";
import { Queue } from "bullmq";
import { getBullConnection, QUEUE_NAMES } from "../bull.config";
import { getBullConnection, getBullTelemetry, QUEUE_NAMES } from "../bull.config";
export const SUBSCRIPTION_EXPIRY_QUEUE = "SUBSCRIPTION_EXPIRY_QUEUE";
export const SubscriptionExpiryQueueProvider: Provider = {
provide: SUBSCRIPTION_EXPIRY_QUEUE,
useFactory: () => {
const telemetry = getBullTelemetry();
return new Queue(QUEUE_NAMES.SUBSCRIPTION_EXPIRY, {
connection: getBullConnection(),
...(telemetry ? { telemetry } : {}),
defaultJobOptions: {
attempts: 3,
backoff: {