feat: authsession service

This commit is contained in:
Ilia Denisov
2026-04-08 16:23:07 +02:00
committed by GitHub
parent 28f04916af
commit 86a68ed9d0
174 changed files with 31732 additions and 112 deletions
@@ -0,0 +1,110 @@
// Package userresolution defines the domain result returned by the user
// resolution boundary before session creation.
package userresolution
import (
"errors"
"fmt"
"strings"
"galaxy/authsession/internal/domain/common"
)
// Kind identifies the coarse user-resolution result for one normalized e-mail.
type Kind string
const (
// KindExisting reports that the e-mail belongs to an existing user.
KindExisting Kind = "existing"
// KindCreatable reports that the e-mail is free and user creation is
// allowed.
KindCreatable Kind = "creatable"
// KindBlocked reports that the e-mail or subject is blocked from login or
// registration.
KindBlocked Kind = "blocked"
)
// IsKnown reports whether Kind is one of the user-resolution kinds supported
// by the current domain model.
func (k Kind) IsKnown() bool {
switch k {
case KindExisting, KindCreatable, KindBlocked:
return true
default:
return false
}
}
// BlockReasonCode stores one machine-readable user-block reason.
type BlockReasonCode string
// String returns BlockReasonCode as its stored code value.
func (code BlockReasonCode) String() string {
return string(code)
}
// IsZero reports whether BlockReasonCode is empty.
func (code BlockReasonCode) IsZero() bool {
return strings.TrimSpace(string(code)) == ""
}
// Validate reports whether BlockReasonCode is non-empty and normalized for
// domain use.
func (code BlockReasonCode) Validate() error {
switch {
case code.IsZero():
return errors.New("block reason code must not be empty")
case strings.TrimSpace(string(code)) != string(code):
return errors.New("block reason code must not contain surrounding whitespace")
default:
return nil
}
}
// Result stores the coarse user-resolution outcome consumed by later auth
// workflow stages.
type Result struct {
// Kind reports the coarse resolution outcome.
Kind Kind
// UserID is set only when Kind is KindExisting.
UserID common.UserID
// BlockReasonCode is set only when Kind is KindBlocked.
BlockReasonCode BlockReasonCode
}
// Validate reports whether Result satisfies the Stage-2 structural invariants.
func (r Result) Validate() error {
if !r.Kind.IsKnown() {
return fmt.Errorf("user resolution kind %q is unsupported", r.Kind)
}
switch r.Kind {
case KindExisting:
if err := r.UserID.Validate(); err != nil {
return fmt.Errorf("user resolution user id: %w", err)
}
if !r.BlockReasonCode.IsZero() {
return errors.New("existing user resolution must not contain block reason code")
}
case KindCreatable:
if !r.UserID.IsZero() {
return errors.New("creatable user resolution must not contain user id")
}
if !r.BlockReasonCode.IsZero() {
return errors.New("creatable user resolution must not contain block reason code")
}
case KindBlocked:
if !r.UserID.IsZero() {
return errors.New("blocked user resolution must not contain user id")
}
if err := r.BlockReasonCode.Validate(); err != nil {
return fmt.Errorf("user resolution block reason code: %w", err)
}
}
return nil
}