Krafta is a monolithic Next.js application that co-locates the customer-facing storefront, the design editor, and the full backend API in a single codebase. There is no separate API service or microservices layer: all server logic runs as Next.js Route Handlers underDocumentation 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.
/api/*, all data lives in a single Prisma-managed SQLite (or libSQL) database, and all file storage uses Supabase Storage private buckets with an automatic local filesystem fallback during development. Authentication is handled by HMAC-SHA256 JWTs verified at the edge in a Next.js middleware, keeping protected routes gated without a round-trip to the database for every request.
Architectural layers
Storefront
The customer-facing pages —/ (homepage), /catalog, /product/[id], /cart, /checkout, and /orders/[id] — are standard Next.js App Router pages. They fetch product and order data from the /api/* layer and render with React 19 server and client components. Tailwind CSS 4 and the Poppins variable font (loaded via next/font/google) provide the visual system. The <Header /> component is included in the root layout.js and rendered on every page.
Design Editor
The design editor lives at/editor and /product/[id]/customize. It renders a Fabric.js 7 canvas on top of a product’s SVG mockup. The canvas reads the print area dimensions from the PrintTemplate record associated with the active ProductVariant — fields printAreaX, printAreaY, printAreaWidth, printAreaHeight, and rotation are all stored as percentages relative to the mockup image. The interactive SVG mockup stores its printable zone as an element with the reserved ID krafta-print-area, which the editor uses for visual alignment. Customers can upload PNG, JPG, SVG, or PDF files (up to 20 MB), reposition and scale their artwork, switch between multiple product views (e.g. front, back), and generate a preview data URL that is stored as previewUrl on the OrderItem record. The react-moveable library powers the drag, scale, and rotate handles on the canvas.
API Layer
All server-side logic is exposed through Next.js Route Handlers under/api/*. The table below lists every endpoint in the codebase:
| Route | Methods | Purpose |
|---|---|---|
/api/auth/register | POST | Create a new CLIENTE user, issue JWT cookie |
/api/auth/login | POST | Verify credentials, issue JWT cookie |
/api/auth/logout | POST | Clear the krafta-token cookie |
/api/auth/me | GET | Return current user profile from JWT |
/api/auth/convert-creator | POST | Upgrade a CLIENTE to the CREADOR role |
/api/catalog | GET | List active products with variants and categories |
/api/catalog | POST | Create a new product and variant (ADMIN only) |
/api/catalog | PUT | Update an existing product, variant, and print template (ADMIN only) |
/api/catalog | DELETE | Delete a product by ID (ADMIN only) |
/api/quotes | POST | Create a Quote with frozen item prices and exchange rate |
/api/quotes | PUT | Admin reviews and updates a quote with pricing (ADMIN only) |
/api/quotes | GET | List all quotes (ADMIN only) |
/api/orders | POST | Convert an approved Quote into an Order |
/api/orders | GET | List orders for the authenticated user |
/api/orders | PUT | Update order status (ADMIN or TALLER only) |
/api/payments | POST | Submit a PaymentSubmission with receipt upload |
/api/payments | PUT | Admin confirms or rejects a payment submission (ADMIN only) |
/api/payments/accounts | GET | List active PaymentAccount records for checkout |
/api/upload | POST | Upload a design file to Supabase or local filesystem |
/api/users | GET | List users (ADMIN only) |
/api/workshops | GET | List all workshops (ADMIN only) |
/api/workshop | GET | Return the workshop profile for the authenticated TALLER user |
/api/settings | GET | Return public platform settings |
/api/reviews | GET | List product reviews |
prisma from src/lib/prisma.js and, where file storage is needed, conditionally uses the supabase client from src/lib/supabase.js or falls back to fs writes into public/uploads/.
The dual storage pattern appears throughout every API route that handles file I/O. The check is consistent across the codebase: if
NEXT_PUBLIC_SUPABASE_URL is set and does not contain the string "placeholder", and NEXT_PUBLIC_SUPABASE_ANON_KEY is set and does not contain "placeholder", the route uploads to the appropriate Supabase private bucket (designs or receipts); otherwise it writes to public/uploads/{userId}/{uuid}{ext} and returns a relative URL. This makes the entire platform functional without any cloud credentials during local development.Middleware
src/middleware.js runs in the Next.js Edge Runtime and protects three route groups:
krafta-token cookie and verifies the HMAC-SHA256 signature using the Web Crypto API (crypto.subtle.verify). It also checks the exp claim for token expiry. The decoded payload carries a role field that is compared against the required role for each route group:
| Route prefix | Required role |
|---|---|
/admin | ADMIN |
/workshop/dashboard | TALLER or ADMIN |
/creator/dashboard | CREADOR or ADMIN |
/creator with a localised error message and a redirect query parameter so the login page can return the user to their intended destination after authentication.
Database
Prisma 6 with the@prisma/adapter-libsql adapter manages the schema. In development, DATABASE_URL points to a local SQLite file (file:./dev.db). In production the same adapter connects to a Turso libSQL instance via a remote URL. The schema defines the following models:
| Model | Purpose |
|---|---|
User | All platform accounts; carries the Role enum (CLIENTE, CREADOR, TALLER, ADMIN) |
Creator | One-to-one extension of User for creator accounts; holds approved flag and links to CreatorStore and CreatorDesign |
CreatorStore | Public storefront at /creator/[slug] |
CreatorDesign | Design file record linked to a creator |
CreatorDesignListing | Maps a CreatorDesign to a ProductVariant at a creator-set retail price |
CreatorEarning | Per-OrderItem earnings record for a creator; queued for payout |
CreatorPayout | Batch payout disbursement to a creator |
Product | Catalog product with commercial image carousel (images JSON) and master SVG (svgContent) |
ProductVariant | SKU-level record with attributes JSON, basePrice, and optional PrintTemplate |
PrintTemplate | Print area geometry (x, y, width, height, rotation as percentages) for a variant |
DesignUpload | Uploaded design file record with magic-bytes validation result |
Quote | Price snapshot (subtotal, shipping, exchange rate, expiry) before order creation |
QuoteItem | Frozen line item inside a Quote |
Order | Placed order with shipping address, totals in USD and Bs, and PaymentStatus |
OrderItem | Line item inside an Order; stores previewUrl, designUploadId, and cost snapshot |
PaymentAccount | Platform’s bank accounts and Pago Móvil numbers shown at checkout |
PaymentSubmission | Customer’s payment proof with receipt URL, reported amount, and verification status |
PaymentVerificationLog | Audit trail of admin confirm/reject/refund actions on an order |
Refund | Refund record linked to an order |
Workshop | Allied workshop with capacity, SLA, payment policy, and geographic coverage |
WorkshopUser | Links a TALLER user account to a Workshop |
WorkshopOffer | A workshop’s cost offer for a specific ProductVariant |
WorkshopCoverage | State/city coverage zones for a workshop |
ProductionAssignment | Assignment of an OrderItem to a workshop; tracks AssignmentStatus |
WorkshopPayable | Scheduled payment installment from platform to workshop |
BusinessExpense | Platform operating expense records |
SurfaceTemplateVersion | Versioned mockup template configuration (manifest JSON) |
MockupScene | Rendering layers (base image, mask, shadow, highlight, displacement map) for a mockup scene |
State | Venezuelan state for shipping zone lookup |
City | City within a State for shipping rate resolution |
ServiceZone | Named service zone used in shipping rate definitions |
ShippingRate | Shipping cost and estimated days per DeliveryMethod, scoped to a city, state, or zone |
FulfillmentRule | Default origin city and preferred delivery method per destination state |
Storage
Two Supabase Storage private buckets are used in production:designs— customer-uploaded artwork files (PNG, JPG, SVG). Access is mediated via signed URLs generated on demand from server-side API routes; thefileUrlcolumn inDesignUploadstores only the internal Supabase storage path, not a public URL.receipts— payment receipt images uploaded during the payment submission flow (PDF or image). Stored under the same private-bucket pattern.
public/uploads/{userId}/ on the local filesystem, and fileUrl stores a relative path such as /uploads/{userId}/{uuid}.png.
Customer order data flow
The following sequence traces a single order from first visit to delivery:-
Catalog browse — The customer visits
/catalog, which callsGET /api/catalogto fetch activeProductrecords with theirProductVariantchildren. Each variant carries thebasePriceand availableWorkshopOfferdata needed to display prices. -
Product detail — At
/product/[id]the customer selects a variant and sees the commercial photo carousel fromProduct.images. -
Design editor — Navigating to
/product/[id]/customize(or/editor) loads the Fabric.js canvas. The customer uploads their artwork viaPOST /api/upload; the file is stored in thedesignsbucket (or locally) and aDesignUploadrecord is created. The canvas generates a preview data URL (previewUrl) when the customer is satisfied. -
Cart and quote — Adding to cart triggers
POST /api/quotes, which creates aQuotewith frozen prices and the current USD/Bs exchange rate. Quotes have an expiry timestamp (expiresAt) to prevent stale pricing. -
Checkout — At
/checkoutthe customer retrieves activePaymentAccountrecords viaGET /api/payments/accountsand selects a bank transfer or Pago Móvil account. They enter the payment reference and upload a receipt image. -
Payment submission —
POST /api/paymentscreates aPaymentSubmissionwithstatus: REPORTED. The order’s ownPaymentStatusadvances toREPORTED. The receipt file is stored in thereceiptsbucket. -
Admin verification — An
ADMINuser reviews the submission at/admin/payments. On confirmation, thePaymentSubmissionstatus becomesCONFIRMED, theOrderstatus advances toCONFIRMED, and aPaymentVerificationLogentry is written. On rejection, arejectionReasonis recorded and the customer is notified. -
Workshop assignment — With payment confirmed, the admin assigns each
OrderItemto an appropriate workshop via aProductionAssignmentrecord. The system matches workshops by theirWorkshopOfferfor the relevantProductVariantand theirWorkshopCoveragefor the delivery state. -
Production — The workshop operator sees the assignment in their dashboard at
/workshop/dashboard. They advance theAssignmentStatusthroughACCEPTED→IN_PRODUCTION→READY→HANDED_TO_DELIVERY. -
Delivery — Once the assignment reaches
COMPLETED, theOrderis closed. If aCreatorDesignListingwas involved, aCreatorEarningrecord is created and queued for payout.
Role enforcement
Roles are enforced at two levels:- Edge middleware (
src/middleware.js) — fast JWT verification in the Edge Runtime that blocks unauthenticated or under-privileged requests before they reach any Route Handler. Covers/admin,/workshop/dashboard, and/creator/dashboard. - API route guards — individual Route Handlers call a
requireRole()helper (fromsrc/lib/api-auth.js) that re-verifies the JWT from thekrafta-tokencookie and checks the role against the endpoint’s requirements. This double-check ensures that even direct API calls without a browser cookie are rejected correctly.
