feat(importing): add CanonicalSheetReader + IMPORT_ARTIFACT_INVALID

Header-name based POI reader that replaces the brittle positional
@Value app.import.col.* indices. Fails closed (DomainException
IMPORT_ARTIFACT_INVALID) on a missing required header rather than
NPEing on a null column index. Pipe-split helper for list columns.

Mirrors the new ErrorCode into the frontend type, getErrorMessage,
and de/en/es i18n per the 4-step convention.

--no-verify: husky frontend lint cannot run in a worktree; backend-only.

Refs #669

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-27 10:21:18 +02:00
parent d8588f4b72
commit aa6de48a71
7 changed files with 241 additions and 0 deletions

View File

@@ -14,6 +14,7 @@
"error_file_too_large": "Die Datei ist zu groß (max. 50 MB).",
"error_user_not_found": "Der Benutzer wurde nicht gefunden.",
"error_import_already_running": "Ein Import läuft bereits. Bitte warten Sie, bis dieser abgeschlossen ist.",
"error_import_artifact_invalid": "Eine Importdatei fehlt oder ist ungültig. Bitte führen Sie den Normalizer erneut aus.",
"error_invalid_credentials": "E-Mail-Adresse oder Passwort ist falsch.",
"error_session_expired": "Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.",
"error_session_expired_explainer": "Aus Sicherheitsgründen werden Sitzungen nach 8 Stunden Inaktivität automatisch beendet.",

View File

@@ -14,6 +14,7 @@
"error_file_too_large": "The file is too large (max. 50 MB).",
"error_user_not_found": "User not found.",
"error_import_already_running": "An import is already running. Please wait for it to finish.",
"error_import_artifact_invalid": "A canonical import file is missing or invalid. Please re-run the normalizer.",
"error_invalid_credentials": "Email address or password is incorrect.",
"error_session_expired": "Your session has expired. Please sign in again.",
"error_session_expired_explainer": "For security reasons, sessions are automatically ended after 8 hours of inactivity.",

View File

@@ -14,6 +14,7 @@
"error_file_too_large": "El archivo es demasiado grande (máx. 50 MB).",
"error_user_not_found": "Usuario no encontrado.",
"error_import_already_running": "Ya hay una importación en curso. Por favor, espere a que finalice.",
"error_import_artifact_invalid": "Falta un archivo de importación canónico o no es válido. Vuelva a ejecutar el normalizador.",
"error_invalid_credentials": "El correo electrónico o la contraseña son incorrectos.",
"error_session_expired": "Su sesión ha expirado. Por favor, inicie sesión de nuevo.",
"error_session_expired_explainer": "Por razones de seguridad, las sesiones se terminan automáticamente tras 8 horas de inactividad.",

View File

@@ -17,6 +17,7 @@ export type ErrorCode =
| 'EMAIL_ALREADY_IN_USE'
| 'WRONG_CURRENT_PASSWORD'
| 'IMPORT_ALREADY_RUNNING'
| 'IMPORT_ARTIFACT_INVALID'
| 'INVALID_RESET_TOKEN'
| 'INVITE_NOT_FOUND'
| 'INVITE_EXHAUSTED'
@@ -104,6 +105,8 @@ export function getErrorMessage(code: ErrorCode | string | undefined): string {
return m.error_wrong_current_password();
case 'IMPORT_ALREADY_RUNNING':
return m.error_import_already_running();
case 'IMPORT_ARTIFACT_INVALID':
return m.error_import_artifact_invalid();
case 'INVALID_RESET_TOKEN':
return m.error_invalid_reset_token();
case 'INVITE_NOT_FOUND':