Skip to content

Merging Individuals

  • When merging is the right move (and when it isn’t)
  • How the merge picker, conflict resolution, and confirmation work
  • What happens to each kind of related record (encounters, annotations, images, relationships)
  • How merge audit logging works and what it records
  • Permission gates and recovery options when something goes wrong

Merging is the right action when two existing individual records turn out to be the same animal. The classic case: a contributor cataloged a juvenile under one identifier, the population’s primary catalog independently recognized it as the offspring of a known matriarch and gave it a different code, and only later did a confirmed match link the two.

Merging is not the right action when:

  • An individual’s identifier needs to change → use the edit drawer on its profile.
  • Two records refer to similar-looking but distinct animals → keep both records; if your evidence doesn’t support a confident match, don’t merge.
  • You want to consolidate alternate IDs that already point at the same record → just edit the alternate IDs on the existing record.

Open the profile page of the individual you want to merge away (the source). Below the profile management section, you’ll see a Merge Profile button.

The button only renders for users with Professional or Administrator roles in the population — it’s a destructive operation and not exposed to lower roles.

Clicking Merge Profile expands an inline panel below the button:

  1. Pick the target. A dropdown loads every individual in the population. Choose the one you want to keep — the target. The current animal you’re on is the source and will be removed.
  2. Review conflicts. If both records have a value for the same field (e.g. both have a nickname, or both have a birth year), each conflict appears as a radio choice: keep the source’s value or keep the target’s. The target’s value is selected by default.
  3. Review the auto-fill summary. Fields where only one side has a value (e.g. source has a birth year and target doesn’t) are listed as “will fill” — they fill the gap on the target without asking. Fields where neither side has a value are skipped.
  4. Continue. Click Continue to open the confirmation dialog.
  5. Confirm. The dialog warns: “This will permanently move all data from {source} to {target} and delete {source}. This action cannot be undone.” Click Confirm Merge to proceed.
  6. Wait briefly. A spinner runs while the merge service walks every related record type. On success, you’re redirected to the target’s profile with a success toast. On failure, you stay on the source profile with an error notification.
Record typeWhat happens
EncounterAnimals (sighting links)All transferred. Deduplicated by (encounter, evidenceTier) so the target doesn’t end up with two identical sightings on one encounter. Different evidence tiers are kept side-by-side.
AnnotationsAll transferred. Bounding boxes, side, category, confirmation state — every annotation that pointed at the source now points at the target.
AnimalImages (raw image attachments)All transferred.
AnimalProfileImages (active profile-image picks)Target wins on Side+Category collisions; source fills any gaps. So if the source had a Left dorsal fin profile image and the target didn’t, the target gains it; if both had a Left dorsal fin pick, the target’s pick stays.
AnimalFileContextsAll transferred.
Catalog graph relationshipsAll edges that pointed at the source are re-pointed at the target. Edges are deduplicated in both directions, so if the source and target shared an edge with the same partner, the result has one edge, not two.
Public artifactsAll transferred.
Deferred notificationsAll transferred so nothing pending gets dropped.
FieldBehaviour
IdentifierTarget wins. The source’s identifier is appended to the target’s alternate IDs so it remains searchable.
Alternate IDsUnion of both lists, plus the source’s old primary identifier. The target’s own primary identifier is removed from the alt list if it had been there.
SexIf both have values and they conflict, you pick at merge time. If one is empty, the non-empty value fills the gap.
NicknameSame rule as sex.
Birth date / Death dateSame rule as sex.
Age classSame rule as sex.
NotesConcatenated with a separator: {target notes}\n\n--- Merged from {source identifier} ---\n{source notes}. Both sides survive in the merged record.
NeedsReview flagLogical OR — if either record was flagged for review, the merged record is too.

The conflict-resolution UI shows you exactly what your choice will produce, so the radio selection plus the auto-fill summary is the full preview.

Every merge writes a complete audit record via the animal-merge audit service. The record captures:

  • Source and target animal IDs and identifiers
  • The user who performed the merge (id and username)
  • A unique merge ID for cross-referencing
  • A state machine: Started → Completed (with summary) or Started → Failed (with exception details)
  • Per-type record counts — how many EncounterAnimals, Annotations, AnimalImages, relationships, and public artifacts moved

If the merge fails partway through, the record is marked Failed with the exception, and the operation rolls back at the database level. You’ll see an error notification in the UI and the source animal will remain intact.

If you ever need to investigate “where did Animal X’s data go?”, the audit trail is the source of truth.

Two notifications fire as part of the merge:

  • Post-merge — a confirmation that the merge completed, including the source and target identifiers, sent through the standard notification system to the user who initiated the merge.
  • On failure — an error notification with enough detail to either retry or escalate.

Both notifications respect each user’s notification preferences.

ActionRequired role
See the Merge Profile button on a profileProfessional or Administrator
Pick a target and run the mergeProfessional or Administrator
Initiate a merge from the population’s individual listSame — but the entry point in the list is the row-actions menu’s “View Profile” → then the merge button

The backend enforces the same role check, so the UI’s role gate isn’t the only line of defence. A user without sufficient role calling the merge API directly is rejected with a permission error.