Skip to content

Import deduplication

Every imported booking is tagged with a short fingerprint that identifies its source row. When you import again — whether it is the same file, a newer export from the same system, or a mixture of old and new rows — Syndik8 skips any row whose fingerprint already exists on a booking in this syndicate.

This makes re-imports safe. You do not have to manually filter a CSV to “only the new bookings”.

Deduplication runs automatically during every import. Admin and owner see the skipped-count on the review step; there is no user toggle.

The behaviour is part of the import wizard:

  • Route: /syndicates/:syndicateId/settings/import-bookings.
  • The review step shows a line like 3 rows will be skipped when any are being skipped — expand the warnings list to see why each was skipped.

The fingerprint is also written into the booking’s notes field as a small tag, e.g. [Import: <batch-id> | <fingerprint>], so you can inspect it on an individual booking.

The fingerprint is computed from these row values, concatenated in order:

InputHow it is normalised
Start timeISO 8601 in UTC.
End timeISO 8601 in UTC.
Member keyEmail if the row has one (lowercased); otherwise display name (lowercased); otherwise empty.
Aircraft registrationLowercased as-is from the CSV — not stripped to alphanumeric.

The four values are joined with a | separator and hashed with FNV-1a (32-bit). The hash is written as lowercase hex (for example 1a3f7c90).

Line on the review stepMeaning
N rows skippedTotal skipped across all reasons.
N duplicates skippedSkipped because the fingerprint already exists in this syndicate.
N unmatched skippedSkipped because the member could not be matched and no invite was issued. (Not a dedupe reason, but shown alongside.)
N warningsRows with a problem worth flagging but not fatal.
  • Deduplication is per syndicate. A booking imported into syndicate A does not block the same booking from being imported into syndicate B. Fingerprints are scoped.
  • The fingerprint is deterministic across devices. Importing the same CSV on Chrome, iOS, or Android produces the same fingerprints for the same rows. (FNV-1a was chosen precisely because Dart’s built-in String.hashCode varies by platform.)
  • Times are compared in UTC. A Goboko row in Europe/London at 10:00 BST and the same row after a timezone-preserving export fingerprint-match because both convert to 09:00 UTC before hashing.
  • Name-only matches still dedupe. A row without an email uses its lowercased display name as the member key. Two different people with the same name at the same aircraft at the same time would collide — a rare case that requires the admin to adjust the second import.
  • Registration is compared as-written. Unlike asset matching (which strips punctuation), the fingerprint keeps hyphens. G-BBBN and GBBBN will not fingerprint-match even though they resolve to the same aircraft. In practice, both forms rarely appear in the same source system — but if your CSV has moved between formats, you may re-import apparent duplicates once.
  • Deduplication applies before member matching. A duplicate row is skipped regardless of whether its member would match, so re-importing a file after updating membership does not re-create previously imported bookings.
  • Manually deleting a booking does not clear its fingerprint. The booking row is soft-deleted but the fingerprint tag remains; to re-import that exact row after a deletion, remove the matching booking from the database or alter the source CSV.
  • Fingerprints are additive, not cryptographic. FNV-1a is not a security primitive; it is a short, stable, cross-platform hash. Collisions are rare but possible in very large imports — if two distinct rows ever collide, the second would be skipped silently. The rate of collision is negligible for realistic syndicate sizes.