Project Collection
Designer-created collection or favorites list of products. Aggregate root for add, remove, select, and portal publish.
Purpose
A user product collection is a designer-curated list of products for a project or design workflow. Short domain name: Collection. Catalog identity lives in product-marketplace; this aggregate holds ProductReference values on its items.
Manufacturer or vendor product lines are VendorProductCollection, not this aggregate.
Products enter a project from Product Marketplace Add to Project (or Design Add Item to Project). That path finds or creates the default Project Collection (collectionKind=default, name {projectName}-default) and upserts Project Product Variant rows (ADR-0083). Graph assignment is a separate PDG command. Extra lists on the same project add membership on the existing item (add-items). Do not create a second item for a variant already on the project.
Invariants
nameis required and non-empty after trim.coverImageUrl, when set, must be an absolutehttporhttpsURL.collectionKindisdefaultorcurated.create()writes curated.createDefault()writes default, requiresprojectId, and names the collection{projectName}-default.- Default collections cannot be renamed (
DefaultCollectionCannotBeRenamedError). - Copy Collection is Airtable-only and always writes
collection_kind=curatedso a default source cannot produce a second default. - Mutations (
addItem,addProductReferences,removeItems,select,publishToPortal,unpublishFromPortal,rename) require statusactive. - Two active items cannot share the same product reference (
DuplicateProjectCollectionItemError).addProductReferencescounts duplicates and continues;addItemfails. removeItemsmarks matching active itemsdeleted. Persistence unlinks deleted items from the parent collection rather than always destroying the Airtable row.select(true|false)sets the collection script flag and copies that value onto every active item.unpublishFromPortalis a no-op when alreadydraft(keepslastUnpublishedAt).
Domain Events
None. The module glossary records that earlier event types were removed because no dispatcher consumed them and use cases already return application results. Do not invent events.