One boolean (Security > Public Registration) switches the whole public
signup lifecycle: front page + login links, the logged-out sidebar's
Create-an-account (via a package-level templates hook so shared page
templates keep their signatures), GET /register -> 302 /login, and an
early 403 on POST /api/auth/register. First-user exception preserved:
zero admins keeps every route and link reachable for bootstrapping —
same 'users exist' reasoning as the setup gate. Admin user creation is
unaffected by design.
Live E2E verified: flag off hides all surfaces and blocks the POST
(403), flag on restores them (201); the admin UI renders the row
automatically.
Regenerates all *_templ.go files after the templ generate pass (version
stamp updates across the board; functional changes only in
admin_archived_templ.go and admin_library_templ.go, which were committed
with their features). web/static/style.css and web/static/htmx.min.js are
refreshed outputs of npm run build (tailwind pass over the current
templates; htmx copied from the current node_modules version).
New /admin/hash-conflicts page (admin-only) listing pending
content-duplicate groups. Each group card shows the library, a
shortened SHA-256, and one row per copy with title, author, path,
size, and per-copy reading-data counts (progress, highlights,
bookmarks, notes, collections) - copies that own user data are
highlighted so the keep choice is informed.
Per copy: 'Keep this copy' merges the other copies' child rows into
it and deletes them. Per group: 'Keep both' for intentional
duplicates. Both confirm first, resolve via htmx POST, and swap the
card for a resolved confirmation inline. The confirmation fragment is
built inline in the handler rather than the templates package
(templates imports handlers; a back-import would be a cycle).
Empty state shown when no conflicts are pending. Adds a 'Hash
Conflicts' entry to the admin sidebar section between Libraries and
Users.