Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/PloutusLab/krafta-web/llms.txt

Use this file to discover all available pages before exploring further.

Every item available on Krafta is modelled as a Product with one or more ProductVariant records, where each variant owns exactly one PrintTemplate that tells the Fabric.js editor where to overlay the customer’s design on the mockup image. This hierarchy gives the platform the flexibility to represent simple single-SKU products as well as multi-colour, multi-size items with independent pricing and print areas.

Data model

Product
 ├─ id, name, description
 ├─ active (Boolean)
 ├─ categoryId → Category
 ├─ images (JSON string array of commercial photo URLs)
 ├─ svgContent (optional — the Master Interactive SVG mockup)
 └─ variants[]
      └─ ProductVariant
           ├─ id, sku (unique), basePrice (Decimal)
           ├─ attributes (Json — e.g. { "color": "Blanco", "talla": "M" })
           ├─ active (Boolean)
           └─ printTemplate → PrintTemplate
                ├─ mockupImageUrl
                ├─ printAreaX / printAreaY / printAreaWidth / printAreaHeight (0–100%)
                ├─ rotation (Decimal, default 0)
                ├─ shape ("RECTANGLE" | "ELLIPSE")
                └─ minDpi (Int, default 150)
The images field on Product stores a JSON-serialised array of commercial photo URLs used in the storefront carousel. The optional svgContent field holds the Master Interactive SVG, which contains the product mockup plus krafta-var- elements that the editor exposes as customer-adjustable colour variables.

Active flags

Both Product and ProductVariant have an active Boolean field. Setting either to false soft-deletes the record — it is excluded from all public API responses — without removing any data from the database. This lets administrators take a product offline for revision, restock, or repricing and bring it back later without losing its history or associated orders. A product is automatically set to active: false when it is created without a valid mockup image. The admin catalog UI shows these products so they can be completed before publishing.

API endpoints

GET /api/catalog?summary=1 — catalog card payload

Returns a light list of all active products, suitable for rendering the homepage grid and catalog listing pages. The svgContent field is omitted. Only active variants are included.
{
  "success": true,
  "products": [
    {
      "id": "prod-1",
      "name": "Camiseta Básica Unisex",
      "description": "Franela de algodón fresca y cómoda para uso diario.",
      "active": true,
      "categoryId": "cat-1",
      "category": { "name": "Camisetas" },
      "thumbnailUrl": "/mockups/franela.png",
      "images": "[\"/mockups/franela.png\"]",
      "variants": [
        {
          "id": "var-1",
          "sku": "CAM-BASE-M-BLANCO",
          "basePrice": 12.00,
          "attributes": { "color": "Blanco", "talla": "M" },
          "printTemplate": {
            "mockupImageUrl": "/mockups/franela.png",
            "printAreaX": 20,
            "printAreaY": 20,
            "printAreaWidth": 60,
            "printAreaHeight": 60,
            "rotation": 0,
            "shape": "RECTANGLE",
            "minDpi": 150
          }
        }
      ]
    }
  ]
}

GET /api/catalog?id=<id> — full product for the editor

Returns a single product with all its active variants and their complete PrintTemplate data. The svgContent field is included so the design editor can mount the interactive SVG mockup.
{
  "success": true,
  "product": {
    "id": "prod-1",
    "name": "Camiseta Básica Unisex",
    "svgContent": "<svg ...>...</svg>",
    "variants": [ { "...": "full variant object with printTemplate" } ]
  }
}

GET /api/catalog?admin=1 — admin management view

When the admin=1 query parameter is present the active filter is removed from the Prisma query, returning both active and inactive products. This endpoint is called by the admin catalog manager and requires the ADMIN role via requireRole() on the mutation methods of the same route.

Default catalog seed

The catalog route includes a DEFAULT_CATALOG constant that serves as an in-memory fallback when the database is unavailable. The three seeded products are:
NameSKU(s)Base PriceCategory
Camiseta Básica UnisexCAM-BASE-M-BLANCO, CAM-BASE-M-NEGRO$12.00Camisetas
Libreta Creativa A5LIB-CREA-A5$8.00Libretas
Taza de Cerámica 11ozTAZ-CER-11OZ$6.00Tazas
PrintTemplate coordinates are stored as percentages of the mockup image dimensions, not as pixel values. A printAreaX of 20 means the print area starts 20% from the left edge of the mockup image regardless of the rendered image size. This makes templates resolution-independent and allows the same template to work correctly when the editor is displayed on screens of different sizes.
mockup image (100% × 100%)
┌─────────────────────────────┐
│                             │
│    ┌──────────────────┐     │  ← printAreaY (e.g. 20%)
│    │   print area     │     │
│    │  (printAreaWidth │     │
│    │  × printAreaHeight)    │
│    └──────────────────┘     │
│                             │
└─────────────────────────────┘

     printAreaX (e.g. 20%)

Workshop pricing

basePrice on ProductVariant is the platform floor price — the minimum retail price a creator may charge. The production cost is stored separately in WorkshopOffer.cost, which represents what the allied workshop charges Krafta to produce one unit. The getVariantPricing() function in src/lib/pricing.js resolves both values for a given variant:
const unitPrice = toNumber(variant.basePrice);   // retail floor
const unitCost  = toNumber(offer.cost);           // workshop production cost
If no active WorkshopOffer exists for a variant, the pricing function returns requiresReview: true, and the order must go through a manual quotation flow instead of the standard checkout.

Build docs developers (and LLMs) love