class Vehicle { /// Hidden, immutable, generated primary key — never shown in the UI and /// never editable. This is what fuel entries actually reference and what /// sync merges on, so that [vin] itself is free to be edited without /// breaking those references or losing sync history. final String id; /// The vehicle's identification number. Required and must be unique /// among active (non-deleted) vehicles, but — unlike [id] — the user can /// edit it later (e.g. to fix a typo from a misread VIN scan). final String vin; /// User-chosen label, e.g. "Mom's Car" or "Red Ford F-150". Optional — /// when absent, screens fall back to other identifying info instead. final String? nickname; final DateTime updatedAt; /// Soft-delete tombstone: null means active. Deleting sets this instead /// of removing the row, so the deletion itself can be merged/synced like /// any other change (newest `updatedAt` wins) instead of silently /// disappearing and later being resurrected by a device that hasn't seen /// the deletion yet. final DateTime? deletedAt; Vehicle({ required this.id, required this.vin, required this.updatedAt, this.nickname, this.deletedAt, }); /// What screens should show as the vehicle's primary label: the nickname /// if one was given, otherwise the VIN itself. String get displayLabel { final trimmedNickname = nickname?.trim(); if (trimmedNickname != null && trimmedNickname.isNotEmpty) { return trimmedNickname; } return vin; } /// Note: [id] is intentionally not overridable here — it's the hidden /// identifier, not an editable field. Vehicle copyWith({ String? vin, String? nickname, bool clearNickname = false, DateTime? updatedAt, DateTime? deletedAt, }) { return Vehicle( id: id, vin: vin ?? this.vin, nickname: clearNickname ? null : (nickname ?? this.nickname), updatedAt: updatedAt ?? this.updatedAt, deletedAt: deletedAt ?? this.deletedAt, ); } Map toMap() => { 'id': id, 'vin': vin, 'nickname': nickname, 'updated_at': updatedAt.millisecondsSinceEpoch, 'deleted_at': deletedAt?.millisecondsSinceEpoch, }; factory Vehicle.fromMap(Map map) => Vehicle( id: map['id'] as String, vin: map['vin'] as String, nickname: map['nickname'] as String?, updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updated_at'] as int, isUtc: true), deletedAt: map['deleted_at'] != null ? DateTime.fromMillisecondsSinceEpoch(map['deleted_at'] as int, isUtc: true) : null, ); }