Catalogue & product data
Product Collections
Generated from docs/plan/core/product-collections/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
Core feature for merchants to curate themed product groups (e.g., ‘Summer Sale’, ‘Gift Ideas’, ‘New Arrivals’). Collections are manual or rule-based groupings of products, distinct from categories. A product can appear in many collections; collections can be featured on the storefront. This is foundational merchandising infrastructure.
The problem
Merchants need to curate themed product groups (e.g., ‘Summer Sale’, ‘Gift Ideas’); static categories don’t fit.
What it does
- Create collection: name, slug (auto-generated), description, optional banner/image, is_active
- Manual product selection: admin manually adds/removes products to/from a collection
- Rule-based collection (optional): collection auto-populates based on criteria (e.g., ‘all products tagged “sale”’, ‘all products in category “tops”’)
- Collection visibility: is_active toggles visibility on storefront; inactive collections are not listed
- Product reordering within collection: reorder products for featured display (e.g., bestsellers first)
- Product count: show how many products in collection (including rule-based)
- Collection page: GET /collections/:slug returns collection with products, description, image
- Collection list: GET /collections returns all active collections (storefront)
- Featured collection: admin can mark collection as ‘featured’ to promote on storefront
- Collection filters: GET /products?collection=:slug returns products in that collection
- SEO fields: meta title, meta description, OG image per collection
- Bulk collection assignment: assign many products to a collection via admin UI
What it deliberately does NOT do
Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.
- Dynamic collection generation (ML-powered ‘similar products’) — that’s merchandising plugin; core provides manual/rule-based only
- Scheduled collection activation (collection goes live on a date) — manual; use scheduler plugin for auto-activation
- Collection-specific pricing or promotions — that’s promotions tier; collections are grouping only
- Personalized collections per customer — that’s recommendation engine; core provides static collections only
- Collection A/B testing — that’s optimization plugin
Data model
New entity: collection (id, name: string (max 255), slug: string (unique), description: text (nullable), banner_image_url: string (nullable), is_active: boolean, is_featured: boolean, rule_based: boolean, rule_criteria: JSON (nullable, e.g., {type: ‘tag’, value: ‘sale’} or {type: ‘category’, value: ‘cat_123’}), position: integer (for ordering), created_at, updated_at). Link through collection_products join table (collection_id, product_id, position) for manual/rule-based products.
API
- GET /collections — list all active collections (public)
- POST /collections — create collection {name, description?, banner_image?, rule_based?, rule_criteria?}
- GET /collections/:slug — retrieve collection with products
- PUT /collections/:id — update collection (name, description, image, rule_criteria, active, featured)
- DELETE /collections/:id — soft delete collection
- POST /collections/:id/products/:product_id — add product to manual collection
- DELETE /collections/:id/products/:product_id — remove product from collection
- GET /products?collection=:slug — filter products by collection
- PUT /collections/:id/products/:product_id/position — reorder product within collection
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Collection management panel: (1) Collection list (name, product count, active/featured status, create/edit/delete buttons), (2) Create/edit modal (name, slug, description WYSIWYG, banner image uploader, active/featured toggles), (3) Rule builder (if rule_based=true, show criteria selector: Tag, Category, Price range, etc.), (4) Product assignment (search/select products, add to collection, drag-drop to reorder, remove button), (5) Collection preview (show on storefront).
The seam — why this is core
Core owns collection schema, CRUD, manual product selection, and rule engine (basic criteria only: tag, category, price, status). Advanced rule logic (complex boolean expressions, ML-driven) belongs in a merchandising plugin.
Core owns the interface + honest collection manager; product grouping is infrastructure, not a per-country obligation or credential.
Dependencies
- product-management (core; products link to collections)
- product-tags (core; rule-based collections can filter by tag)
- category-management (core; rule-based collections can filter by category)
Acceptance checks
Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.
- POST /collections with {name: ‘Summer Sale’} creates collection and returns {id: ‘col_abc’, slug: ‘summer-sale’, product_count: 0}.
- Manually adding 5 products to collection via POST /collections/:id/products/:product_id updates product_count=5.
- A rule-based collection with {rule_criteria: {type: ‘tag’, value: ‘bestseller’}} auto-includes all products tagged ‘bestseller’.
- Reordering products within collection (drag-drop or PUT /collections/:id/products/:product_id/position) changes their display order.
- GET /collections/:slug (public) returns only active collections; inactive collections return 404.
- Marking collection as is_featured=true shows it prominently on storefront homepage.
- Exporting collection as CSV includes product_id, name, price, position_in_collection.
- Deleting a rule-based collection does not delete the products; rule is removed, products remain tagged/categorized.
Risks
Rule-based collections that depend on tags or categories can break if those are deleted (collection includes nothing or errors). If product reordering is not persisted correctly, the order resets on page reload. If a rule uses outdated criteria (e.g., old tag name), collection becomes stale.
Commercial context
| Suggested price | free (core) |
| Rival anchor | Shopify: included (Collections); Magento: included |
The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.
Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full
catalogue and ../../AI-GUIDE.md for how to work on this repository.