- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import { db } from '../db';
|
|
import { systemAuditLog } from '@shared/schema';
|
|
|
|
export interface AuditEntry {
|
|
action: string;
|
|
userId?: number | null;
|
|
organizationId?: number | null;
|
|
taskId?: number | null;
|
|
details?: Record<string, unknown> | null;
|
|
ip?: string | null;
|
|
userAgent?: string | null;
|
|
}
|
|
|
|
/**
|
|
* Write a system audit log entry asynchronously (fire-and-forget).
|
|
* A write failure is logged to console but never throws — it must not
|
|
* interrupt the primary action.
|
|
*/
|
|
export function logAudit(entry: AuditEntry): void {
|
|
db.insert(systemAuditLog)
|
|
.values({
|
|
action: entry.action,
|
|
userId: entry.userId ?? null,
|
|
organizationId: entry.organizationId ?? null,
|
|
taskId: entry.taskId ?? null,
|
|
details: entry.details ?? null,
|
|
ip: entry.ip ?? null,
|
|
userAgent: entry.userAgent ?? null,
|
|
})
|
|
.catch(err => {
|
|
console.error('[audit] Failed to write system audit log:', err);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Extract the client IP address from an Express request,
|
|
* honouring the X-Forwarded-For header (trust proxy must be enabled).
|
|
*/
|
|
export function getClientIp(req: { ip?: string; headers: Record<string, string | string[] | undefined> }): string | null {
|
|
const forwarded = req.headers['x-forwarded-for'];
|
|
if (forwarded) {
|
|
const first = Array.isArray(forwarded) ? forwarded[0] : forwarded.split(',')[0];
|
|
return first.trim() || null;
|
|
}
|
|
return req.ip ?? null;
|
|
}
|