Skip to content

🏷️ Domain Models Overview

pkg/domain is the data structure layer of Composer Skills. It contains no business logic, only Go structs corresponding to Packagist REST API and Composer metadata, used by pkg/client (API client) and pkg/repository (repository access layer) for request/response deserialization.

One-line positioning

The domain package is the contract layer for "network bytes → Go structs": whatever JSON the API returns, there's a corresponding struct here.

📦 Package Path

  • Import path: github.com/scagogogo/composer-skills/pkg/domain
  • Package name: domain
  • Dependencies: Only depends on Go standard library (time), zero external dependencies, can be safely imported by any module

🧩 Why a Separate Domain Layer

ConcernDescription
🔄 DecouplingAPI client (pkg/client) only handles HTTP, unaware of field meanings; business code only consumes structs, unaware of JSON
🧪 TestableTests can directly construct domain structs for assertions without mocking network
📊 PersistableMost fields have both json and bson tags, can be directly stored in MongoDB
🎯 Type safeMaps loose JSON to strongly typed Go fields, catches field typos at compile time

📋 Type List

Categorized into six groups by usage, each corresponding to a sub-document:

📦 Package Info Models — package.md

TypeUsageSource File
PackageInfoPackage basic info (name, description, GitHub stats, downloads, etc.)package.go
ComposerPackageInfoPackage complete info (includes lowercase name, md5, three timestamps)package.go
PackageDownloadsDownload stats (total/monthly/daily)package.go
MaintainerMaintainer (name, avatar)maintainer.go
VersionSingle version's complete metadata (dependencies, source, dist, license, etc.)version.go

🔒 Security Advisory Models — advisory.md

TypeUsageSource File
AdvisoriesResponseSecurity advisory top-level response (grouped by package name)advisory.go
AdvisorySingle security advisory (CVE, affected versions, source)advisory.go
SourceAdvisory source (GitHub, NVD, etc.)advisory.go

🔍 Search Result Models — search.md

TypeUsageSource File
SearchResponseSearch response top-level (result list + pagination)search.go
SearchResultSingle search resultsearch.go

📊 Statistics Models — statistics.md

TypeUsageSource File
StatisticsResponseRepository statistics top-levelstatistics.go
TotalsRepository totals (downloads/packages/versions)statistics.go
PackageStatsResponseSingle package download statspackage_stats.go
ChangeTrackingResponseMetadata change tracking responsepackage_stats.go
ChangeActionSingle change action (update/delete)package_stats.go

🛠️ Create/Edit/List Models — create-package.md

TypeUsageSource File
PackageCreateRequest / PackageCreateResponseCreate packagecreate_package.go
PackageEditRequest / PackageEditResponseEdit packagecreate_package.go
PackageUpdateRequest / PackageUpdateResponseUpdate packagecreate_package.go
PackageListResponsePackage name listpackage_list.go
PackageListWithDataResponsePackage list with additional datapackage_list.go
PackageDataPackage additional data (type/repository/abandoned status)package_list.go
PopularPackagesResponse / PopularPackagePopular package listpopular_packages.go

🔗 Type to API Method Mapping

The following table lists pkg/client.ComposerClient methods with their corresponding input/output domain types:

ComposerClient MethodInput domain typeReturn domain type
GetPackage*ComposerPackageInfo
GetStatistics*StatisticsResponse
GetSecurityAdvisories*AdvisoriesResponse
GetSecurityAdvisoriesForPackages*AdvisoriesResponse
GetSecurityAdvisoriesSince*AdvisoriesResponse
ListPackages / ListPackagesByVendor / ListPackagesByType*PackageListResponse
ListPackagesWithData*PackageListWithDataResponse
ListPopularPackages*PopularPackagesResponse
SearchPackages / SearchPackagesByTags / SearchPackagesByType*SearchResponse
GetPackageStats*PackageStatsResponse
GetPackageChanges*ChangeTrackingResponse
CreatePackage*PackageCreateRequest*PackageCreateResponse
EditPackage*PackageEditRequest*PackageEditResponse
UpdatePackage*PackageUpdateRequest*PackageUpdateResponse

Also applies to Repository layer

pkg/repository.Repository methods (like Statistics, ListSecurityAdvisories, ListAdvisories) also reuse the same domain types, ensuring consistent behavior across layers.

🚀 Quick Example

After getting package info from Packagist, the domain struct looks like this:

go
package main

import (
    "fmt"
    "log"
    "time"

    "github.com/scagogogo/composer-skills/pkg/client"
    "github.com/scagogogo/composer-skills/pkg/domain"
)

func main() {
    c := client.NewComposerClient(30*time.Second)
    info, err := c.GetPackage("symfony/console")
    if err != nil {
        log.Fatalf("Failed to get package info: %v", err)
    }

    // info is *domain.ComposerPackageInfo
    fmt.Printf("Package name: %s\n", info.PackageName)
    fmt.Printf("Description: %s\n", info.Package.Description)
    fmt.Printf("Total downloads: %d\n", info.Package.Downloads.Total)
    fmt.Printf("GitHub Stars: %d\n", info.Package.GithubStars)
    for name := range info.Package.Versions {
        fmt.Printf("Version: %s\n", name)
    }
}

📚 Next Steps

Released under the MIT License