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) }