From 1795ce0ddcedac9dc2e0c34121579610ee90f6b5 Mon Sep 17 00:00:00 2001 From: hailin Date: Fri, 5 Dec 2025 05:14:22 -0800 Subject: [PATCH] feat(account): make email optional for anonymous accounts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: - Modified CreateAccountRequest to make email optional (omitempty) - Changed Account.Email from string to *string pointer type - Updated PostgreSQL repository to handle nullable email with sql.NullString - Username remains required and auto-generated by identity-service This supports anonymous account creation without requiring email registration. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../adapters/input/http/account_handler.go | 2 +- .../adapters/output/postgres/account_repo.go | 12 ++++++++---- .../services/account/domain/entities/account.go | 16 ++++++++++------ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/backend/mpc-system/services/account/adapters/input/http/account_handler.go b/backend/mpc-system/services/account/adapters/input/http/account_handler.go index 5f6118db..a7905268 100644 --- a/backend/mpc-system/services/account/adapters/input/http/account_handler.go +++ b/backend/mpc-system/services/account/adapters/input/http/account_handler.go @@ -108,7 +108,7 @@ func (h *AccountHTTPHandler) RegisterRoutes(router *gin.RouterGroup) { // CreateAccountRequest represents the request for creating an account type CreateAccountRequest struct { Username string `json:"username" binding:"required"` - Email string `json:"email" binding:"required,email"` + Email string `json:"email" binding:"omitempty,email"` Phone *string `json:"phone"` PublicKey string `json:"publicKey" binding:"required"` KeygenSessionID string `json:"keygenSessionId" binding:"required"` diff --git a/backend/mpc-system/services/account/adapters/output/postgres/account_repo.go b/backend/mpc-system/services/account/adapters/output/postgres/account_repo.go index 6d33e480..451dd4d1 100644 --- a/backend/mpc-system/services/account/adapters/output/postgres/account_repo.go +++ b/backend/mpc-system/services/account/adapters/output/postgres/account_repo.go @@ -215,7 +215,7 @@ func (r *AccountPostgresRepo) scanAccount(row *sql.Row) (*entities.Account, erro var ( id uuid.UUID username string - email string + email sql.NullString phone sql.NullString publicKey []byte keygenSessionID uuid.UUID @@ -249,7 +249,9 @@ func (r *AccountPostgresRepo) scanAccount(row *sql.Row) (*entities.Account, erro account.ID = value_objects.AccountIDFromUUID(id) account.Username = username - account.Email = email + if email.Valid { + account.Email = &email.String + } if phone.Valid { account.Phone = &phone.String } @@ -267,7 +269,7 @@ func (r *AccountPostgresRepo) scanAccountFromRows(rows *sql.Rows) (*entities.Acc var ( id uuid.UUID username string - email string + email sql.NullString phone sql.NullString publicKey []byte keygenSessionID uuid.UUID @@ -298,7 +300,9 @@ func (r *AccountPostgresRepo) scanAccountFromRows(rows *sql.Rows) (*entities.Acc account.ID = value_objects.AccountIDFromUUID(id) account.Username = username - account.Email = email + if email.Valid { + account.Email = &email.String + } if phone.Valid { account.Phone = &phone.String } diff --git a/backend/mpc-system/services/account/domain/entities/account.go b/backend/mpc-system/services/account/domain/entities/account.go index 6253e4b1..4015f4f7 100644 --- a/backend/mpc-system/services/account/domain/entities/account.go +++ b/backend/mpc-system/services/account/domain/entities/account.go @@ -10,8 +10,8 @@ import ( // Account represents a user account with MPC-based authentication type Account struct { ID value_objects.AccountID - Username string - Email string + Username string // Required: auto-generated by identity-service + Email *string // Optional: for anonymous accounts Phone *string PublicKey []byte // MPC group public key KeygenSessionID uuid.UUID @@ -33,10 +33,16 @@ func NewAccount( thresholdT int, ) *Account { now := time.Now().UTC() + var emailPtr *string + + if email != "" { + emailPtr = &email + } + return &Account{ ID: value_objects.NewAccountID(), Username: username, - Email: email, + Email: emailPtr, PublicKey: publicKey, KeygenSessionID: keygenSessionID, ThresholdN: thresholdN, @@ -119,9 +125,7 @@ func (a *Account) Validate() error { if a.Username == "" { return ErrInvalidUsername } - if a.Email == "" { - return ErrInvalidEmail - } + // Email is optional, but if provided must be valid (checked by binding) if len(a.PublicKey) == 0 { return ErrInvalidPublicKey }