// Package domain holds pansy's core types: plain structs mirroring the database // schema and the sentinel errors the service layer returns. It has no // dependencies on store, api, or any framework — every other package depends on // it, not the other way around. package domain import "errors" // Sentinel errors returned by the service layer and mapped to HTTP status codes // by the API layer (404, 403, 409 respectively). var ( // ErrNotFound means the requested entity does not exist (or is invisible to // the actor, when we deliberately mask existence). ErrNotFound = errors.New("not found") // ErrForbidden means the actor is known but lacks permission for the action. ErrForbidden = errors.New("forbidden") // ErrVersionConflict means the row's version did not match the one supplied // with a PATCH/DELETE; the caller should refetch and retry. ErrVersionConflict = errors.New("version conflict") ) // Enumerated string values mirrored from the schema CHECK constraints. const ( UnitMetric = "metric" UnitImperial = "imperial" RoleViewer = "viewer" RoleEditor = "editor" KindBed = "bed" KindGrowBag = "grow_bag" KindContainer = "container" KindInGround = "in_ground" KindTree = "tree" KindPath = "path" KindStructure = "structure" ShapeRect = "rect" ShapeCircle = "circle" ShapePolygon = "polygon" // reserved for post-v1 CategoryVegetable = "vegetable" CategoryHerb = "herb" CategoryFlower = "flower" CategoryFruit = "fruit" CategoryTreeShrub = "tree_shrub" CategoryCover = "cover" ) // User is a pansy account. It may have a local password, OIDC identity, or both. type User struct { ID int64 `json:"id"` Email string `json:"email"` DisplayName string `json:"displayName"` PasswordHash *string `json:"-"` // never serialized OIDCIssuer *string `json:"-"` OIDCSubject *string `json:"-"` IsAdmin bool `json:"isAdmin"` Version int64 `json:"version"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` } // Session is a server-side session record. The raw token is never stored; only // its sha256 hash (the primary key) is. type Session struct { TokenHash string `json:"-"` UserID int64 `json:"userId"` ExpiresAt string `json:"expiresAt"` CreatedAt string `json:"createdAt"` } // Garden is a planning surface owned by one user, at real-world scale (cm). type Garden struct { ID int64 `json:"id"` OwnerID int64 `json:"ownerId"` Name string `json:"name"` WidthCM float64 `json:"widthCm"` HeightCM float64 `json:"heightCm"` UnitPref string `json:"unitPref"` Notes string `json:"notes"` Version int64 `json:"version"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` } // GardenShare grants a non-owner user viewer or editor access to a garden. type GardenShare struct { ID int64 `json:"id"` GardenID int64 `json:"gardenId"` UserID int64 `json:"userId"` Role string `json:"role"` CreatedBy int64 `json:"createdBy"` Version int64 `json:"version"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` } // GardenObject is any placeable object in a garden (bed, container, tree, path…). // Positioned by center point + rotation about center, in garden space. type GardenObject struct { ID int64 `json:"id"` GardenID int64 `json:"gardenId"` Kind string `json:"kind"` Name string `json:"name"` Shape string `json:"shape"` Points *string `json:"points,omitempty"` // reserved: JSON for polygons XCM float64 `json:"xCm"` YCM float64 `json:"yCm"` WidthCM float64 `json:"widthCm"` HeightCM float64 `json:"heightCm"` RotationDeg float64 `json:"rotationDeg"` ZIndex int `json:"zIndex"` Plantable bool `json:"plantable"` Color *string `json:"color,omitempty"` Props *string `json:"props,omitempty"` // kind-specific JSON Notes string `json:"notes"` Version int64 `json:"version"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` } // Plant is a catalog entry. OwnerID nil means a read-only seeded built-in. type Plant struct { ID int64 `json:"id"` OwnerID *int64 `json:"ownerId,omitempty"` // nil = built-in Name string `json:"name"` Category string `json:"category"` SpacingCM float64 `json:"spacingCm"` Color string `json:"color"` Icon string `json:"icon"` DaysToMaturity *int `json:"daysToMaturity,omitempty"` Notes string `json:"notes"` Version int64 `json:"version"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` } // Planting ("plop") is a circular patch of one plant, positioned in its parent // object's local frame. Count nil means it is derived from area / spacing². type Planting struct { ID int64 `json:"id"` ObjectID int64 `json:"objectId"` PlantID int64 `json:"plantId"` XCM float64 `json:"xCm"` YCM float64 `json:"yCm"` RadiusCM float64 `json:"radiusCm"` Count *int `json:"count,omitempty"` // nil = derived Label *string `json:"label,omitempty"` PlantedAt *string `json:"plantedAt,omitempty"` RemovedAt *string `json:"removedAt,omitempty"` Version int64 `json:"version"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` }