diff --git a/backend/migrations/20251222000000-fix-vehicle-condition-null.cjs b/backend/migrations/20251222000000-fix-vehicle-condition-null.cjs new file mode 100644 index 0000000..76c79f8 --- /dev/null +++ b/backend/migrations/20251222000000-fix-vehicle-condition-null.cjs @@ -0,0 +1,60 @@ +/* eslint-disable */ +module.exports = { + async up(queryInterface, Sequelize) { + // Ensure column exists + await queryInterface.sequelize.query(` + ALTER TABLE falukant_data.vehicle + ADD COLUMN IF NOT EXISTS condition integer; + `); + + // Backfill nulls (legacy data) + await queryInterface.sequelize.query(` + UPDATE falukant_data.vehicle + SET condition = 100 + WHERE condition IS NULL; + `); + + // Clamp out-of-range values defensively + await queryInterface.sequelize.query(` + UPDATE falukant_data.vehicle + SET condition = GREATEST(0, LEAST(100, condition)) + WHERE condition < 0 OR condition > 100; + `); + + // Default + NOT NULL + await queryInterface.sequelize.query(` + ALTER TABLE falukant_data.vehicle + ALTER COLUMN condition SET DEFAULT 100; + `); + await queryInterface.sequelize.query(` + ALTER TABLE falukant_data.vehicle + ALTER COLUMN condition SET NOT NULL; + `); + + // Check constraint 0..100 + await queryInterface.sequelize.query(` + ALTER TABLE falukant_data.vehicle + DROP CONSTRAINT IF EXISTS vehicle_condition_0_100_chk; + `); + await queryInterface.sequelize.query(` + ALTER TABLE falukant_data.vehicle + ADD CONSTRAINT vehicle_condition_0_100_chk + CHECK (condition >= 0 AND condition <= 100); + `); + }, + + async down(queryInterface, Sequelize) { + // Keep the column, but remove constraint/default to be reversible + await queryInterface.sequelize.query(` + ALTER TABLE falukant_data.vehicle + DROP CONSTRAINT IF EXISTS vehicle_condition_0_100_chk; + `); + await queryInterface.sequelize.query(` + ALTER TABLE falukant_data.vehicle + ALTER COLUMN condition DROP DEFAULT; + `); + // NOT NULL not reverted to avoid introducing NULLs on rollback; can be adjusted if needed + }, +}; + + diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index a2edcac..674d2d6 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -922,7 +922,8 @@ class FalukantService extends BaseService { return { id: plain.id, - condition: plain.condition, + // Defensive: legacy DB rows can have NULL -> UI would display "Unbekannt" + condition: Math.max(0, Math.min(100, Number.isFinite(Number(plain.condition)) ? Number(plain.condition) : 100)), availableFrom: plain.availableFrom, status, type: { diff --git a/backend/utils/syncDatabase.js b/backend/utils/syncDatabase.js index f55991f..036fd0c 100644 --- a/backend/utils/syncDatabase.js +++ b/backend/utils/syncDatabase.js @@ -395,7 +395,27 @@ const syncDatabaseForDeployment = async () => { console.log(`✅ ${deletedCount8} verwaiste political_office Einträge entfernt`); } - if (deletedCount1 === 0 && deletedCount2 === 0 && deletedCount3 === 0 && deletedCount4 === 0 && deletedCount5 === 0 && deletedCount6 === 0 && deletedCount7 === 0 && deletedCount8 === 0) { + // Cleanup vehicle.condition: Legacy-Nulls + Range clamp (UI zeigt sonst "Unbekannt") + const result9 = await sequelize.query(` + UPDATE falukant_data.vehicle + SET condition = 100 + WHERE condition IS NULL; + `); + const updatedNullConditions = result9[1] || 0; + if (updatedNullConditions > 0) { + console.log(`✅ ${updatedNullConditions} vehicle.condition NULL → 100 gesetzt`); + } + const result10 = await sequelize.query(` + UPDATE falukant_data.vehicle + SET condition = GREATEST(0, LEAST(100, condition)) + WHERE condition < 0 OR condition > 100; + `); + const clampedConditions = result10[1] || 0; + if (clampedConditions > 0) { + console.log(`✅ ${clampedConditions} vehicle.condition Werte auf 0..100 geklemmt`); + } + + if (deletedCount1 === 0 && deletedCount2 === 0 && deletedCount3 === 0 && deletedCount4 === 0 && deletedCount5 === 0 && deletedCount6 === 0 && deletedCount7 === 0 && deletedCount8 === 0 && updatedNullConditions === 0 && clampedConditions === 0) { console.log("✅ Keine verwaisten Einträge gefunden"); } } catch (e) {