feat: user service

This commit is contained in:
Ilia Denisov
2026-04-10 19:05:02 +02:00
committed by GitHub
parent 710bad712e
commit 23ffcb7535
140 changed files with 33418 additions and 952 deletions
+56
View File
@@ -0,0 +1,56 @@
// Package authblock defines the dedicated pre-user auth-block entity stored by
// User Service.
package authblock
import (
"fmt"
"time"
"galaxy/user/internal/domain/common"
)
// BlockedEmailSubject stores a blocked e-mail subject that may exist before
// any user account exists.
type BlockedEmailSubject struct {
// Email stores the normalized blocked e-mail subject.
Email common.Email
// ReasonCode stores the machine-readable reason for the block.
ReasonCode common.ReasonCode
// BlockedAt stores when the block became effective.
BlockedAt time.Time
// Actor stores optional audit metadata for the block initiator.
Actor common.ActorRef
// ResolvedUserID stores the linked user when the blocked e-mail already
// belongs to an existing account.
ResolvedUserID common.UserID
}
// Validate reports whether BlockedEmailSubject satisfies the frozen Stage 02
// structural invariants.
func (record BlockedEmailSubject) Validate() error {
if err := record.Email.Validate(); err != nil {
return fmt.Errorf("blocked email subject email: %w", err)
}
if err := record.ReasonCode.Validate(); err != nil {
return fmt.Errorf("blocked email subject reason code: %w", err)
}
if err := common.ValidateTimestamp("blocked email subject blocked at", record.BlockedAt); err != nil {
return err
}
if !record.Actor.IsZero() {
if err := record.Actor.Validate(); err != nil {
return fmt.Errorf("blocked email subject actor: %w", err)
}
}
if !record.ResolvedUserID.IsZero() {
if err := record.ResolvedUserID.Validate(); err != nil {
return fmt.Errorf("blocked email subject resolved user id: %w", err)
}
}
return nil
}
@@ -0,0 +1,61 @@
package authblock
import (
"testing"
"time"
"galaxy/user/internal/domain/common"
"github.com/stretchr/testify/require"
)
func TestBlockedEmailSubjectValidate(t *testing.T) {
t.Parallel()
tests := []struct {
name string
record BlockedEmailSubject
wantErr bool
}{
{
name: "valid without actor or user",
record: BlockedEmailSubject{
Email: common.Email("pilot@example.com"),
ReasonCode: common.ReasonCode("policy_blocked"),
BlockedAt: time.Unix(1_775_240_000, 0).UTC(),
},
},
{
name: "valid with actor and user",
record: BlockedEmailSubject{
Email: common.Email("pilot@example.com"),
ReasonCode: common.ReasonCode("policy_blocked"),
BlockedAt: time.Unix(1_775_240_000, 0).UTC(),
Actor: common.ActorRef{Type: common.ActorType("admin"), ID: common.ActorID("admin-1")},
ResolvedUserID: common.UserID("user-123"),
},
},
{
name: "missing blocked at",
record: BlockedEmailSubject{
Email: common.Email("pilot@example.com"),
ReasonCode: common.ReasonCode("policy_blocked"),
},
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := tt.record.Validate()
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
})
}
}