feat: user management — admin create, password reset, archive/delete, quick invite
Phase 1: must_change_password enforcement + change password endpoint/page Phase 2: Admin user creation (M365-style) with temp password Phase 3: Password reset (self-service forgot + admin-triggered) Phase 4: User archive (soft delete) + hard delete with precheck Phase 5: Quick invite from admin Users page Also fixes: - Auto-create subscription for accounts missing one - Hard delete precheck ignores sole-member personal accounts - Seed script patches tree nodes for validation compliance Migrations: 031 (must_change_password), 032 (password_reset_tokens), 033 (user soft delete) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ interface ProtectedRouteProps {
|
||||
}
|
||||
|
||||
export function ProtectedRoute({ requiredRole, children }: ProtectedRouteProps) {
|
||||
const { isAuthenticated, isLoading } = useAuthStore()
|
||||
const { isAuthenticated, isLoading, user } = useAuthStore()
|
||||
const location = useLocation()
|
||||
const { effectiveRole } = usePermissions()
|
||||
|
||||
@@ -24,6 +24,11 @@ export function ProtectedRoute({ requiredRole, children }: ProtectedRouteProps)
|
||||
return <Navigate to="/login" state={{ from: location }} replace />
|
||||
}
|
||||
|
||||
// Enforce must_change_password — redirect unless already on /change-password
|
||||
if (user?.must_change_password && location.pathname !== '/change-password') {
|
||||
return <Navigate to="/change-password" replace />
|
||||
}
|
||||
|
||||
if (requiredRole) {
|
||||
const ROLE_HIERARCHY: Record<EffectiveRole, number> = {
|
||||
super_admin: 4,
|
||||
|
||||
Reference in New Issue
Block a user