The IV is normally stored with the ciphertext. It is not derived from some other secret. To decrypt some encrypted data, all you need to know is the key and the encrypted data.
because without the correct salt/iv. The data would be nonsense.
I'm not sure what you're trying to say. If you're thinking “if someone has the key but not the IV, then they can't decrypt the data”, this is not necessarily true. It depends on the encryption mode and on the partial knowledge that the adversary has about the data. If you want to protect against decryption, the key must be secret.
make sure that the data on the frontend can only be encrypted if the correct user is logged in
To do this, arrange for the encryption key to be “unlocked” when the user logs in. How to do this depends on how users log in. Remember to take into account both what happens on a normal login, what happens on a resumed session (if that's a thing), and what happens for account recovery (e.g. lost password), as well as what happens when the user's authentication method changes (password change).
If users authenticate with a password, here's a common design. Use the password as input to a key stretching function to calculate a user master key $K_m$. A key stretching function is essentially the same as a password hashing function which is used to check that the user provided the expected password: it applies a slow transformation to the password, to reduce the rate at which the output can be guessed by brute force. For password hashing, the expected output is stored in the user database. For key stretching, the output is not stored anywhere, and is used as a key.
To encrypt some data associated with the user, generate a random key $K_d$ for your data encryption method, and encrypt the data with that key. If $K_d$ is used to encrypt more than once, use a random IV/nonce; if you generate a unique $K_d$ each time you encrypt some data, the IV/nonce can be fixed (e.g. always 0). Either way, you'll need to recover $K_d$ to decrypt the data later, so store a copy of $K_d$ encrypted with $K_m$. The next time the user logs in, you'll calculat the same $K_m$ again from their password, which will allow you to decrypt the encrypted copy of $K_m$, which will allow you to decrypt the data.
When the user changes their password, $K_m$ will change. Decrypt the saved encrypted copy of $K_d$ with the old $K_m$ and write a copy of $K_m$ encrypted with the new $K_m$. Don't forget to securely wipe the old encrypted copy, since it would be a vulnerability if the user's old password became known (and that may be a reason why the user is changing their password).
If the user can authenticate by some method other than their password, you may need to keep other copies of $K_m$ “locked” by the other authentication method. For example, if you have a lost password procedure, you'll need to make a choice between telling the user that all their encrypted data is lost, or having a way to recover $K_d$. One possible way to offer a way to recover $K_d$ is to generate a random key $K_r$, save a copy of $K_d$ encrypted with $K_r$, and provide the user with a “recovery code” (a long string that they should print and save securely) which allows you to recover $K_r$ (you would not store $K_r$ itself).
Coming back to the IV for each piece of encrypted data, as I've explained above, it isn't secret. So you just store it with the rest of the ciphertext.
As for choosing an encryption mode, the best choice is Libsodium's
crypto_secretbox or a similar API. Let a cryptographer decide what algorithm is best. If you need to know the mode, for example because you need a ciphertext format that is interoperable between multiple pieces of software, ChaCha20-Poly1305 and AES-GCM are two popular choices. SIV variants are better if your library provides them, but they're still relatively new and not available everywhere. Avoid unauthenticated modes like CBC and CTR: they're older and harder to use, and the lack of authentication can open you to subtle attacks.