I did the thing. I was moving fast, setting up a fresh instance, and I put the admin password somewhere it could be read. Nobody malicious saw it as far as I can tell. But "as far as I can tell" is not a security posture, so I had to rotate it, and rotating it is where the story gets useful.
My first instinct was the lazy one. Change the password in the environment file, restart the container, done. The initial-admin seeder reads that value on boot and sets up the admin account, so surely restarting re-sets the password. I restarted. The old password still worked. The new one didn't.
The reason is that the seeder, at the time, only created the admin if it was missing. On an instance that already had one it left the existing account alone, which is correct behavior, it just wasn't what I needed. My "fix" did nothing. The old password was still live. (The seeder upserts now and rewrites the hash on every boot, so the restart I tried would work today. That change came later and is not what got me out of this.)
The tempting next move was to go into the database and overwrite the password hash by hand. I've done worse at 1am. But hand-editing auth data in production is how you lock yourself out of your own account, and it's the opposite of the point I'm trying to make with this project.
So I built the thing that was actually missing: a proper change-password endpoint. You send your current password and a new one. It verifies the current password, checks the new one against the complexity rules, and stores a fresh hash. There's an admin version too, for resetting someone else's. Both of them also revoke the account's refresh tokens, so a session that was open before the change can't be quietly refreshed afterward.
Then I used the endpoint to rotate my own password, the boring correct way, and the old one stopped working like it should have from the start.
The lesson I keep relearning is that the shortcut and the fix are often the same size. The database hack and the endpoint were both an evening's work. One leaves you with a hack you have to remember and a capability the product still lacks. The other leaves you with a feature every future user gets. I picked the hack first. I usually do. Writing it down is how I try to pick the feature first next time.