feat(auth): login, roles, user mgmt, setup wizard, and session guard

- New skald-setup crate: interactive first-run wizard that creates the
  admin user, prompts for encryption choice and password
- Auth system: session-based login/logout with cookie, guard middleware
- Roles API: CRUD for data-driven roles, seeded on first boot
- Users management API: create, list, edit, delete users
- Setup state API: check if first admin has been created
- Frontend: login-page, setup-page, users-page, roles-page, profile-page
  components with corresponding CSS
- Topbar: avatar dropdown with profile link and logout
- Sidebar: nav entries for Users and Roles (admin only)
- Page shell CSS: layout support for the new pages
- build.sh: builds both skald and skald-setup binaries
- run.sh: runs skald-setup before the server loop
- CLAUDE.md: updated workspace layout and build/run docs
This commit is contained in:
2026-07-10 19:19:25 +01:00
parent 178a38357e
commit 7dd77d4ef4
36 changed files with 2660 additions and 27 deletions
+1
View File
@@ -52,6 +52,7 @@ impl Skald {
// Runtime / cross-cutting
pub fn db(&self) -> &Arc<SqlitePool> { &self.rt.db }
pub fn users(&self) -> &Arc<UserManager> { &self.rt.users }
pub fn sessions(&self) -> &Arc<crate::auth::SessionStore> { &self.rt.sessions }
pub fn config(&self) -> &Arc<GlobalConfigManager> { &self.rt.config }
pub fn config_properties(&self) -> &[core_api::ConfigSet] { &self.rt.config_properties }
pub fn system_bus(&self) -> &Arc<SystemEventBus> { &self.rt.system_bus }
+4
View File
@@ -17,6 +17,7 @@ use tracing::info;
use core_api::events::GlobalEvent;
use core_api::system_bus::SystemEventBus;
use crate::auth::SessionStore;
use crate::chat_event_bus::ChatEventBus;
use crate::config_store::GlobalConfigManager;
use crate::users::UserManager;
@@ -28,6 +29,7 @@ pub(super) struct Runtime {
/// writes: nothing has moved to per-user pools yet. `users` owns those.
pub(super) db: Arc<SqlitePool>,
pub(super) users: Arc<UserManager>,
pub(super) sessions: Arc<SessionStore>,
pub(super) config: Arc<GlobalConfigManager>,
pub(super) config_properties: Vec<core_api::ConfigSet>,
pub(super) system_bus: Arc<SystemEventBus>,
@@ -46,6 +48,7 @@ impl Runtime {
let config = Arc::new(GlobalConfigManager::new(Arc::clone(&pool)));
let users = Arc::new(UserManager::new(Arc::clone(&pool)));
let sessions = Arc::new(SessionStore::new(Arc::clone(&users)));
let system_bus = Arc::new(SystemEventBus::new());
info!("system event bus ready");
@@ -58,6 +61,7 @@ impl Runtime {
Runtime {
db: pool,
users,
sessions,
config,
config_properties: vec![crate::tic::config_set()],
system_bus,