🏷️ 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
| Concern | Description |
|---|---|
| 🔄 Decoupling | API client (pkg/client) only handles HTTP, unaware of field meanings; business code only consumes structs, unaware of JSON |
| 🧪 Testable | Tests can directly construct domain structs for assertions without mocking network |
| 📊 Persistable | Most fields have both json and bson tags, can be directly stored in MongoDB |
| 🎯 Type safe | Maps 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
| Type | Usage | Source File |
|---|---|---|
PackageInfo | Package basic info (name, description, GitHub stats, downloads, etc.) | package.go |
ComposerPackageInfo | Package complete info (includes lowercase name, md5, three timestamps) | package.go |
PackageDownloads | Download stats (total/monthly/daily) | package.go |
Maintainer | Maintainer (name, avatar) | maintainer.go |
Version | Single version's complete metadata (dependencies, source, dist, license, etc.) | version.go |
🔒 Security Advisory Models — advisory.md
| Type | Usage | Source File |
|---|---|---|
AdvisoriesResponse | Security advisory top-level response (grouped by package name) | advisory.go |
Advisory | Single security advisory (CVE, affected versions, source) | advisory.go |
Source | Advisory source (GitHub, NVD, etc.) | advisory.go |
🔍 Search Result Models — search.md
| Type | Usage | Source File |
|---|---|---|
SearchResponse | Search response top-level (result list + pagination) | search.go |
SearchResult | Single search result | search.go |
📊 Statistics Models — statistics.md
| Type | Usage | Source File |
|---|---|---|
StatisticsResponse | Repository statistics top-level | statistics.go |
Totals | Repository totals (downloads/packages/versions) | statistics.go |
PackageStatsResponse | Single package download stats | package_stats.go |
ChangeTrackingResponse | Metadata change tracking response | package_stats.go |
ChangeAction | Single change action (update/delete) | package_stats.go |
🛠️ Create/Edit/List Models — create-package.md
| Type | Usage | Source File |
|---|---|---|
PackageCreateRequest / PackageCreateResponse | Create package | create_package.go |
PackageEditRequest / PackageEditResponse | Edit package | create_package.go |
PackageUpdateRequest / PackageUpdateResponse | Update package | create_package.go |
PackageListResponse | Package name list | package_list.go |
PackageListWithDataResponse | Package list with additional data | package_list.go |
PackageData | Package additional data (type/repository/abandoned status) | package_list.go |
PopularPackagesResponse / PopularPackage | Popular package list | popular_packages.go |
🔗 Type to API Method Mapping
The following table lists pkg/client.ComposerClient methods with their corresponding input/output domain types:
| ComposerClient Method | Input domain type | Return 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:
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
- 📦 Want to understand package detail fields → package.md
- 🔒 Care about security auditing → advisory.md
- 🔍 Doing package search → search.md
- 📊 Viewing repository/package statistics → statistics.md
- 🛠️ Need to create/edit packages → create-package.md