feat: align RU validation, error contract, and generator runtime templates
Wire DSL-derived field labels, safe API error JSON (string|string[]), decimal/enum DTO fixes, and client dataProvider without comma-splitting. Add generation/templates/runtime as canonical source copied on generate; extend AID bundle, prompts, validation gate, and docs.
This commit is contained in:
28
server/src/common/field-labels.generated.ts
Normal file
28
server/src/common/field-labels.generated.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/** AUTO-GENERATED from domain DSL (generation/generate.mjs). Do not edit by hand. */
|
||||
export const FIELD_LABELS: Record<string, string> = {
|
||||
"code": "Код вида оборудования",
|
||||
"commissionedAt": "Дата ввода в эксплуатацию",
|
||||
"completedAt": "Фактическая дата завершения",
|
||||
"contractor": "Подрядная организация (если внешний ремонт)",
|
||||
"description": "Описание работ / дефекта",
|
||||
"engineHoursAtRepair": "Наработка на момент ремонта, моточасов",
|
||||
"engineHoursSinceLastRepair": "Наработка с последнего ремонта, моточасов",
|
||||
"equipmentId": "Оборудование",
|
||||
"equipmentTypeCode": "Вид оборудования",
|
||||
"id": "Идентификатор",
|
||||
"inventoryNumber": "Инвентарный номер",
|
||||
"lastRepairAt": "Дата последнего ремонта",
|
||||
"location": "Место эксплуатации / скважина / куст",
|
||||
"maintenanceIntervalHours": "Периодичность ТО, моточасов",
|
||||
"manufacturer": "Производитель",
|
||||
"name": "Наименование единицы оборудования",
|
||||
"notes": "Примечания",
|
||||
"number": "Номер заявки",
|
||||
"overhaulIntervalHours": "Периодичность КР, моточасов",
|
||||
"plannedAt": "Плановая дата начала",
|
||||
"repairKind": "Вид ремонта",
|
||||
"serialNumber": "Заводской (серийный) номер",
|
||||
"startedAt": "Фактическая дата начала",
|
||||
"status": "Текущий статус",
|
||||
"totalEngineHours": "Общая наработка, моточасов",
|
||||
};
|
||||
@@ -12,7 +12,7 @@ import { Request, Response } from 'express';
|
||||
|
||||
type ErrorResponseBody = {
|
||||
statusCode: number;
|
||||
message: string;
|
||||
message: string | string[];
|
||||
code: string;
|
||||
details?: unknown;
|
||||
path: string;
|
||||
@@ -39,8 +39,10 @@ export class ApiExceptionFilter implements ExceptionFilter {
|
||||
};
|
||||
|
||||
if (mapped.statusCode >= 500) {
|
||||
const logDetail =
|
||||
exception instanceof Error ? exception.message : String(mapped.message);
|
||||
this.logger.error(
|
||||
`Unhandled error on ${request.method} ${request.url}: ${mapped.message}`,
|
||||
`Unhandled error on ${request.method} ${request.url}: ${logDetail}`,
|
||||
exception instanceof Error ? exception.stack : undefined,
|
||||
);
|
||||
}
|
||||
@@ -50,7 +52,7 @@ export class ApiExceptionFilter implements ExceptionFilter {
|
||||
|
||||
private mapException(exception: unknown): {
|
||||
statusCode: number;
|
||||
message: string;
|
||||
message: string | string[];
|
||||
code: string;
|
||||
details?: unknown;
|
||||
} {
|
||||
@@ -74,9 +76,11 @@ export class ApiExceptionFilter implements ExceptionFilter {
|
||||
}
|
||||
|
||||
const rawMessage = payload?.message ?? exception.message;
|
||||
const message = Array.isArray(rawMessage)
|
||||
? rawMessage.join(', ')
|
||||
: rawMessage || exception.message;
|
||||
const message: string | string[] = Array.isArray(rawMessage)
|
||||
? rawMessage.map((m) => String(m))
|
||||
: typeof rawMessage === 'string' && rawMessage.length > 0
|
||||
? rawMessage
|
||||
: String(exception.message ?? 'Bad Request');
|
||||
|
||||
return {
|
||||
statusCode,
|
||||
@@ -118,21 +122,26 @@ export class ApiExceptionFilter implements ExceptionFilter {
|
||||
if (exception instanceof Error) {
|
||||
return {
|
||||
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
message: exception.message || 'Internal server error',
|
||||
message: 'Внутренняя ошибка сервера.',
|
||||
code: 'INTERNAL_ERROR',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
message: 'Internal server error',
|
||||
message: 'Внутренняя ошибка сервера.',
|
||||
code: 'INTERNAL_ERROR',
|
||||
};
|
||||
}
|
||||
|
||||
private mapPrismaKnownRequestError(
|
||||
exception: Prisma.PrismaClientKnownRequestError,
|
||||
) {
|
||||
): {
|
||||
statusCode: number;
|
||||
message: string;
|
||||
code: string;
|
||||
details?: unknown;
|
||||
} {
|
||||
switch (exception.code) {
|
||||
case 'P2002': {
|
||||
const target = Array.isArray(exception.meta?.target)
|
||||
|
||||
Reference in New Issue
Block a user