turash/bugulma/backend/internal/domain/community_listing.go

149 lines
6.2 KiB
Go

package domain
import (
"context"
"fmt"
"time"
"github.com/lib/pq"
"gorm.io/datatypes"
)
// CommunityListingType defines the type of community listing
type CommunityListingType string
const (
CommunityListingTypeProduct CommunityListingType = "product"
CommunityListingTypeService CommunityListingType = "service"
CommunityListingTypeTool CommunityListingType = "tool"
CommunityListingTypeSkill CommunityListingType = "skill"
CommunityListingTypeNeed CommunityListingType = "need"
)
// CommunityListingPriceType defines how the listing is priced
type CommunityListingPriceType string
const (
CommunityListingPriceTypeFree CommunityListingPriceType = "free"
CommunityListingPriceTypeSale CommunityListingPriceType = "sale"
CommunityListingPriceTypeRent CommunityListingPriceType = "rent"
CommunityListingPriceTypeTrade CommunityListingPriceType = "trade"
CommunityListingPriceTypeBorrow CommunityListingPriceType = "borrow"
)
// CommunityListingStatus defines the status of a listing
type CommunityListingStatus string
const (
CommunityListingStatusActive CommunityListingStatus = "active"
CommunityListingStatusReserved CommunityListingStatus = "reserved"
CommunityListingStatusCompleted CommunityListingStatus = "completed"
CommunityListingStatusArchived CommunityListingStatus = "archived"
)
// CommunityListingCondition defines the condition of a product/tool
type CommunityListingCondition string
const (
CommunityListingConditionNew CommunityListingCondition = "new"
CommunityListingConditionLikeNew CommunityListingCondition = "like_new"
CommunityListingConditionGood CommunityListingCondition = "good"
CommunityListingConditionFair CommunityListingCondition = "fair"
CommunityListingConditionNeedsRepair CommunityListingCondition = "needs_repair"
)
// CommunityListing represents a listing created by a community member (user)
// This extends the platform beyond business-only listings to enable "I Don't Know Who Has What" for citizens
type CommunityListing struct {
ID string `gorm:"primaryKey;type:text"`
UserID string `gorm:"not null;type:text;index"` // References users table
User *User `gorm:"foreignKey:UserID"` // User who created the listing
// Listing Information
Title string `gorm:"not null;type:varchar(255);index"`
Description string `gorm:"type:text"`
ListingType CommunityListingType `gorm:"not null;type:varchar(50);index"`
Category string `gorm:"not null;type:varchar(100);index"`
Subcategory string `gorm:"type:varchar(100)"`
// For Products/Tools
Condition *CommunityListingCondition `gorm:"type:varchar(50)"` // Condition of item (new, like_new, good, etc.)
Price *float64 `gorm:"type:decimal(10,2)"` // NULL = free
PriceType *CommunityListingPriceType `gorm:"type:varchar(50)"` // free, sale, rent, trade, borrow
// For Services/Skills
ServiceType *string `gorm:"type:varchar(50)"` // 'offering' or 'seeking'
Rate *float64 `gorm:"type:decimal(10,2)"` // Rate for service/skill
RateType *string `gorm:"type:varchar(50)"` // 'hourly', 'fixed', 'negotiable', 'free', 'trade'
// Availability
AvailabilityStatus string `gorm:"type:varchar(20);default:'available';index"` // available, limited, reserved, unavailable
AvailabilitySchedule datatypes.JSON `gorm:"type:jsonb"` // Time-based availability schedule
QuantityAvailable *int `gorm:"type:integer"` // For products (NULL = unlimited)
// Location
Location Point `gorm:"type:geometry(Point,4326)"` // PostGIS geometry point
PickupAvailable bool `gorm:"default:true"` // Can be picked up
DeliveryAvailable bool `gorm:"default:false"` // Can be delivered
DeliveryRadiusKm *float64 `gorm:"type:decimal(5,2)"` // Delivery radius in km
// Media
Images pq.StringArray `gorm:"type:text[]"` // Array of image URLs
// Metadata
Tags pq.StringArray `gorm:"type:text[]"` // Searchable tags array
SearchKeywords string `gorm:"type:text"` // Full-text search keywords
// Trust & Verification
UserRating *float64 `gorm:"type:decimal(3,2)"` // Average rating from reviews (0-5)
ReviewCount int `gorm:"default:0"` // Number of reviews
Verified bool `gorm:"default:false"` // Platform verification
// Status
Status CommunityListingStatus `gorm:"type:varchar(20);default:'active';index"` // active, reserved, completed, archived
// Timestamps
CreatedAt time.Time `gorm:"autoCreateTime"`
UpdatedAt time.Time `gorm:"autoUpdateTime"`
ExpiresAt *time.Time `gorm:"type:timestamp with time zone"` // Auto-archive after expiration
}
// TableName specifies the table name for GORM
func (CommunityListing) TableName() string {
return "community_listings"
}
// Validate performs business rule validation
func (cl *CommunityListing) Validate() error {
if cl.Title == "" {
return fmt.Errorf("listing title cannot be empty")
}
if cl.Category == "" {
return fmt.Errorf("listing category cannot be empty")
}
if cl.UserID == "" {
return fmt.Errorf("user ID cannot be empty")
}
if cl.Price != nil && *cl.Price < 0 {
return fmt.Errorf("price cannot be negative")
}
if cl.Rate != nil && *cl.Rate < 0 {
return fmt.Errorf("rate cannot be negative")
}
return nil
}
// CommunityListingRepository defines operations for community listing management
type CommunityListingRepository interface {
Create(ctx context.Context, listing *CommunityListing) error
GetByID(ctx context.Context, id string) (*CommunityListing, error)
GetByUser(ctx context.Context, userID string) ([]*CommunityListing, error)
GetByType(ctx context.Context, listingType CommunityListingType) ([]*CommunityListing, error)
GetByCategory(ctx context.Context, category string) ([]*CommunityListing, error)
SearchWithLocation(ctx context.Context, query string, location *Point, radiusKm float64) ([]*CommunityListing, error)
GetNearby(ctx context.Context, lat, lng, radiusKm float64) ([]*CommunityListing, error)
Update(ctx context.Context, listing *CommunityListing) error
Delete(ctx context.Context, id string) error
GetAll(ctx context.Context) ([]*CommunityListing, error)
}