Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ency07/B2B/llms.txt

Use this file to discover all available pages before exploring further.

ERP B2B Premium exposes a health check API, uses a structured logger with pluggable transports, and instruments slow operations with a timing utility. In development the default transport writes to the console; in production, swap in a Sentry or Datadog transport via setTransport() at application startup.

Health check API

The health check is implemented at src/app/api/health/route.ts as a Next.js App Router route handler.

Basic check — GET /api/health

Returns 200 OK as long as the Node.js process is running. This is the endpoint polled by Docker and uptime monitors.
{
  "status": "ok",
  "timestamp": "2026-06-22T14:30:00.000Z",
  "uptime": 3600.5,
  "node": "v22.1.0",
  "memory": {
    "rss": 45678,
    "heapTotal": 12345,
    "heapUsed": 9876
  }
}

Full check — GET /api/health?full=true

Adds a live Supabase connectivity check by querying the tenants table. Use this endpoint for synthetic monitors that need to verify end-to-end database access. 200 — healthy:
{
  "status": "ok",
  "timestamp": "2026-06-22T14:30:00.000Z",
  "uptime": 3600.5,
  "node": "v22.1.0",
  "memory": { "rss": 45678, "heapTotal": 12345, "heapUsed": 9876 },
  "supabase": "connected"
}
503 — degraded (Supabase error or unreachable):
{
  "status": "degraded",
  "timestamp": "2026-06-22T14:30:00.000Z",
  "uptime": 3600.5,
  "node": "v22.1.0",
  "memory": { "rss": 45678, "heapTotal": 12345, "heapUsed": 9876 },
  "supabase": "error"
}
The supabase field can be "connected", "error" (Supabase returned a query error), or "unreachable" (the import or network call threw an exception).

Docker health check

The Dockerfile registers a built-in health check using the basic endpoint:
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
After three consecutive failures within 30-second intervals, Docker marks the container unhealthy, triggering a restart policy or alerting your orchestrator.

Structured logging

All application code must use createLogger from src/lib/utils/logger.ts instead of console.* calls.

Creating a module logger

import createLogger from "@/lib/utils/logger";

const log = createLogger("catalog");

log.info("Fetching catalog", { data: { tenantCode } });
log.warn("Cache miss — querying database");
log.error("Catalog fetch failed", { error: err, data: { tenantCode } });

Log format

Every log line follows the pattern:
[ISO_TIMESTAMP] [LEVEL] [MODULE] message {data}
Example output:
[2026-06-22T14:30:00.123Z] [WARN] [perf] Slow operation: catalog-fetch {"elapsedMs":342}
[2026-06-22T14:30:01.000Z] [ERROR] [catalog] Catalog fetch failed {"tenantCode":"acme"}

Log levels

LevelMethodWhen to use
debuglog.debug()Detailed trace information — development only
infolog.info()Normal operational events
warnlog.warn()Unexpected conditions that don’t block execution
errorlog.error()Failures that require attention

Swapping the transport for production

The default transport writes to console.*. Replace it with a Sentry or Datadog transport at application startup (e.g. in src/instrumentation.ts):
import { setTransport } from "@/lib/utils/logger";
import * as Sentry from "@sentry/nextjs";

setTransport((entry) => {
  if (entry.level === "error") {
    Sentry.captureMessage(entry.message, {
      level: "error",
      extra: { module: entry.module, ...entry.data },
    });
  }
  // forward all levels to Datadog, etc.
});
See the Logger reference page for the full LogEntry type and child() logger usage.

Performance timing

Use startTimer from src/lib/utils/timing.ts to instrument any operation that may be slow. The utility automatically emits a warn-level log entry when the operation exceeds 300 ms.
import { startTimer } from "@/lib/utils/timing";

const timer = startTimer("catalog-fetch");
const catalog = await getIndustrialCatalog(tenantCode);
const elapsedMs = timer.stop(); // logs warning if > 300ms
stop() accepts an optional extra object (Record<string, unknown>) that is merged into the log entry, and returns the elapsed time in milliseconds so you can include it in your own response metrics. Wrap all slow Server Actions — catalog fetches, wizard submissions, report generation — with startTimer so that performance regressions surface automatically in the log stream.

Error classes

AppError at src/lib/utils/app-error.ts is the canonical typed error for the entire application.

Error codes

CodeWhen to use
VALIDATION_ERRORInvalid or malformed input
AUTH_ERRORUnauthenticated request / expired session
FORBIDDENAuthenticated but not authorized
NOT_FOUNDResource does not exist
RATE_LIMITEDToo many requests
TENANT_MISMATCHCross-tenant data access attempt
INTERNAL_ERRORUnexpected server error (default)

Server Action response convention

All Server Actions use toActionResponse() from app-error.ts to wrap any promise and convert thrown AppError instances into a discriminated union:
import { toActionResponse } from "@/lib/utils/app-error";

const { data, error } = await toActionResponse(someAsyncOperation());

if (error) {
  // error is an AppError instance with .code, .statusCode, and .message
  console.error(error.code, error.message);
} else {
  // data is the resolved value
}
toActionResponse catches thrown AppError instances and returns them as { data: null, error: AppError }. Any other thrown value is wrapped in a new AppError with code INTERNAL_ERROR before being returned. Configure the following alerts in your monitoring stack:
MetricThresholdPriority
Catalog fetch latency> 1 secondHigh
Wizard submission error rate> 5 %High
Slow DB queries (timing utility warnings)> 300 msMedium
GET /api/health?full=true responseNon-200Critical
npm audit — high+ vulnerabilitiesAnyHigh
ToolRole
SentryError tracking, stack traces, release tracking
DatadogMetrics, APM, log aggregation, dashboards
UptimeRobot / Better UptimeExternal synthetic monitor for /api/health?full=true
GitHub DependabotAutomated security PRs (already configured in .github/dependabot.yml)

Build docs developers (and LLMs) love