Note: this whole story is written about migrating from J!3 to J!4 and changing the template from (a modified copy of) Protostar to Cassiopeia. If you're using another template, a lot of stuff after the actual migration will probably be different.

Right, it's time to do my first migration...
Chose the simplest site I've made, early in 2018.  The template is a copy of Protostar. It does use a custom font, though. There are no users.

Here's the Step by Step I need to follow: J3 to J4 Step By Step.
Read the Self Assessment. I should be good to go.
Read the Planning for Migration. No problems there, I think.

Set up a local "migration" folder

You need a place to temporarily store files that need to be moved from the old site to the new one (e.g. custom fonts, favicons) and files that need to be modified and then moved (e.g. htaccess, user.css).

Check user.css

Download user.css to the local folder. Do a general check. Remove all the menu-css (won't work anyway, and a lot of it is native Cassiopeia).
Save user.css for use after migration.

Freeze the live site

No problem in this case. It's a pretty static site.
If any changes do come up, they'll have to wait until after the migration (or I'll have to do them twice).

Set up Dev Location

Created a subdomain on my own website, and created a shiny new database.
Moved the J!3 site to the subdomain using the Akeeba .jpa file and Kickstart.
Did a backup.
Check database schema
Structure is up to date.
Empty trash
For articles, categories, menu's and modules. Easy in this case, trash was empty.

Pre-update Checker

There were some "left overs" from old Akeeba versions (fofs and fefs, stuff like that). Akeeba has developed a tool to remove them, the Magic Eraser. I ran it, and it did an excellent job of removing the left overs.
All the other stuff can be simply uninstalled:

  • Dutch Language pack - I can uninstall that, and there is a working version for J!4.
  • RL Emailprotector - can be uninstalled. J!4 has it's own native Emailprotector.
  • MySites plugin - needs to be removed, the site will be added back to MySites after migration.
  • Top-of-the-page plugin - can be uninstalled. J!4 has it's own native To-top.

Dutch Language pack

Checked for overrides (there weren't any).
Set default language to English for front & backend.
Uninstalled Dutch language pack.

The plugins

Uninstalled them. No issues.

The template

Set Protostar as default.
Remove all other templates, frontend (Beez and my copy of Protostar), and backend (Hathor).

Run a backup

Turn on error reporting

Check pre-update checker one more time, just in case

Good to go.
We're going to update to 4.0.3.

Hit update...

Step-by-step says: make tea... But for this site, it didn't take very long.
Read post-installation messages. Activated HTTP Security Headers.
Install Akeeba 9 (the J4 version). Let it convert the settings from Akeeba 8. Run Configuration Wizard. Run a backup. Interesting: the new jpa backup file is about twice as large as the old one.
Uninstall Akeeba 8.
Set the Atum Style to one of the site's main colors and add the site's logo. 🤣
Pfff...

So far, so good 😊 🍷
Have a glass of wine.

Check extensions

Upload and install any extensions that have a J!4 version (if you had to remove the J!3 version).

Check TinyMCE

Make sure Joomla Text Filtering is ON, at least for the sets that will be used on the site. (Note: the migration process does not retain the settings you had in J!3).

Language

If the Dutch language pack was uninstalled before upgrade, and is necessary on the site, re-install it (and set as default).

Make new .htaccess

The standard htaccess.txt that comes with J!4 is not the same as the J!3 one. (See Github).
The migration process, however, dutifully copies your old .htaccess to your new J!4 installation.
So: remove the J!3 .htaccess, add any "personal" rules to the J!4 htaccess.txt, rename it to .htaccess, upload to J!4 root folder.
In this case, I added the rule to rewrite www to non-www (which I copied from Developer Mozilla).

Position modules

Go to the modules list, and reassign all your modules to Cassiopeia positions.
Set the style for your Main Menu module - I set Cassiopeia Collapsible Dropdown.

Favicon

Get the old site's favicon.ico. Get an SVG version of the favicon, rename it to joomla-favicon.svg. Make a copy of this, and rename it to joomla-favicon-pinned.svg.
Upload these three files to cassiopeia/images.

Fonts

If used, upload any custom fonts to templates/cassiopeia/fonts. The @font-face rules in the old user.css should still work.
If used: set Cassiopeia's style to use Roboto as font.

Rework the CSS

This is actually the part I was dreading the most...

Transfer the old user.css from your local migration folder - checked and modified in an earlier step - to Cassiopeia. The site is now starting to look more like itself again but there's a lot of CSS tweaking to be done.
The CSS for custom modules still works nicely, though sometimes you need to add a class, or modify the selector slightly.

And then start checking page by page, adding custom css rules as you go along.
Backup regularly!

Ready?

Make a final backup, save a copy off-site. Transfer a copy of the  .jpa to your local migration-folder.

Replace J!3

Log in to the J!3 site, run a final backup, save a copy off-site.
Take a deep breath.
In the hoster's C-Panel, delete the J!3 database and remove all the files.
Create a new database for the J!4 site.
Upload the J!4 definitive .jpa file plus Kickstart.
Run Kickstart.

Check everything.
Backup.
If error reporting is still on, turn it off again.
Check in Global that robots.txt is set to index and follow.
If you hadn't done so already, set a custom Output Directory for Akeeba.
If required, register the J!4 site with MySites.guru.

Done!