v0.38.0

2 November 2026

Users are stored in shard folders by uuid, and the cache per value all is now none.

Added

  • phlat user:migrate moves data/users/{username} folders to data/users/{shard}/{uuid} and saves each folder's name as its username. Run phlat registry:rebuild afterwards.
  • $app->users($query) takes a find query: $app->users('role=admin,sort=-created').
  • UserCollection::first(), last() and nth() return ?User.

Changed

  • A user is stored at data/users/{shard}/{uuid}, where the shard is the first two characters of the uuid. The username is kept in _index.json.
  • $app->user($username) finds the account through the registry and returns null for anything that is not a valid username. Logging in needs the registry; phlat registry:rebuild restores it.
  • User::new() checks the username under a lock and throws ConflictException when it is taken.
  • A user's registry path is {shard}/{uuid}, and $app->users() sorts by username. $user->name() returns the uuid: use $user->username.
  • per: 'none' replaces per: 'all' in {cache}, {fragment}, {component} and a view's cache. Cache and SessionRoot take none the same way.

Removed

  • The built-in guest user. A signed-out visitor still holds the guest role, and site/roles/guest still overrides it.