feat: чанкинг batch-create >100 задач + журнал ошибок API
B: BatchCreateDialog режет список на чанки ≤100 (лимит сервера), каждый чанк со своим idempotency-key (requestId-N) — повтор после ошибки не создаёт дублей; 10-минутный лок армируется только при полном успехе, а не до запроса (раньше блокировал даже после 400). D: таблица error_logs (миграция 0066), захват ответов >=400 в request middleware (без 401/health/events, дедуп 60с), admin API GET/DELETE /api/error-logs и вкладка «Журнал ошибок» в Настройках.
This commit is contained in:
@@ -3698,6 +3698,27 @@ export const idempotencyKeys = pgTable("idempotency_keys", {
|
||||
export type IdempotencyKey = typeof idempotencyKeys.$inferSelect;
|
||||
export type InsertIdempotencyKey = typeof idempotencyKeys.$inferInsert;
|
||||
|
||||
// =====================
|
||||
// Error Logs (серверный журнал ошибок API, просмотр админом в Настройках)
|
||||
// =====================
|
||||
|
||||
export const errorLogs = pgTable("error_logs", {
|
||||
id: serial("id").primaryKey(),
|
||||
organizationId: integer("organization_id").references(() => organizations.id, { onDelete: "cascade" }),
|
||||
userId: integer("user_id"),
|
||||
method: varchar("method", { length: 10 }).notNull(),
|
||||
path: text("path").notNull(),
|
||||
statusCode: integer("status_code").notNull(),
|
||||
message: text("message"),
|
||||
createdAt: timestamp("created_at").defaultNow(),
|
||||
}, (table) => ({
|
||||
orgCreatedIdx: index("error_logs_org_created_idx").on(table.organizationId, table.createdAt),
|
||||
statusIdx: index("error_logs_status_idx").on(table.statusCode),
|
||||
}));
|
||||
|
||||
export type ErrorLog = typeof errorLogs.$inferSelect;
|
||||
export type InsertErrorLog = typeof errorLogs.$inferInsert;
|
||||
|
||||
export const FINANCE_COLORS = [
|
||||
"#2563eb", "#e11d48", "#16a34a", "#f59e0b",
|
||||
"#8b5cf6", "#06b6d4", "#ea580c", "#84cc16",
|
||||
|
||||
Reference in New Issue
Block a user