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.

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 under /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:
RouteMethodsPurpose
/api/auth/registerPOSTCreate a new CLIENTE user, issue JWT cookie
/api/auth/loginPOSTVerify credentials, issue JWT cookie
/api/auth/logoutPOSTClear the krafta-token cookie
/api/auth/meGETReturn current user profile from JWT
/api/auth/convert-creatorPOSTUpgrade a CLIENTE to the CREADOR role
/api/catalogGETList active products with variants and categories
/api/catalogPOSTCreate a new product and variant (ADMIN only)
/api/catalogPUTUpdate an existing product, variant, and print template (ADMIN only)
/api/catalogDELETEDelete a product by ID (ADMIN only)
/api/quotesPOSTCreate a Quote with frozen item prices and exchange rate
/api/quotesPUTAdmin reviews and updates a quote with pricing (ADMIN only)
/api/quotesGETList all quotes (ADMIN only)
/api/ordersPOSTConvert an approved Quote into an Order
/api/ordersGETList orders for the authenticated user
/api/ordersPUTUpdate order status (ADMIN or TALLER only)
/api/paymentsPOSTSubmit a PaymentSubmission with receipt upload
/api/paymentsPUTAdmin confirms or rejects a payment submission (ADMIN only)
/api/payments/accountsGETList active PaymentAccount records for checkout
/api/uploadPOSTUpload a design file to Supabase or local filesystem
/api/usersGETList users (ADMIN only)
/api/workshopsGETList all workshops (ADMIN only)
/api/workshopGETReturn the workshop profile for the authenticated TALLER user
/api/settingsGETReturn public platform settings
/api/reviewsGETList product reviews
Each route imports 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:
export const config = {
  matcher: [
    "/admin/:path*",
    "/workshop/dashboard/:path*",
    "/creator/dashboard/:path*",
  ],
};
On every matched request the middleware reads the 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 prefixRequired role
/adminADMIN
/workshop/dashboardTALLER or ADMIN
/creator/dashboardCREADOR or ADMIN
Unauthorized requests are redirected to /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:
ModelPurpose
UserAll platform accounts; carries the Role enum (CLIENTE, CREADOR, TALLER, ADMIN)
CreatorOne-to-one extension of User for creator accounts; holds approved flag and links to CreatorStore and CreatorDesign
CreatorStorePublic storefront at /creator/[slug]
CreatorDesignDesign file record linked to a creator
CreatorDesignListingMaps a CreatorDesign to a ProductVariant at a creator-set retail price
CreatorEarningPer-OrderItem earnings record for a creator; queued for payout
CreatorPayoutBatch payout disbursement to a creator
ProductCatalog product with commercial image carousel (images JSON) and master SVG (svgContent)
ProductVariantSKU-level record with attributes JSON, basePrice, and optional PrintTemplate
PrintTemplatePrint area geometry (x, y, width, height, rotation as percentages) for a variant
DesignUploadUploaded design file record with magic-bytes validation result
QuotePrice snapshot (subtotal, shipping, exchange rate, expiry) before order creation
QuoteItemFrozen line item inside a Quote
OrderPlaced order with shipping address, totals in USD and Bs, and PaymentStatus
OrderItemLine item inside an Order; stores previewUrl, designUploadId, and cost snapshot
PaymentAccountPlatform’s bank accounts and Pago Móvil numbers shown at checkout
PaymentSubmissionCustomer’s payment proof with receipt URL, reported amount, and verification status
PaymentVerificationLogAudit trail of admin confirm/reject/refund actions on an order
RefundRefund record linked to an order
WorkshopAllied workshop with capacity, SLA, payment policy, and geographic coverage
WorkshopUserLinks a TALLER user account to a Workshop
WorkshopOfferA workshop’s cost offer for a specific ProductVariant
WorkshopCoverageState/city coverage zones for a workshop
ProductionAssignmentAssignment of an OrderItem to a workshop; tracks AssignmentStatus
WorkshopPayableScheduled payment installment from platform to workshop
BusinessExpensePlatform operating expense records
SurfaceTemplateVersionVersioned mockup template configuration (manifest JSON)
MockupSceneRendering layers (base image, mask, shadow, highlight, displacement map) for a mockup scene
StateVenezuelan state for shipping zone lookup
CityCity within a State for shipping rate resolution
ServiceZoneNamed service zone used in shipping rate definitions
ShippingRateShipping cost and estimated days per DeliveryMethod, scoped to a city, state, or zone
FulfillmentRuleDefault 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; the fileUrl column in DesignUpload stores 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.
In local development both buckets fall back to 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:
  1. Catalog browse — The customer visits /catalog, which calls GET /api/catalog to fetch active Product records with their ProductVariant children. Each variant carries the basePrice and available WorkshopOffer data needed to display prices.
  2. Product detail — At /product/[id] the customer selects a variant and sees the commercial photo carousel from Product.images.
  3. Design editor — Navigating to /product/[id]/customize (or /editor) loads the Fabric.js canvas. The customer uploads their artwork via POST /api/upload; the file is stored in the designs bucket (or locally) and a DesignUpload record is created. The canvas generates a preview data URL (previewUrl) when the customer is satisfied.
  4. Cart and quote — Adding to cart triggers POST /api/quotes, which creates a Quote with frozen prices and the current USD/Bs exchange rate. Quotes have an expiry timestamp (expiresAt) to prevent stale pricing.
  5. Checkout — At /checkout the customer retrieves active PaymentAccount records via GET /api/payments/accounts and selects a bank transfer or Pago Móvil account. They enter the payment reference and upload a receipt image.
  6. Payment submissionPOST /api/payments creates a PaymentSubmission with status: REPORTED. The order’s own PaymentStatus advances to REPORTED. The receipt file is stored in the receipts bucket.
  7. Admin verification — An ADMIN user reviews the submission at /admin/payments. On confirmation, the PaymentSubmission status becomes CONFIRMED, the Order status advances to CONFIRMED, and a PaymentVerificationLog entry is written. On rejection, a rejectionReason is recorded and the customer is notified.
  8. Workshop assignment — With payment confirmed, the admin assigns each OrderItem to an appropriate workshop via a ProductionAssignment record. The system matches workshops by their WorkshopOffer for the relevant ProductVariant and their WorkshopCoverage for the delivery state.
  9. Production — The workshop operator sees the assignment in their dashboard at /workshop/dashboard. They advance the AssignmentStatus through ACCEPTEDIN_PRODUCTIONREADYHANDED_TO_DELIVERY.
  10. Delivery — Once the assignment reaches COMPLETED, the Order is closed. If a CreatorDesignListing was involved, a CreatorEarning record 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 (from src/lib/api-auth.js) that re-verifies the JWT from the krafta-token cookie 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.

Build docs developers (and LLMs) love