Files
galaxy-game/backend/internal/user/deps.go
T
2026-05-07 00:58:53 +03:00

107 lines
3.8 KiB
Go

package user
import (
"context"
"github.com/google/uuid"
"go.uber.org/zap"
)
// LobbyCascade collects the lobby-side hooks the user lifecycle invokes
// after a successful soft-delete or permanent-block transition. The
// real implementation lives in `backend/internal/lobby`.
// Until then `NewNoopLobbyCascade` satisfies the contract.
type LobbyCascade interface {
OnUserDeleted(ctx context.Context, userID uuid.UUID) error
OnUserBlocked(ctx context.Context, userID uuid.UUID) error
}
// NotificationCascade collects the notification-side hooks invoked at
// soft-delete. The real implementation lives in
// `backend/internal/notification`.
type NotificationCascade interface {
OnUserDeleted(ctx context.Context, userID uuid.UUID) error
}
// GeoCascade collects the geo-side hooks invoked at soft-delete. The
// real implementation is `*geo.Service` once The implementation lands the
// `OnUserDeleted` method.
type GeoCascade interface {
OnUserDeleted(ctx context.Context, userID uuid.UUID) error
}
// SessionRevoker revokes every active session bound to a user. The
// canonical implementation wraps `*auth.Service.RevokeAllForUser`. The
// adapter lives in `cmd/backend/main.go` so `auth` does not export an
// extra method shape.
//
// The actor argument carries audit context: who initiated the revoke
// and why. The auth side persists it into `session_revocations`; user
// callers populate it with a fixed kind matching the trigger.
type SessionRevoker interface {
RevokeAllForUser(ctx context.Context, userID uuid.UUID, actor SessionRevokeActor) error
}
// SessionRevokeActor describes the principal behind a session revoke.
// Kind is a closed vocabulary mirrored by `auth.ActorKind`; ID is the
// stable identifier of the principal (a user UUID for self-driven
// flows, an admin username for admin-driven flows). Reason is a
// free-form note recorded in the audit row.
type SessionRevokeActor struct {
Kind string
ID string
Reason string
}
// Closed Kind vocabulary. Mirror constants live in
// `auth.ActorKind*`; the values must stay in sync because the auth
// adapter forwards them verbatim.
const (
SessionRevokeActorSoftDeleteUser = "soft_delete_user"
SessionRevokeActorSoftDeleteAdmin = "soft_delete_admin"
SessionRevokeActorAdminSanction = "admin_sanction"
)
// NewNoopLobbyCascade returns a LobbyCascade that logs every invocation
// at info level and returns nil. The canonical lobby is wired in `cmd/backend/main.go`.
// implementation; until then the no-op keeps the cascade orchestration
// callable end-to-end.
func NewNoopLobbyCascade(logger *zap.Logger) LobbyCascade {
if logger == nil {
logger = zap.NewNop()
}
return &noopLobbyCascade{logger: logger.Named("user.lobby.noop")}
}
type noopLobbyCascade struct {
logger *zap.Logger
}
func (c *noopLobbyCascade) OnUserDeleted(_ context.Context, userID uuid.UUID) error {
c.logger.Info("lobby on-user-deleted (noop cascade)", zap.String("user_id", userID.String()))
return nil
}
func (c *noopLobbyCascade) OnUserBlocked(_ context.Context, userID uuid.UUID) error {
c.logger.Info("lobby on-user-blocked (noop cascade)", zap.String("user_id", userID.String()))
return nil
}
// NewNoopNotificationCascade returns a NotificationCascade that logs
// every invocation at info level and returns nil. The canonical implementation replaces // it with the real notification implementation.
func NewNoopNotificationCascade(logger *zap.Logger) NotificationCascade {
if logger == nil {
logger = zap.NewNop()
}
return &noopNotificationCascade{logger: logger.Named("user.notification.noop")}
}
type noopNotificationCascade struct {
logger *zap.Logger
}
func (c *noopNotificationCascade) OnUserDeleted(_ context.Context, userID uuid.UUID) error {
c.logger.Info("notification on-user-deleted (noop cascade)", zap.String("user_id", userID.String()))
return nil
}