There are better explanations out there, but the short welcome-to-unicode-in-perl is:
You, the programmer, are responsible for knowing the encoding of all scalars within your program, usually by reading the documentation of every API you use and knowing the flags on your database connections and etc.
There is an internal utf-8 flag on every scalar, but it does not mean what you want it to mean. It is an implementation detail and you should never need to look at it unless you're writing C code.
You must never concatenate string-of-bytes with string-of-unicode. Convert them to matching encodings before concatenating.
If you have a string which you know to be encoded as UTF-8 bytes, and you need to pass it to a function that expects a unicode string, call decode('UTF-8', $octets, Encode::FB_CROAK) to get a string of characters.
If you have a string which you know contains unicode characters, and you need to pass it to a function that expects bytes, call encode('UTF-8', $characters, Encode::FB_CROAK) to get a string of bytes.
You can modify the string in-place with utf8::encode and utf8::decode, but beware that now you may have changed assumptions about what is in that string if it can be seen by other parts of the program. (such as encoding or decoding hash entries or global variables)
If you have a string and you don't know whether it is unicode or bytes, stop and refactor your program until you do know.
If you have a string and you really can't know whether it is unicode or bytes and you don't have time to refactor your program, call decode in a loop like while (utf8::decode($s)) {} which results in you definitely having a unicode string. There is a tiny chance that you break some unlikely sequence of characters that probably won't ever be seen in a real string of unicode. Now that you know you have a unicode string, you can call a single encode() to get the bytes you need.