package dto import ( "github.com/noteapp/backend/internal/domain/entities" ) // ========== AUTH DTOs ========== // RegisterRequest represents a registration request type RegisterRequest struct { Email string `json:"email" validate:"required,email"` Username string `json:"username" validate:"required,min=3,max=20"` Password string `json:"password" validate:"required,min=8"` PasswordConfirm string `json:"password_confirm" validate:"required,eqfield=Password"` FirstName string `json:"first_name" validate:"max=50"` LastName string `json:"last_name" validate:"max=50"` } // LoginRequest represents a login request type LoginRequest struct { Email string `json:"email" validate:"required,email"` Password string `json:"password" validate:"required"` } // LoginResponse represents a login response type LoginResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token,omitempty"` User *UserDTO `json:"user"` ExpiresIn int `json:"expires_in"` } // AuthProviderDTO represents an OAuth/OIDC provider in API responses. type AuthProviderDTO struct { ID string `json:"id"` Name string `json:"name"` Type string `json:"type"` AuthorizationURL string `json:"authorization_url,omitempty"` TokenURL string `json:"token_url,omitempty"` UserInfoURL string `json:"userinfo_url,omitempty"` Scopes []string `json:"scopes"` IDTokenClaim string `json:"id_token_claim,omitempty"` IsActive bool `json:"is_active"` } // CreateAuthProviderRequest represents an OAuth/OIDC provider creation request. type CreateAuthProviderRequest struct { Name string `json:"name"` Type string `json:"type"` ClientID string `json:"client_id"` ClientSecret string `json:"client_secret"` AuthorizationURL string `json:"authorization_url"` TokenURL string `json:"token_url"` UserInfoURL string `json:"userinfo_url"` Scopes []string `json:"scopes"` IDTokenClaim string `json:"id_token_claim,omitempty"` IsActive bool `json:"is_active"` } // FeatureFlagsDTO represents app-wide feature flags in API responses. type FeatureFlagsDTO struct { RegistrationEnabled bool `json:"registration_enabled"` ProviderLoginEnabled bool `json:"provider_login_enabled"` PublicSharingEnabled bool `json:"public_sharing_enabled"` FileExplorerEnabled bool `json:"file_explorer_enabled"` S3Endpoint string `json:"s3_endpoint,omitempty"` S3Bucket string `json:"s3_bucket,omitempty"` S3Region string `json:"s3_region,omitempty"` S3AccessKey string `json:"s3_access_key,omitempty"` S3SecretKeySet bool `json:"s3_secret_key_set"` } // UpdateFeatureFlagsRequest represents admin payload for feature flag updates. type UpdateFeatureFlagsRequest struct { RegistrationEnabled bool `json:"registration_enabled"` ProviderLoginEnabled bool `json:"provider_login_enabled"` PublicSharingEnabled bool `json:"public_sharing_enabled"` FileExplorerEnabled bool `json:"file_explorer_enabled"` S3Endpoint string `json:"s3_endpoint"` S3Bucket string `json:"s3_bucket"` S3Region string `json:"s3_region"` S3AccessKey string `json:"s3_access_key"` S3SecretKey string `json:"s3_secret_key"` // empty = keep existing encrypted value } // UserDTO represents a user in API responses type UserDTO struct { ID string `json:"id"` Email string `json:"email"` Username string `json:"username"` FirstName string `json:"first_name"` LastName string `json:"last_name"` Avatar string `json:"avatar,omitempty"` GroupIDs []string `json:"group_ids,omitempty"` Permissions []string `json:"permissions,omitempty"` EmailVerified bool `json:"email_verified"` } // NewUserDTO creates a DTO from a user entity func NewUserDTO(user *entities.User) *UserDTO { groupIDs := make([]string, 0, len(user.GroupIDs)) for _, groupID := range user.GroupIDs { groupIDs = append(groupIDs, groupID.Hex()) } return &UserDTO{ ID: user.ID.Hex(), Email: user.Email, Username: user.Username, FirstName: user.FirstName, LastName: user.LastName, Avatar: user.Avatar, GroupIDs: groupIDs, Permissions: user.Permissions, EmailVerified: user.EmailVerified, } } // AdminUserDTO extends UserDTO with admin-visible fields type AdminUserDTO struct { *UserDTO IsActive bool `json:"is_active"` CreatedAt string `json:"created_at"` } // PermissionGroupDTO represents a permission group in API responses. type PermissionGroupDTO struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description"` Permissions []string `json:"permissions"` IsSystem bool `json:"is_system"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // CreatePermissionGroupRequest represents group creation input. type CreatePermissionGroupRequest struct { Name string `json:"name"` Description string `json:"description"` Permissions []string `json:"permissions"` } // UpdatePermissionGroupRequest represents group update input. type UpdatePermissionGroupRequest struct { Name string `json:"name"` Description string `json:"description"` Permissions []string `json:"permissions"` } // UpdateUserGroupsRequest represents user group assignment input. type UpdateUserGroupsRequest struct { GroupIDs []string `json:"group_ids"` } // NewAdminUserDTO creates an admin DTO from a user entity func NewAdminUserDTO(user *entities.User) *AdminUserDTO { return &AdminUserDTO{ UserDTO: NewUserDTO(user), IsActive: user.IsActive, CreatedAt: user.CreatedAt.Format("2006-01-02T15:04:05Z"), } } // NewPermissionGroupDTO creates a DTO from a permission group entity. func NewPermissionGroupDTO(group *entities.PermissionGroup) *PermissionGroupDTO { return &PermissionGroupDTO{ ID: group.ID.Hex(), Name: group.Name, Description: group.Description, Permissions: group.Permissions, IsSystem: group.IsSystem, CreatedAt: group.CreatedAt.Format("2006-01-02T15:04:05Z"), UpdatedAt: group.UpdatedAt.Format("2006-01-02T15:04:05Z"), } } // AddSpaceMemberRequest represents a request to add a member to a space type AddSpaceMemberRequest struct { UserID string `json:"user_id"` } // SpaceMemberDTO represents a member in a space type SpaceMemberDTO struct { UserID string `json:"user_id"` Username string `json:"username"` JoinedAt string `json:"joined_at"` } // UserOptionDTO is a lightweight user object for dropdowns type UserOptionDTO struct { ID string `json:"id"` Username string `json:"username"` } // NewAuthProviderDTO creates a DTO from an auth provider entity. func NewAuthProviderDTO(provider *entities.AuthProvider) *AuthProviderDTO { return &AuthProviderDTO{ ID: provider.ID.Hex(), Name: provider.Name, Type: provider.Type, AuthorizationURL: provider.AuthorizationURL, TokenURL: provider.TokenURL, UserInfoURL: provider.UserInfoURL, Scopes: provider.Scopes, IDTokenClaim: provider.IDTokenClaim, IsActive: provider.IsActive, } } // NewFeatureFlagsDTO creates a DTO from feature flags entity. func NewFeatureFlagsDTO(flags *entities.FeatureFlags) *FeatureFlagsDTO { if flags == nil { flags = entities.NewDefaultFeatureFlags() } return &FeatureFlagsDTO{ RegistrationEnabled: flags.RegistrationEnabled, ProviderLoginEnabled: flags.ProviderLoginEnabled, PublicSharingEnabled: flags.PublicSharingEnabled, FileExplorerEnabled: flags.FileExplorerEnabled, S3Endpoint: flags.S3Endpoint, S3Bucket: flags.S3Bucket, S3Region: flags.S3Region, S3AccessKey: flags.S3AccessKey, S3SecretKeySet: flags.S3SecretKey != "", } } // ========== SPACE DTOs ========== // CreateSpaceRequest represents a space creation request type CreateSpaceRequest struct { Name string `json:"name" validate:"required,min=1,max=100"` Description string `json:"description" validate:"max=500"` Icon string `json:"icon,omitempty" validate:"max=20"` IsPublic bool `json:"is_public"` } // SpaceDTO represents a space in API responses type SpaceDTO struct { ID string `json:"id"` Name string `json:"name"` PermissionKey string `json:"permission_key"` Description string `json:"description"` Icon string `json:"icon,omitempty"` OwnerID string `json:"owner_id"` IsPublic bool `json:"is_public"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // NewSpaceDTO creates a DTO from a space entity func NewSpaceDTO(space *entities.Space) *SpaceDTO { dto := &SpaceDTO{ ID: space.ID.Hex(), Name: space.Name, PermissionKey: entities.SpacePermissionToken(space.Name), Description: space.Description, Icon: space.Icon, OwnerID: space.OwnerID.Hex(), IsPublic: space.IsPublic, CreatedAt: space.CreatedAt.Format("2006-01-02T15:04:05Z"), UpdatedAt: space.UpdatedAt.Format("2006-01-02T15:04:05Z"), } return dto } // ========== NOTE DTOs ========== // CreateNoteRequest represents a note creation request type CreateNoteRequest struct { Title string `json:"title" validate:"required,min=1,max=255"` Description string `json:"description" validate:"max=500"` Content string `json:"content"` NotePassword string `json:"note_password,omitempty" validate:"omitempty,min=4,max=128"` Tags []string `json:"tags"` CategoryID *string `json:"category_id,omitempty"` IsPinned bool `json:"is_pinned"` IsFavorite bool `json:"is_favorite"` IsPublic bool `json:"is_public"` } // UpdateNoteRequest represents a note update request type UpdateNoteRequest struct { Title string `json:"title" validate:"min=1,max=255"` Description *string `json:"description,omitempty" validate:"omitempty,max=500"` Content string `json:"content"` NotePassword *string `json:"note_password,omitempty" validate:"omitempty,max=128"` Tags []string `json:"tags"` CategoryID *string `json:"category_id,omitempty"` IsPinned *bool `json:"is_pinned"` IsFavorite *bool `json:"is_favorite"` IsPublic *bool `json:"is_public,omitempty"` } // UnlockNoteRequest represents a password unlock request for protected notes type UnlockNoteRequest struct { Password string `json:"password" validate:"required,min=1,max=128"` } // NoteDTO represents a note in API responses type NoteDTO struct { ID string `json:"id"` SpaceID string `json:"space_id"` CategoryID *string `json:"category_id,omitempty"` Title string `json:"title"` Description string `json:"description"` Content string `json:"content"` Tags []string `json:"tags"` IsPinned bool `json:"is_pinned"` IsFavorite bool `json:"is_favorite"` IsPublic bool `json:"is_public"` IsPasswordProtected bool `json:"is_password_protected"` CreatedBy string `json:"created_by"` UpdatedBy string `json:"updated_by"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // NoteListItemDTO represents a lightweight note payload for list/tree endpoints type NoteListItemDTO struct { ID string `json:"id"` SpaceID string `json:"space_id"` CategoryID *string `json:"category_id,omitempty"` Title string `json:"title"` Description string `json:"description"` IsPinned bool `json:"is_pinned"` IsFavorite bool `json:"is_favorite"` IsPublic bool `json:"is_public"` IsPasswordProtected bool `json:"is_password_protected"` UpdatedAt string `json:"updated_at"` } // NewNoteDTO creates a DTO from a note entity func NewNoteDTO(note *entities.Note) *NoteDTO { var categoryID *string if note.CategoryID != nil { id := note.CategoryID.Hex() categoryID = &id } return &NoteDTO{ ID: note.ID.Hex(), SpaceID: note.SpaceID.Hex(), CategoryID: categoryID, Title: note.Title, Description: note.Description, Content: note.Content, Tags: note.Tags, IsPinned: note.IsPinned, IsFavorite: note.IsFavorite, IsPublic: note.IsPublic, IsPasswordProtected: note.IsPasswordProtected, CreatedBy: note.CreatedBy.Hex(), UpdatedBy: note.UpdatedBy.Hex(), CreatedAt: note.CreatedAt.Format("2006-01-02T15:04:05Z"), UpdatedAt: note.UpdatedAt.Format("2006-01-02T15:04:05Z"), } } // NewNoteListItemDTO creates a lightweight DTO from a note entity func NewNoteListItemDTO(note *entities.Note) *NoteListItemDTO { var categoryID *string if note.CategoryID != nil { id := note.CategoryID.Hex() categoryID = &id } return &NoteListItemDTO{ ID: note.ID.Hex(), SpaceID: note.SpaceID.Hex(), CategoryID: categoryID, Title: note.Title, Description: note.Description, IsPinned: note.IsPinned, IsFavorite: note.IsFavorite, IsPublic: note.IsPublic, IsPasswordProtected: note.IsPasswordProtected, UpdatedAt: note.UpdatedAt.Format("2006-01-02T15:04:05Z"), } } // ========== CATEGORY DTOs ========== // CreateCategoryRequest represents a category creation request type CreateCategoryRequest struct { Name string `json:"name" validate:"required,min=1,max=100"` Description string `json:"description" validate:"max=500"` ParentID *string `json:"parent_id,omitempty"` Icon string `json:"icon,omitempty" validate:"max=20"` } // UpdateCategoryRequest represents a category update request type UpdateCategoryRequest struct { Name string `json:"name" validate:"min=1,max=100"` Description string `json:"description" validate:"max=500"` Icon string `json:"icon,omitempty" validate:"max=20"` } // CategoryDTO represents a category in API responses type CategoryDTO struct { ID string `json:"id"` SpaceID string `json:"space_id"` Name string `json:"name"` Description string `json:"description"` ParentID *string `json:"parent_id,omitempty"` Icon string `json:"icon,omitempty"` Order int `json:"order"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // CategoryTreeDTO represents a category with its subcategories and notes type CategoryTreeDTO struct { *CategoryDTO Subcategories []*CategoryTreeDTO `json:"subcategories"` Notes []*NoteListItemDTO `json:"notes"` } // NewCategoryDTO creates a DTO from a category entity func NewCategoryDTO(category *entities.Category) *CategoryDTO { var parentID *string if category.ParentID != nil { id := category.ParentID.Hex() parentID = &id } return &CategoryDTO{ ID: category.ID.Hex(), SpaceID: category.SpaceID.Hex(), Name: category.Name, Description: category.Description, ParentID: parentID, Icon: category.Icon, Order: category.Order, CreatedAt: category.CreatedAt.Format("2006-01-02T15:04:05Z"), UpdatedAt: category.UpdatedAt.Format("2006-01-02T15:04:05Z"), } } // ========== ERROR DTOs ========== // ErrorResponse represents an error response type ErrorResponse struct { Error string `json:"error"` Message string `json:"message"` Code int `json:"code"` } // ValidationError represents a validation error type ValidationError struct { Field string `json:"field"` Message string `json:"message"` } // ValidationErrorResponse represents multiple validation errors type ValidationErrorResponse struct { Errors []ValidationError `json:"errors"` }