WP-01: domain contract and failing tests for auth and user management
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / ui (push) Has been cancelled

Domain entities/ports, service stubs, 18 application unit tests with in-memory
fakes, API integration tests for /api/auth and /api/users, Vitest specs for the
auth store, login page and user form, Playwright auth/user-management flow.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-09-02 21:31:59 +02:00
parent 780c84098b
commit 83aa500f5d
21 changed files with 1427 additions and 29 deletions

View File

@ -0,0 +1,42 @@
//! Ports implemented by the infrastructure layer.
use async_trait::async_trait;
use uuid::Uuid;
use crate::auth::{AccessClaims, AuthEvent, RefreshToken};
use crate::user::{User, UserUpdate};
use crate::DomainError;
#[async_trait]
pub trait UserRepository: Send + Sync {
async fn find_by_id(&self, id: Uuid) -> Result<Option<User>, DomainError>;
async fn find_by_email(&self, email: &str) -> Result<Option<User>, DomainError>;
async fn list(&self) -> Result<Vec<User>, DomainError>;
async fn count(&self) -> Result<u64, DomainError>;
async fn count_active_admins(&self) -> Result<u64, DomainError>;
async fn insert(&self, user: &User) -> Result<(), DomainError>;
async fn update(&self, id: Uuid, update: &UserUpdate) -> Result<User, DomainError>;
async fn set_password_hash(&self, id: Uuid, hash: &str) -> Result<(), DomainError>;
}
#[async_trait]
pub trait RefreshTokenRepository: Send + Sync {
async fn insert(&self, token: &RefreshToken) -> Result<(), DomainError>;
async fn find_by_hash(&self, hash: &str) -> Result<Option<RefreshToken>, DomainError>;
async fn revoke(&self, id: Uuid) -> Result<(), DomainError>;
async fn revoke_family(&self, family: Uuid) -> Result<(), DomainError>;
}
#[async_trait]
pub trait AuditLog: Send + Sync {
async fn record(&self, event: &AuthEvent) -> Result<(), DomainError>;
}
pub trait PasswordHasher: Send + Sync {
fn hash(&self, password: &str) -> Result<String, DomainError>;
fn verify(&self, password: &str, hash: &str) -> bool;
}
pub trait AccessTokenIssuer: Send + Sync {
fn issue(&self, user: &User) -> Result<String, DomainError>;
fn verify(&self, token: &str) -> Result<AccessClaims, DomainError>;
}