feat: manage fruits — full CRUD with images and synonyms (story #02)
Backend: domain structs, FruitRepository interface + pg implementation,
9 Echo v4 handlers (list/get/create/update/delete, image sub-resources),
migration 000002 (fruit_type ENUM, fruits, fruit_synonyms, fruit_images),
route-scoped BodyLimit("5M") for uploads, http.DetectContentType for serving.
Frontend: typed fetch API layer, Pinia setup-style fruitStore, FruitList
(paginated), FruitCreate, and FruitDetail (edit + synonyms editor + image
gallery). 25 backend unit tests + integration test; 18 frontend tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type Fruit struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
OSDBNumber string `json:"osdb_number"`
|
||||
Comment *string `json:"comment"`
|
||||
FruitType string `json:"fruit_type"`
|
||||
Synonyms []string `json:"synonyms"`
|
||||
Images []FruitImage `json:"images"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type FruitImage struct {
|
||||
ID int `json:"id"`
|
||||
FruitID int `json:"fruit_id"`
|
||||
Filename *string `json:"filename"`
|
||||
ImageType string `json:"image_type"`
|
||||
Title *string `json:"title"`
|
||||
URL string `json:"url"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type FruitWriteDTO struct {
|
||||
Name string `json:"name"`
|
||||
OSDBNumber string `json:"osdb_number"`
|
||||
Comment *string `json:"comment"`
|
||||
FruitType string `json:"fruit_type"`
|
||||
Synonyms []string `json:"synonyms"`
|
||||
}
|
||||
|
||||
type FruitListResponse struct {
|
||||
Items []Fruit `json:"items"`
|
||||
Total int `json:"total"`
|
||||
Limit int `json:"limit"`
|
||||
Offset int `json:"offset"`
|
||||
}
|
||||
Reference in New Issue
Block a user