Implement auth domain with outside-in TDD (22 tests)
Controller (7 tests): signup, login, logout, GET/PATCH me. Standalone MockMvc setup (Boot 4 removed @WebMvcTest). Service (11 tests): signup with conflict check, login with password/active validation, getCurrentUser with household info, updateProfile with password change flow. Repository (4 tests): save/find, case-insensitive email via IgnoreCase queries (citext + Hibernate needs explicit IgnoreCase), existsByEmail. Also includes: - SecurityConfig: session auth, CSRF, role-based authorization - CustomUserDetailsService: loads UserAccount for Spring Security - UserAccount, Household, HouseholdMember JPA entities - spring-boot-flyway dependency (Boot 4 requires explicit module) - ddl-auto=none (Flyway owns schema, validate fails on citext) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package com.recipeapp.auth.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "user_account")
|
||||
public class UserAccount {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
@Column(nullable = false, unique = true, columnDefinition = "citext")
|
||||
private String email;
|
||||
|
||||
@Column(name = "display_name", nullable = false, length = 100)
|
||||
private String displayName;
|
||||
|
||||
@Column(name = "password_hash", nullable = false)
|
||||
private String passwordHash;
|
||||
|
||||
@Column(name = "system_role", nullable = false, length = 10)
|
||||
private String systemRole = "user";
|
||||
|
||||
@Column(name = "is_active", nullable = false)
|
||||
private boolean isActive = true;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private Instant createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private Instant updatedAt;
|
||||
|
||||
protected UserAccount() {}
|
||||
|
||||
public UserAccount(String email, String displayName, String passwordHash) {
|
||||
this.email = email;
|
||||
this.displayName = displayName;
|
||||
this.passwordHash = passwordHash;
|
||||
}
|
||||
|
||||
@PrePersist
|
||||
void onCreate() {
|
||||
createdAt = Instant.now();
|
||||
updatedAt = Instant.now();
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
void onUpdate() {
|
||||
updatedAt = Instant.now();
|
||||
}
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
public String getDisplayName() { return displayName; }
|
||||
public void setDisplayName(String displayName) { this.displayName = displayName; }
|
||||
public String getPasswordHash() { return passwordHash; }
|
||||
public void setPasswordHash(String passwordHash) { this.passwordHash = passwordHash; }
|
||||
public String getSystemRole() { return systemRole; }
|
||||
public void setSystemRole(String systemRole) { this.systemRole = systemRole; }
|
||||
public boolean isActive() { return isActive; }
|
||||
public void setActive(boolean active) { isActive = active; }
|
||||
public Instant getCreatedAt() { return createdAt; }
|
||||
public Instant getUpdatedAt() { return updatedAt; }
|
||||
}
|
||||
Reference in New Issue
Block a user