feat(account): make email optional for anonymous accounts

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 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-05 05:14:22 -08:00
parent 553ffd365e
commit 1795ce0ddc
3 changed files with 19 additions and 11 deletions

View File

@ -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"`

View File

@ -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
}

View File

@ -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
}