As far as I can tell deploying firmware updates is still a risky business as there is a risk of bricking the device by accidentally uploading the wrong firmware etc.
You can "package" your firmware along with some "headers", including a checksum of the application code. When you upload the firmware package to the device, it checks the headers to ensure that it is intended for this device, and that the checksum is correct. At this point youre in a good place and only need to program the newly received code into the device flash.
If youre not doing that at a minimum, then youre just opening yourself up to programming the wrong firmware in. Certainly it would seem to be a fairly common practice in my experience.
At the moment if you want a fail safe system then you have to roll your own solution by co-locating another micro which has the sole purpose of receiving firmware and reprogramming the target chip. The system I'm currently using uses a STM32F042 to manage a SAMD21 (https://omzlo.com/articles/canzero). It works but it's requires a bunch of code to make it work as there don't appear to be any standards for kind of thing (I could be wrong).
This can easily be done with a single micro. The method I have been using is to "partition" the micros internal flash into two: one partition (just several KB in size) holds the bootloader code, and the rest of it holds the application code. The partitions are sized accordingly so that neither of them crosses a flash page erasure boundary, so in theory they are both safe from each other as long as something catastrophic doesnt go wrong during erase operations.
I use an external SPI EEPROM to hold new application code, because flash based SPI EEPROMs are dirt cheap.
On boot, the bootloader compares a version number of the loaded application code and the externally stored application code, and if they are different, and if a checksum of the stored application code checks out OK, it erases the application area of the internal flash and programs the externally stored version in.
Before jumping into the application code, whether an upgrade was just performed or not, the bootloader checksums the loaded application code to make sure it isnt corrupt. If its OK, it jumps into it, if its not OK then it can attempt to load in the externally stored version as above. If both the internal and external application code are corrupt, well, youre kind of screwed at that point, so I just flash "SOS" on a status LED.