feat(diagnostics): add types.ts with session, trace, log, screenshot schemas
This commit is contained in:
parent
4163e1410a
commit
f51c352452
381
services/platform-service/src/modules/diagnostics/types.ts
Normal file
381
services/platform-service/src/modules/diagnostics/types.ts
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
/**
|
||||||
|
* Diagnostics types — remote debug session management.
|
||||||
|
*
|
||||||
|
* Cosmos containers:
|
||||||
|
* - debug_sessions (pk: /id, TTL: 7 days)
|
||||||
|
* - debug_traces (pk: /pk composite ${productId}:${sessionId}, TTL: 7 days)
|
||||||
|
* - debug_logs (pk: /pk composite ${productId}:${sessionId}, TTL: 3 days)
|
||||||
|
* - debug_screenshots (pk: /sessionId) — metadata only, images in Azure Blob
|
||||||
|
*
|
||||||
|
* @module diagnostics
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// Enums
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export const SessionStatusEnum = z.enum(['pending', 'active', 'paused', 'completed', 'cancelled']);
|
||||||
|
export type SessionStatus = z.infer<typeof SessionStatusEnum>;
|
||||||
|
|
||||||
|
export const CollectionLevelEnum = z.enum(['standard', 'debug', 'trace']);
|
||||||
|
export type CollectionLevel = z.infer<typeof CollectionLevelEnum>;
|
||||||
|
|
||||||
|
export const LogLevelEnum = z.enum(['debug', 'info', 'warn', 'error', 'fatal']);
|
||||||
|
export type LogLevel = z.infer<typeof LogLevelEnum>;
|
||||||
|
|
||||||
|
export const ScreenshotTriggerEnum = z.enum(['manual', 'error', 'interval', 'user_request']);
|
||||||
|
export type ScreenshotTrigger = z.infer<typeof ScreenshotTriggerEnum>;
|
||||||
|
|
||||||
|
export const SpanStatusEnum = z.enum(['ok', 'error', 'unset']);
|
||||||
|
export type SpanStatus = z.infer<typeof SpanStatusEnum>;
|
||||||
|
|
||||||
|
export const SpanKindEnum = z.enum(['internal', 'server', 'client', 'producer', 'consumer']);
|
||||||
|
export type SpanKind = z.infer<typeof SpanKindEnum>;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// DebugSessionDoc
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export interface DebugSessionDoc {
|
||||||
|
id: string;
|
||||||
|
productId: string;
|
||||||
|
|
||||||
|
// Target (at least one required)
|
||||||
|
targetUserId?: string;
|
||||||
|
targetAnonymousId?: string;
|
||||||
|
targetDeviceId?: string;
|
||||||
|
targetSessionId?: string;
|
||||||
|
|
||||||
|
// Status
|
||||||
|
status: SessionStatus;
|
||||||
|
|
||||||
|
// Collection config
|
||||||
|
collectionLevel: CollectionLevel;
|
||||||
|
captureLogs: boolean;
|
||||||
|
captureNetwork: boolean;
|
||||||
|
captureScreenshots: boolean;
|
||||||
|
screenshotOnError: boolean;
|
||||||
|
maxDurationMinutes: number;
|
||||||
|
|
||||||
|
// Timestamps
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
startedAt?: string;
|
||||||
|
endedAt?: string;
|
||||||
|
expiresAt: string;
|
||||||
|
|
||||||
|
// Stats (denormalized)
|
||||||
|
logCount: number;
|
||||||
|
traceCount: number;
|
||||||
|
screenshotCount: number;
|
||||||
|
|
||||||
|
// Audit
|
||||||
|
createdBy: string;
|
||||||
|
updatedBy?: string;
|
||||||
|
|
||||||
|
// Consent tracking
|
||||||
|
userConsent?: {
|
||||||
|
consentedAt: string;
|
||||||
|
consentMethod: 'prompt' | 'pre_consent' | 'auto';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// DebugTraceDoc (OpenTelemetry-compatible)
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export interface DebugTraceDoc {
|
||||||
|
id: string;
|
||||||
|
pk: string; // Composite: ${productId}:${sessionId}
|
||||||
|
sessionId: string;
|
||||||
|
productId: string;
|
||||||
|
|
||||||
|
// OTel context
|
||||||
|
traceId: string;
|
||||||
|
parentId?: string;
|
||||||
|
spanId: string;
|
||||||
|
name: string;
|
||||||
|
kind?: SpanKind;
|
||||||
|
|
||||||
|
// Timing
|
||||||
|
startTime: string;
|
||||||
|
endTime?: string;
|
||||||
|
durationMs?: number;
|
||||||
|
|
||||||
|
// Context
|
||||||
|
attributes: Record<string, unknown>;
|
||||||
|
status: SpanStatus;
|
||||||
|
statusMessage?: string;
|
||||||
|
|
||||||
|
// Events within span
|
||||||
|
events?: Array<{
|
||||||
|
name: string;
|
||||||
|
timestamp: string;
|
||||||
|
attributes?: Record<string, unknown>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
// Links to other traces
|
||||||
|
links?: Array<{
|
||||||
|
traceId: string;
|
||||||
|
spanId: string;
|
||||||
|
attributes?: Record<string, unknown>;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// DebugLogEntryDoc
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export interface DebugLogEntryDoc {
|
||||||
|
id: string;
|
||||||
|
pk: string; // Composite: ${productId}:${sessionId}
|
||||||
|
sessionId: string;
|
||||||
|
productId: string;
|
||||||
|
|
||||||
|
level: LogLevel;
|
||||||
|
message: string;
|
||||||
|
messageHash?: string;
|
||||||
|
|
||||||
|
// Timestamps
|
||||||
|
timestamp: string;
|
||||||
|
receivedAt?: string;
|
||||||
|
|
||||||
|
// Source context
|
||||||
|
module: string;
|
||||||
|
file?: string;
|
||||||
|
line?: number;
|
||||||
|
function?: string;
|
||||||
|
|
||||||
|
// Thread/task context
|
||||||
|
threadId?: string;
|
||||||
|
correlationId?: string;
|
||||||
|
|
||||||
|
// Context (PII-scanned)
|
||||||
|
context: Record<string, unknown>;
|
||||||
|
|
||||||
|
// PII redaction metadata
|
||||||
|
redaction?: {
|
||||||
|
fieldsRedacted: string[];
|
||||||
|
patternsMatched: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// DebugScreenshotDoc (metadata only)
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export interface DebugScreenshotDoc {
|
||||||
|
id: string;
|
||||||
|
sessionId: string;
|
||||||
|
productId: string;
|
||||||
|
|
||||||
|
// Blob storage reference
|
||||||
|
blobUrl: string;
|
||||||
|
blobPath: string;
|
||||||
|
containerName: string;
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
capturedAt: string;
|
||||||
|
trigger: ScreenshotTrigger;
|
||||||
|
|
||||||
|
// Dimensions
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
format: 'png' | 'jpeg' | 'webp';
|
||||||
|
sizeBytes: number;
|
||||||
|
|
||||||
|
// Privacy
|
||||||
|
sensitiveViewsBlurred: boolean;
|
||||||
|
blurRegions?: Array<{ x: number; y: number; w: number; h: number }>;
|
||||||
|
|
||||||
|
// Context
|
||||||
|
screenName?: string;
|
||||||
|
breadcrumbAtCapture?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// Input Schemas
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export const CreateDebugSessionSchema = z.object({
|
||||||
|
productId: z.string().min(1),
|
||||||
|
targetUserId: z.string().optional(),
|
||||||
|
targetAnonymousId: z.string().optional(),
|
||||||
|
targetDeviceId: z.string().optional(),
|
||||||
|
targetSessionId: z.string().optional(),
|
||||||
|
collectionLevel: CollectionLevelEnum.default('debug'),
|
||||||
|
captureLogs: z.boolean().default(true),
|
||||||
|
captureNetwork: z.boolean().default(true),
|
||||||
|
captureScreenshots: z.boolean().default(false),
|
||||||
|
screenshotOnError: z.boolean().default(true),
|
||||||
|
maxDurationMinutes: z.number().min(5).max(1440).default(60),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const UpdateDebugSessionSchema = z.object({
|
||||||
|
status: SessionStatusEnum.optional(),
|
||||||
|
collectionLevel: CollectionLevelEnum.optional(),
|
||||||
|
captureLogs: z.boolean().optional(),
|
||||||
|
captureNetwork: z.boolean().optional(),
|
||||||
|
captureScreenshots: z.boolean().optional(),
|
||||||
|
screenshotOnError: z.boolean().optional(),
|
||||||
|
maxDurationMinutes: z.number().min(5).max(1440).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ListDebugSessionsQuerySchema = z.object({
|
||||||
|
productId: z.string().optional(),
|
||||||
|
status: SessionStatusEnum.optional(),
|
||||||
|
targetUserId: z.string().optional(),
|
||||||
|
from: z.string().datetime().optional(),
|
||||||
|
to: z.string().datetime().optional(),
|
||||||
|
limit: z.coerce.number().min(1).max(100).default(20),
|
||||||
|
offset: z.coerce.number().min(0).default(0),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const IngestTracesSchema = z.object({
|
||||||
|
sessionId: z.string().min(1),
|
||||||
|
traces: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
traceId: z.string().min(1),
|
||||||
|
spanId: z.string().min(1),
|
||||||
|
parentId: z.string().optional(),
|
||||||
|
name: z.string().min(1),
|
||||||
|
kind: SpanKindEnum.optional(),
|
||||||
|
startTime: z.string().datetime(),
|
||||||
|
endTime: z.string().datetime().optional(),
|
||||||
|
durationMs: z.number().optional(),
|
||||||
|
attributes: z.record(z.unknown()).default({}),
|
||||||
|
status: SpanStatusEnum,
|
||||||
|
statusMessage: z.string().optional(),
|
||||||
|
events: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
name: z.string(),
|
||||||
|
timestamp: z.string().datetime(),
|
||||||
|
attributes: z.record(z.unknown()).optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
links: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
traceId: z.string(),
|
||||||
|
spanId: z.string(),
|
||||||
|
attributes: z.record(z.unknown()).optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.min(1)
|
||||||
|
.max(50),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const IngestLogsSchema = z.object({
|
||||||
|
sessionId: z.string().min(1),
|
||||||
|
logs: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
level: LogLevelEnum,
|
||||||
|
message: z.string().max(4096),
|
||||||
|
timestamp: z.string().datetime(),
|
||||||
|
module: z.string().min(1),
|
||||||
|
file: z.string().optional(),
|
||||||
|
line: z.number().optional(),
|
||||||
|
function: z.string().optional(),
|
||||||
|
threadId: z.string().optional(),
|
||||||
|
correlationId: z.string().optional(),
|
||||||
|
context: z.record(z.unknown()).default({}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.min(1)
|
||||||
|
.max(50),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CreateScreenshotMetadataSchema = z.object({
|
||||||
|
sessionId: z.string().min(1),
|
||||||
|
capturedAt: z.string().datetime(),
|
||||||
|
trigger: ScreenshotTriggerEnum,
|
||||||
|
width: z.number().positive(),
|
||||||
|
height: z.number().positive(),
|
||||||
|
format: z.enum(['png', 'jpeg', 'webp']),
|
||||||
|
sizeBytes: z.number().positive(),
|
||||||
|
sensitiveViewsBlurred: z.boolean(),
|
||||||
|
blurRegions: z
|
||||||
|
.array(z.object({ x: z.number(), y: z.number(), w: z.number(), h: z.number() }))
|
||||||
|
.optional(),
|
||||||
|
screenName: z.string().optional(),
|
||||||
|
breadcrumbAtCapture: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const QueryTracesSchema = z.object({
|
||||||
|
limit: z.coerce.number().min(1).max(200).default(50),
|
||||||
|
continuationToken: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const QueryLogsSchema = z.object({
|
||||||
|
level: LogLevelEnum.optional(),
|
||||||
|
from: z.string().datetime().optional(),
|
||||||
|
to: z.string().datetime().optional(),
|
||||||
|
search: z.string().max(256).optional(),
|
||||||
|
limit: z.coerce.number().min(1).max(200).default(50),
|
||||||
|
continuationToken: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// Inferred Types
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export type CreateDebugSessionInput = z.infer<typeof CreateDebugSessionSchema>;
|
||||||
|
export type UpdateDebugSessionInput = z.infer<typeof UpdateDebugSessionSchema>;
|
||||||
|
export type ListDebugSessionsQuery = z.infer<typeof ListDebugSessionsQuerySchema>;
|
||||||
|
export type IngestTracesInput = z.infer<typeof IngestTracesSchema>;
|
||||||
|
export type IngestLogsInput = z.infer<typeof IngestLogsSchema>;
|
||||||
|
export type CreateScreenshotMetadataInput = z.infer<typeof CreateScreenshotMetadataSchema>;
|
||||||
|
export type QueryTracesInput = z.infer<typeof QueryTracesSchema>;
|
||||||
|
export type QueryLogsInput = z.infer<typeof QueryLogsSchema>;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// Event Bus Event Types
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export interface DiagnosticsSessionCreatedEvent {
|
||||||
|
sessionId: string;
|
||||||
|
productId: string;
|
||||||
|
targetUserId?: string;
|
||||||
|
createdBy: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiagnosticsSessionUpdatedEvent {
|
||||||
|
sessionId: string;
|
||||||
|
productId: string;
|
||||||
|
changes: Partial<DebugSessionDoc>;
|
||||||
|
updatedBy: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiagnosticsSessionCancelledEvent {
|
||||||
|
sessionId: string;
|
||||||
|
productId: string;
|
||||||
|
reason?: string;
|
||||||
|
cancelledBy: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiagnosticsSessionCompletedEvent {
|
||||||
|
sessionId: string;
|
||||||
|
productId: string;
|
||||||
|
stats: {
|
||||||
|
logCount: number;
|
||||||
|
traceCount: number;
|
||||||
|
screenshotCount: number;
|
||||||
|
};
|
||||||
|
endedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiagnosticsIngestFatalEvent {
|
||||||
|
sessionId: string;
|
||||||
|
productId: string;
|
||||||
|
logEntry: DebugLogEntryDoc;
|
||||||
|
timestamp: string;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user