feat(auth): add error logs API and database schema

Add centralized error logging endpoint to mana-core-auth:
- Error logs database schema with app_id, error message, stack traces
- POST /error-logs endpoint for single errors
- POST /error-logs/batch endpoint for batch submissions
- Error logs service with automatic cleanup of old entries
- DTOs with validation for error log submissions
This commit is contained in:
Wuesteon 2025-12-19 02:17:55 +01:00
parent 5e1118b711
commit 319ccd1a46
11 changed files with 527 additions and 0 deletions

View file

@ -0,0 +1,71 @@
-- Add error_logs schema and table for centralized error tracking
-- This migration is safe to run on existing databases
-- Create error_logs schema if not exists
CREATE SCHEMA IF NOT EXISTS "error_logs";
-- Create enum types if not exist (PostgreSQL 9.1+ required for IF NOT EXISTS)
DO $$ BEGIN
CREATE TYPE "error_source_type" AS ENUM('backend', 'frontend_web', 'frontend_mobile');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "error_environment" AS ENUM('development', 'staging', 'production');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "error_severity" AS ENUM('debug', 'info', 'warning', 'error', 'critical');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- Create error_logs table
CREATE TABLE IF NOT EXISTS "error_logs"."error_logs" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"error_code" text NOT NULL,
"error_type" text NOT NULL,
"message" text NOT NULL,
"stack_trace" text,
"app_id" text NOT NULL,
"source_type" "error_source_type",
"service_name" text,
"user_id" text,
"session_id" text,
"request_url" text,
"request_method" text,
"request_headers" jsonb,
"request_body" jsonb,
"response_status_code" integer,
"environment" "error_environment",
"severity" "error_severity" DEFAULT 'error',
"context" jsonb DEFAULT '{}'::jsonb,
"fingerprint" text,
"user_agent" text,
"browser_info" jsonb,
"device_info" jsonb,
"occurred_at" timestamp with time zone NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
-- Add foreign key constraint (safe - ignores if exists)
DO $$ BEGIN
ALTER TABLE "error_logs"."error_logs"
ADD CONSTRAINT "error_logs_user_id_users_id_fk"
FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id")
ON DELETE set null ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- Create indexes (safe - ignores if exists)
CREATE INDEX IF NOT EXISTS "error_logs_app_id_idx" ON "error_logs"."error_logs" USING btree ("app_id");
CREATE INDEX IF NOT EXISTS "error_logs_user_id_idx" ON "error_logs"."error_logs" USING btree ("user_id");
CREATE INDEX IF NOT EXISTS "error_logs_environment_idx" ON "error_logs"."error_logs" USING btree ("environment");
CREATE INDEX IF NOT EXISTS "error_logs_severity_idx" ON "error_logs"."error_logs" USING btree ("severity");
CREATE INDEX IF NOT EXISTS "error_logs_occurred_at_idx" ON "error_logs"."error_logs" USING btree ("occurred_at");
CREATE INDEX IF NOT EXISTS "error_logs_error_code_idx" ON "error_logs"."error_logs" USING btree ("error_code");
CREATE INDEX IF NOT EXISTS "error_logs_fingerprint_idx" ON "error_logs"."error_logs" USING btree ("fingerprint");

View file

@ -22,6 +22,13 @@
"when": 1734560000000,
"tag": "0002_fix_session_columns",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1734600000000,
"tag": "0003_add_error_logs",
"breakpoints": true
}
]
}

View file

@ -0,0 +1,97 @@
import {
pgSchema,
uuid,
text,
timestamp,
jsonb,
integer,
index,
pgEnum,
} from 'drizzle-orm/pg-core';
import { users } from './auth.schema';
export const errorLogsSchema = pgSchema('error_logs');
// Source type enum
export const errorSourceTypeEnum = pgEnum('error_source_type', [
'backend',
'frontend_web',
'frontend_mobile',
]);
// Environment enum
export const errorEnvironmentEnum = pgEnum('error_environment', [
'development',
'staging',
'production',
]);
// Severity enum
export const errorSeverityEnum = pgEnum('error_severity', [
'debug',
'info',
'warning',
'error',
'critical',
]);
// Error logs table
export const errorLogs = errorLogsSchema.table(
'error_logs',
{
// Primary key
id: uuid('id').primaryKey().defaultRandom(),
// Error identification
errorCode: text('error_code').notNull(),
errorType: text('error_type').notNull(),
message: text('message').notNull(),
stackTrace: text('stack_trace'),
// Source identification
appId: text('app_id').notNull(),
sourceType: errorSourceTypeEnum('source_type'),
serviceName: text('service_name'),
// User context (optional)
userId: text('user_id').references(() => users.id, { onDelete: 'set null' }),
sessionId: text('session_id'),
// Request metadata (backend errors)
requestUrl: text('request_url'),
requestMethod: text('request_method'),
requestHeaders: jsonb('request_headers'),
requestBody: jsonb('request_body'),
responseStatusCode: integer('response_status_code'),
// Classification
environment: errorEnvironmentEnum('environment'),
severity: errorSeverityEnum('severity').default('error'),
// Additional context
context: jsonb('context').default({}),
fingerprint: text('fingerprint'),
// Browser/device info (frontend errors)
userAgent: text('user_agent'),
browserInfo: jsonb('browser_info'),
deviceInfo: jsonb('device_info'),
// Timestamps
occurredAt: timestamp('occurred_at', { withTimezone: true }).notNull(),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
},
(table) => ({
appIdIdx: index('error_logs_app_id_idx').on(table.appId),
userIdIdx: index('error_logs_user_id_idx').on(table.userId),
environmentIdx: index('error_logs_environment_idx').on(table.environment),
severityIdx: index('error_logs_severity_idx').on(table.severity),
occurredAtIdx: index('error_logs_occurred_at_idx').on(table.occurredAt),
errorCodeIdx: index('error_logs_error_code_idx').on(table.errorCode),
fingerprintIdx: index('error_logs_fingerprint_idx').on(table.fingerprint),
})
);
// Type exports
export type ErrorLog = typeof errorLogs.$inferSelect;
export type NewErrorLog = typeof errorLogs.$inferInsert;

View file

@ -1,5 +1,6 @@
export * from './auth.schema';
export * from './credits.schema';
export * from './error-logs.schema';
export * from './feedback.schema';
export * from './organizations.schema';
export * from './referrals.schema';