initial commit

This commit is contained in:
m.zare
2026-04-10 18:25:21 +03:30
commit 77ca6c34a3
263 changed files with 34470 additions and 0 deletions

0
internal/domain/.gitkeep Normal file
View File

View File

@@ -0,0 +1,17 @@
package asset
import (
"github.com/google/uuid"
)
type Artifact struct {
ID uuid.UUID
AssetID uuid.UUID
Type string
DownloadURL string
Price int // in cents or smallest currency unit
Title string
Description string
}

View File

@@ -0,0 +1,36 @@
package asset
import (
"encoding/json"
"time"
"github.com/google/uuid"
)
//go:generate stringer -type=Status
type Status int
const (
StatusPublished Status = iota
StatusDisabled
StatusPending
StatusDeleted
)
type Asset struct {
ID uuid.UUID
ProfileID uuid.UUID
Status Status
AssetCategoryID uuid.UUID
AssetCategory Category
Title string
Description string
Link string
Analytics json.RawMessage
Reports []Report
AssetArtifacts []Artifact
Comments []Comment
CreatedAt time.Time
UpdatedAt time.Time
}

View File

@@ -0,0 +1,17 @@
package asset
import (
"github.com/google/uuid"
)
type Category struct {
ID uuid.UUID
Name string
Icon string
Color string
CardType string
Featured bool
Description string
}

View File

@@ -0,0 +1,22 @@
package asset
import (
"time"
"github.com/google/uuid"
)
type Comment struct {
ID uuid.UUID
AssetID uuid.UUID
Content string
CreatedAt time.Time
UpdatedAt time.Time
WriterID uuid.UUID
WriterType string
ParentID *uuid.UUID
Replies []Comment
}

View File

@@ -0,0 +1,51 @@
package asset
import (
"encoding/json"
"time"
"github.com/google/uuid"
)
//go:generate stringer -type=ReportStatus
type ReportStatus int
const (
ReportStatusPending ReportStatus = iota
ReportStatusReviewed
ReportStatusResolved
ReportStatusDismissed
)
type Report struct {
ID uuid.UUID
AssetID uuid.UUID
ReportedBy ReportedBy
ReportedAt time.Time
Reason ReportReason
Status ReportStatus
Notes string
Attachments []Attachment
}
type ReportedBy struct {
ID uuid.UUID
Name string
Description string
RestOfFields json.RawMessage
}
type ReportReason struct {
ID uuid.UUID
Name string
Description string
RestOfFields json.RawMessage
}
type Attachment struct {
ID uuid.UUID
URL string
Type string
}

View File

@@ -0,0 +1,29 @@
package asset
import (
"context"
"github.com/google/uuid"
)
type AssetRepository interface {
Create(ctx context.Context, asset *Asset) error
FindByID(ctx context.Context, id uuid.UUID) (*Asset, error)
Update(ctx context.Context, asset *Asset) error
Delete(ctx context.Context, asset *Asset) error
FindByProfileID(ctx context.Context, profileID uuid.UUID) ([]*Asset, error)
FindLatest(ctx context.Context, limit, offset int) ([]*Asset, error)
FindLatestByCategory(ctx context.Context, categoryID uuid.UUID, limit int) ([]*Asset, error)
FindLatestByCategoryPaginated(ctx context.Context, categoryID uuid.UUID, limit, offset int) ([]*Asset, error)
CountByCategory(ctx context.Context, categoryID uuid.UUID) (int, error)
Count(ctx context.Context) (int, error)
}
type CategoryRepository interface {
Create(ctx context.Context, category *Category) error
FindByID(ctx context.Context, id uuid.UUID) (*Category, error)
Update(ctx context.Context, category *Category) error
Delete(ctx context.Context, id uuid.UUID) error
FindAll(ctx context.Context) ([]*Category, error)
FindByIDs(ctx context.Context, ids []uuid.UUID) ([]*Category, error)
}

View File

@@ -0,0 +1,25 @@
package auth
import (
"encoding/json"
"time"
"github.com/google/uuid"
"base/internal/pkg/oauth"
)
type Account struct {
ID uuid.UUID
UserID uuid.UUID
Provider oauth.Provider
Password *string
AccessToken *string
RefreshToken *string
AccessTokenExpiry *time.Time
RefreshTokenExpiry *time.Time
Scope []string
Meta json.RawMessage
CreatedAt time.Time
UpdatedAt time.Time
}

View File

@@ -0,0 +1,17 @@
package auth
import (
"time"
"github.com/google/uuid"
)
// AccountCreatedEvent represents the event when an account is created
type AccountCreatedEvent struct {
UserID uuid.UUID `json:"user_id"`
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
PhoneNumber string `json:"phone_number"`
CreatedAt time.Time `json:"created_at"`
}

View File

@@ -0,0 +1,33 @@
package auth
// UserQueryOption represents options for querying users
type UserQueryOption func(*UserQueryOptions)
// UserQueryOptions holds options for user queries
type UserQueryOptions struct {
LoadRoles bool
LoadAccounts bool
}
// WithRoles enables loading of user roles
func WithRoles() UserQueryOption {
return func(opts *UserQueryOptions) {
opts.LoadRoles = true
}
}
// WithAccounts enables loading of user accounts
func WithAccounts() UserQueryOption {
return func(opts *UserQueryOptions) {
opts.LoadAccounts = true
}
}
// WithRelations enables loading of all relations
func WithRelations() UserQueryOption {
return func(opts *UserQueryOptions) {
opts.LoadRoles = true
opts.LoadAccounts = true
}
}

View File

@@ -0,0 +1,51 @@
package auth
import (
"context"
"github.com/google/uuid"
)
type UserRepository interface {
Create(ctx context.Context, user *User) error
CreateWithAccount(ctx context.Context, user *User, account *Account) error
UpsertWithAccount(ctx context.Context, email string, user *User, account *Account) (isNewUser bool, err error)
FindByID(ctx context.Context, id uuid.UUID, opts ...UserQueryOption) (*User, error)
FindByEmail(ctx context.Context, email string, opts ...UserQueryOption) (*User, error)
Update(ctx context.Context, user *User) error
Delete(ctx context.Context, id uuid.UUID) error
List(ctx context.Context, limit, offset int, opts ...UserQueryOption) ([]*User, error)
Count(ctx context.Context) (int64, error)
UserRoles(ctx context.Context, userID uuid.UUID) ([]Role, error)
UserAccounts(ctx context.Context, userID uuid.UUID) ([]Account, error)
}
type RoleRepository interface {
Create(ctx context.Context, role *Role) error
FindByID(ctx context.Context, id uuid.UUID) (*Role, error)
FindByName(ctx context.Context, name string) (*Role, error)
Update(ctx context.Context, role *Role) error
Delete(ctx context.Context, id uuid.UUID) error
List(ctx context.Context, limit, offset int) ([]*Role, error)
Count(ctx context.Context) (int64, error)
}
type AccountRepository interface {
Create(ctx context.Context, account *Account) error
FindByID(ctx context.Context, id uuid.UUID) (*Account, error)
FindByUserID(ctx context.Context, userID uuid.UUID) ([]*Account, error)
Update(ctx context.Context, account *Account) error
Delete(ctx context.Context, id uuid.UUID) error
List(ctx context.Context, limit, offset int) ([]*Account, error)
Count(ctx context.Context) (int64, error)
}
type UserRoleRepository interface {
Create(ctx context.Context, userID, roleID uuid.UUID) error
FindByUserID(ctx context.Context, userID uuid.UUID) ([]*Role, error)
FindByRoleID(ctx context.Context, roleID uuid.UUID) ([]*User, error)
Delete(ctx context.Context, userID, roleID uuid.UUID) error
DeleteByUserID(ctx context.Context, userID uuid.UUID) error
DeleteByRoleID(ctx context.Context, roleID uuid.UUID) error
Exists(ctx context.Context, userID, roleID uuid.UUID) (bool, error)
}

View File

@@ -0,0 +1,15 @@
package auth
import (
"time"
"github.com/google/uuid"
)
type Role struct {
ID uuid.UUID
Name string
Description string
CreatedAt time.Time
UpdatedAt time.Time
}

View File

@@ -0,0 +1,65 @@
package auth
import (
"time"
"github.com/google/uuid"
)
//go:generate stringer -type=UserStatus
type UserStatus int
const (
UserStatusActive UserStatus = iota
UserStatusInactive
UserStatusPending
UserStatusDeleted
)
// User represents a user aggregate root
// The repository handles loading of related entities (Roles, Accounts)
// This keeps the domain entity pure and decoupled from infrastructure
type User struct {
ID uuid.UUID
FirstName string
LastName string
PhoneNumber string
Email string
EmailVerified bool
Status UserStatus
InvitationCode string
Roles []Role
Accounts []Account
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt time.Time
}
// HasRole checks if the user has a specific role
func (u *User) HasRole(roleName string) bool {
for _, role := range u.Roles {
if role.Name == roleName {
return true
}
}
return false
}
// GetRoleNames returns a slice of role names
func (u *User) GetRoleNames() []string {
names := make([]string, len(u.Roles))
for i, role := range u.Roles {
names[i] = role.Name
}
return names
}
// HasAccount checks if the user has an account for the given provider
func (u *User) HasAccount(provider string) bool {
for _, account := range u.Accounts {
if account.Provider.String() == provider {
return true
}
}
return false
}

View File

@@ -0,0 +1,24 @@
package bookmark
import (
"encoding/json"
"github.com/google/uuid"
)
type AssetBookmarkGroup struct {
ID uuid.UUID
ProfileID uuid.UUID
Name string
Assets []BookmarkedAsset
}
type BookmarkedAsset struct {
ID uuid.UUID
BookmarkGroupID uuid.UUID
AssetID uuid.UUID
AssetType string
AssetName string
RestOfFields json.RawMessage
}

View File

@@ -0,0 +1,21 @@
package bookmark
import (
"encoding/json"
"github.com/google/uuid"
)
type SpecialistBookmark struct {
ID uuid.UUID
ProfileID uuid.UUID
Profile BookmarkedProfile
}
type BookmarkedProfile struct {
ID uuid.UUID
Name string
Description string
RestOfFields json.RawMessage
}

View File

@@ -0,0 +1,24 @@
package feedback
import (
"github.com/google/uuid"
)
//go:generate stringer -type=Status
type Status int
const (
StatusOpen Status = iota
StatusClosed
StatusPending
StatusDeleted
)
type Feedback struct {
ID uuid.UUID
UserID uuid.UUID
Title string
Description string
Status Status
Category string
}

View File

@@ -0,0 +1,27 @@
package notification
import (
"encoding/json"
"time"
"github.com/google/uuid"
)
type Notification struct {
ID uuid.UUID
UserID uuid.UUID
Title string
Description string
CreatedAt time.Time
UpdatedAt time.Time
Read bool
ReadAt *time.Time
Action string
ActionData json.RawMessage
ActionURL string
ActionText string
ActionIcon string
}

View File

@@ -0,0 +1,17 @@
package preference
import (
"github.com/google/uuid"
)
type Preference struct {
ID uuid.UUID
UserID uuid.UUID
Name string
Value string
Type string
Description string
}

View File

@@ -0,0 +1,13 @@
package profile
type About struct {
ProfilePicture string
About string
Achievements []Achievement
}
type Achievement struct {
Title string
Value string
Enabled bool
}

View File

@@ -0,0 +1,12 @@
package profile
type Contact struct {
Email string
Phone string
SocialLinks []SocialLink
}
type SocialLink struct {
LinkType string
Link string
}

View File

@@ -0,0 +1,5 @@
package profile
import "errors"
var ErrProfileNotFound = errors.New("profile not found")

View File

@@ -0,0 +1,15 @@
package profile
import "github.com/google/uuid"
type Filter struct {
RoleID uuid.UUID
FirstName string
LastName string
Company string
SkillName string // Search by skill name
Page uint
PageSize uint
SortedBy string
Ascending bool
}

View File

@@ -0,0 +1,12 @@
package profile
type Hero struct {
Role *Role
FirstName string
LastName string
Company string
ShortDescription string
ResumeLink string
CTAEnabled bool
Avatar string
}

View File

@@ -0,0 +1,5 @@
package profile
type PageSetting struct {
VisibilityLevel string // enum: public, private, only_me
}

View File

@@ -0,0 +1,21 @@
package profile
import (
"time"
"github.com/google/uuid"
)
type Profile struct {
ID uuid.UUID
UserID *uuid.UUID // Optional: links profile to a user account
Handle string
PageSectionOrder map[string]int
Hero Hero
About About
Skills []Skill
Contact Contact
PageSetting PageSetting
CreatedAt time.Time
UpdatedAt time.Time
}

View File

@@ -0,0 +1,17 @@
package profile
import (
"context"
"github.com/google/uuid"
)
type Repository interface {
FindByID(ctx context.Context, id uuid.UUID) (*Profile, error)
FindByHandle(ctx context.Context, handle string) (*Profile, error)
Create(ctx context.Context, profile *Profile) error
Update(ctx context.Context, profile *Profile) error
Delete(ctx context.Context, profile *Profile) error
FindByUserID(ctx context.Context, userId uuid.UUID) (*Profile, error)
FindAll(ctx context.Context, filter Filter) ([]*Profile, int, error)
}

View File

@@ -0,0 +1,9 @@
package profile
import "github.com/google/uuid"
type Role struct {
ID uuid.UUID
Level string // e.g. Junior, Senior, Lead
Title string
}

View File

@@ -0,0 +1,20 @@
package profile
import (
"context"
"errors"
"github.com/google/uuid"
)
var ErrRoleNotFound = errors.New("profile role not found")
// RoleRepository provides access to profile_roles (roles for profiles).
type RoleRepository interface {
FindByID(ctx context.Context, id uuid.UUID) (*Role, error)
FindAll(ctx context.Context) ([]*Role, error)
List(ctx context.Context, limit, offset int) ([]*Role, error)
Create(ctx context.Context, role *Role) error
Update(ctx context.Context, role *Role) error
Delete(ctx context.Context, id uuid.UUID) error
}

View File

@@ -0,0 +1,6 @@
package profile
type Skill struct {
SkillName string
Level string
}

View File

@@ -0,0 +1,16 @@
package profile
import (
"time"
"github.com/google/uuid"
)
type Achievement struct {
ID uuid.UUID
ProfileID uuid.UUID
Name string
Description string
CreatedAt time.Time
UpdatedAt time.Time
}

View File

@@ -0,0 +1,16 @@
package profile
import (
"time"
"github.com/google/uuid"
)
type AvailabilityException struct {
ID uuid.UUID
ProfileID uuid.UUID
Date time.Time
Start *time.Time
End *time.Time
DayUnavailable bool
}

View File

@@ -0,0 +1,16 @@
package profile
import (
"time"
"github.com/google/uuid"
)
type AvailabilityRule struct {
ID uuid.UUID
ProfileID uuid.UUID
Title string
Weekday int // 0-6, where 0 is Sunday
Start time.Time
End time.Time
}

View File

@@ -0,0 +1,12 @@
package profile
import (
"github.com/google/uuid"
)
type Award struct {
ID uuid.UUID
ProfileID uuid.UUID
Name string
Description string
}

View File

@@ -0,0 +1,22 @@
package profile
import (
"github.com/google/uuid"
)
type BookingService struct {
ID uuid.UUID
ProfileID uuid.UUID
BookingServiceTypeID uuid.UUID
BookingServiceType BookingServiceType
Title string
Description string
Duration int // in minutes
Price int // in cents or smallest currency unit
MaxBookingDays int
}
type BookingServiceType struct {
ID uuid.UUID
Name string
}

View File

@@ -0,0 +1,12 @@
package profile
import (
"github.com/google/uuid"
)
type Certification struct {
ID uuid.UUID
ProfileID uuid.UUID
Name string
Description string
}

View File

@@ -0,0 +1,18 @@
package profile
import (
"time"
"github.com/google/uuid"
)
type Education struct {
ID uuid.UUID
ProfileID uuid.UUID
SchoolName string
Degree string
FieldOfStudy string
StartDate *time.Time
EndDate *time.Time
Description string
}

View File

@@ -0,0 +1,17 @@
package profile
import (
"time"
"github.com/google/uuid"
)
type Experience struct {
ID uuid.UUID
ProfileID uuid.UUID
CompanyName string
Position string
StartDate *time.Time
EndDate *time.Time
Description string
}

View File

@@ -0,0 +1,52 @@
package profile
import (
"encoding/json"
"time"
"github.com/google/uuid"
)
//go:generate stringer -type=Status
type Status int
const (
StatusPublished Status = iota
StatusDisabled
StatusPending
StatusDeleted
)
type Profile struct {
ID uuid.UUID
UserID uuid.UUID
ProfileHandle string
Status Status
Settings Settings
Skills []Skill
SocialLinks []SocialLink
Achievements []Achievement
Experiences []Experience
Educations []Education
Certifications []Certification
Awards []Award
AvailabilityRules []AvailabilityRule
AvailabilityExceptions []AvailabilityException
BookingServices []BookingService
// Note: These are typically loaded separately to avoid circular dependencies
// Assets, AssetBookmarkGroups, SpecialistBookmarks, PurchasedAssets, BookedServices
// are accessed through their respective repositories using ProfileID/UserID
CreatedAt time.Time
UpdatedAt time.Time
}
type Settings struct {
Theme ThemeSettings `json:"theme"`
Other json.RawMessage `json:"rest_of_fields"`
}
type ThemeSettings struct {
BackgroundColor string `json:"background_color"`
TextColor string `json:"text_color"`
RestOfFields json.RawMessage `json:"rest_of_fields"`
}

View File

@@ -0,0 +1,22 @@
package profile
import (
"github.com/google/uuid"
)
//go:generate stringer -type=SkillLevel
type SkillLevel int
const (
SkillLevelBeginner SkillLevel = iota
SkillLevelIntermediate
SkillLevelAdvanced
SkillLevelExpert
)
type Skill struct {
ID uuid.UUID
ProfileID uuid.UUID
Name string
Level SkillLevel
}

View File

@@ -0,0 +1,12 @@
package profile
import (
"github.com/google/uuid"
)
type SocialLink struct {
ID uuid.UUID
ProfileID uuid.UUID
LinkType string
Link string
}

View File

@@ -0,0 +1,67 @@
package purchase
import (
"encoding/json"
"time"
"github.com/google/uuid"
)
//go:generate stringer -type=BookingStatus
type BookingStatus int
const (
BookingStatusPending BookingStatus = iota
BookingStatusConfirmed
BookingStatusCancelled
BookingStatusCompleted
BookingStatusRescheduled
)
type BookedService struct {
ID uuid.UUID
UserID uuid.UUID
Service BookedServiceInfo
BookingDate time.Time
BookingPrice int // in cents or smallest currency unit
BookingCurrency string
BookingStatus BookingStatus
BookingReceipt string
HostUser UserInfo
GuestUser UserInfo
RescheduleHistory []RescheduleHistory
}
type BookedServiceInfo struct {
ID uuid.UUID
Name string
Description string
RestOfFields json.RawMessage
}
type UserInfo struct {
ID uuid.UUID
Name string
Description string
RestOfFields json.RawMessage
}
type RescheduleHistory struct {
ID uuid.UUID
BookedServiceID uuid.UUID
RequestedBy UserInfo
RequestedTo UserInfo
RequestedAt time.Time
Status string
Reason string
Notes string
Attachments []RescheduleAttachment
}
type RescheduleAttachment struct {
ID uuid.UUID
URL string
Type string
}

View File

@@ -0,0 +1,38 @@
package purchase
import (
"encoding/json"
"time"
"github.com/google/uuid"
)
//go:generate stringer -type=PurchaseStatus
type PurchaseStatus int
const (
PurchaseStatusPending PurchaseStatus = iota
PurchaseStatusCompleted
PurchaseStatusFailed
PurchaseStatusRefunded
)
type PurchasedAsset struct {
ID uuid.UUID
UserID uuid.UUID
Asset PurchasedAssetInfo
PurchaseDate time.Time
PurchasePrice int // in cents or smallest currency unit
PurchaseCurrency string
PurchaseStatus PurchaseStatus
PurchaseReceipt string
}
type PurchasedAssetInfo struct {
ID uuid.UUID
Name string
Description string
RestOfFields json.RawMessage
}

View File

@@ -0,0 +1,13 @@
package skill
import (
"context"
"github.com/google/uuid"
)
// Repository provides access to the skills catalog.
type Repository interface {
FindAll(ctx context.Context) ([]*Skill, error)
FindByID(ctx context.Context, id uuid.UUID) (*Skill, error)
}

View File

@@ -0,0 +1,9 @@
package skill
import "github.com/google/uuid"
// Skill represents a selectable skill from the catalog (for profile skill selection).
type Skill struct {
ID uuid.UUID
Name string
}

View File

@@ -0,0 +1,36 @@
package ticket
import (
"github.com/google/uuid"
)
//go:generate stringer -type=TicketStatus
type TicketStatus int
const (
TicketStatusOpen TicketStatus = iota
TicketStatusClosed
TicketStatusPending
TicketStatusDeleted
)
//go:generate stringer -type=TicketPriority
type TicketPriority int
const (
TicketPriorityLow TicketPriority = iota
TicketPriorityMedium
TicketPriorityHigh
)
type Ticket struct {
ID uuid.UUID
UserID uuid.UUID
Title string
Description string
Status TicketStatus
Priority TicketPriority
Category string
}