Platform Reference11 min read

PrintLife Studio — 12-Domain System Coupling & Blast-Radius Map

> Why This Document Exists: PrintLife Studio is a tightly coupled, end-to-end shop management platform. Almost every feature reads from and writes to shared Firestore document s...

PrintLife Studio — 12-Domain System Coupling & Blast-Radius Map

Why This Document Exists: PrintLife Studio is a tightly coupled, end-to-end shop management platform. Almost every feature reads from and writes to shared Firestore document structures (Quote, Project, LineItem, Decoration, Customer, StoreOrder, PurchaseOrder, PriceMatrix) and triggers downstream workflows across pricing, mockups, automations, production scheduling, inventory, shipping, and accounting.

No agent may modify any file in src/ without first consulting this Coupling Map, reading the matching docs/*.md domain specification(s), and tracing all upstream/downstream callers.


1. End-to-End Cross-System Data Flow

flowchart TD
    D1["1. Suppliers & Product Catalog\n(PSRestful, SanMar, S&S, Custom)"] --> D2["2. Pricing & Markup Matrices\n(Screen Print, Embroidery, DTF, Garment Markup)"]
    D1 --> D3["3. Art Library & Mockup Generator\n(Color Separations, Vector Renderer, Multi-Proofs)"]
    D4["4. Customers, Contacts & Locations\n(Tax Exemption, Credit Terms, Addresses)"] --> D5["5. Central Quote & Invoice Engine\n(Projects, LineItems, Decorations, Fees, Totals)"]
    D2 --> D5
    D3 --> D5
    D5 <-->|"Dual-Write Mirror\n(.set with merge:true)"| D6["6. Public Quote (/q/[id]), Portal & Design Lab\n(Mockup/Roster Approval, Self-Serve Changes)"]
    D7["7. Online Stores, Value Offers & Gang Sheets\n(/s/[slug], Fundraising, DTF Builder)"] --> D8["8. Payments, Surcharges, Refunds & QuickBooks\n(Stripe, Square, Cash/Check, Credit Terms, QBO)"]
    D5 --> D8
    D6 --> D8
    D6 --> D9["9. Automation Engine & Two-Way Inbox\n(Triggers, Shortcodes, Gmail/Outlook/SMTP)"]
    D8 --> D9
    D5 --> D9
    D8 --> D10["10. Production Dashboard, Kanban & Auto-Scheduler\n(Capacity Minutes, Dept Queues, Rush Dates)"]
    D9 --> D10
    D5 --> D11["11. Inventory, Ready-to-Order, POs & Receiving\n(Stock Allocation, Vendor POs, Supacolor)"]
    D7 --> D11
    D5 --> D12["12. Work Orders, Contractor Portal, Printables & Shipping\n(Job Cards, Packing Slips, EasyPost/ShipStation)"]
    D10 --> D12

2. Shared Firestore Document Contracts & Dual-Write Invariants

2.1 Primary Quote Document (tenants/{tenantId}/quotes/{quoteId}) & Public Mirror (publicQuotes/{quoteId})

  • Dual-Write Mirror Rule:
    • tenants/{tenantId}/quotes/{quoteId} is the canonical shop document.
    • publicQuotes/{quoteId} is the top-level lookup/mirror document used by /q/[quoteId], public payment routes, and public actions (findQuoteTenantId).
    • CRITICAL INVARIANT: Whenever any API route or server helper mutates publicQuotes/{quoteId}, it MUST use transaction.set(publicQuoteRef, { ...payload, tenantId }, { merge: true }) or batch.set(publicQuoteRef, { ...payload, tenantId }, { merge: true }) — NEVER raw .update(publicQuoteRef, ...). Legacy quotes, imported quotes, or quotes created before public mirror initialization may not have an existing publicQuotes/{quoteId} document, causing raw .update() to throw 5 NOT_FOUND: No document to update and roll back the entire transaction (breaking cash payments, card payments, refunds, status changes, and manual actions).
  • Firestore null vs. undefined Rule:
    • The Firebase Admin SDK throws a fatal runtime error if undefined appears anywhere inside .update(), .set(), or FieldValue.arrayUnion(...) (including optional fields like details: payment.notes || '' in activityLog entries or mockup / mockups fields on decorations). Always use null or '', never undefined.

2.2 Quote -> projects[] -> lineItems[] & decorations[] Schema Contract

Every Project inside quote.projects[] contains two tightly coupled arrays that 10 different domains read and mutate:

  1. lineItems[]:
    • Key fields: id, productId, productName, brandName, styleNumber, color, sizes (map of sizeName -> quantity), unitCosts (map of sizeName -> wholesaleCost), priceOverrides (map of sizeName -> manualRetailOverride), taxable, personalizations[] (custom names & numbers roster), fulfillmentStatus / poId (inventory & PO tracking).
    • Who reads/writes lineItems[]:
      • Pricing Engine (src/lib/utils/quote-pricing-calculations.ts)
      • Customer Public Quote & Roster Approval (src/lib/data/public-actions.ts, src/app/q/[id]/page.tsx)
      • Inventory & Ready-to-Order Aggregation (src/lib/data/inventory.ts, src/lib/data/purchase-orders.ts)
      • Shipping Rate & Weight Calculation (src/lib/server/shipping/shipping-service.ts)
      • QuickBooks Invoice Line Sync (src/lib/server/quickbooks-sync.ts)
      • Printables: Job Cards, Work Orders, Packing Slips (src/app/(app)/quotes-invoices/[id]/job-card/, work-order/, packing-slip/)
  2. decorations[]:
    • Key fields: id, type / method (Screen Printing, Embroidery, DTF, etc.), location (Front, Back, Left Chest, etc.), colors / stitchCount / dimensions, matrixId, artwork (linked Art Library item), mockup (legacy single { id, url, path } | null), mockups[] (multi-proof array of { id, url, path, label, isApproved, approvedAt, approvedBy, isRejected, rejectionReason, rejectedAt }), isApproved, approvedAt, approvedBy, isRejected, rejectionReason, rejectedAt.
    • CRITICAL INVARIANT:
      • Always read proofs via getDecorationMockups(decoration) from src/lib/utils/mockup.ts so both legacy d.mockup and modern d.mockups[] shapes work identically.
      • Always evaluate quote-wide proof & roster sign-off via checkAllMockupsApproved(projects, quoteData) from src/lib/utils/mockup.ts.
      • When updating d.mockups[], only write updatedDecoration.mockups when Array.isArray(d.mockups) is true (or initialize it explicitly as an array), and sync updatedDecoration.mockup to first ? { id: first.id, url: first.url, path: first.path } : null.

3. The 12 Core Domains — Specifications, Key Files & Blast-Radius Coupling

Domain 1: Suppliers, Product Catalog & Custom Products

  • Authoritative Docs:
  • Key Files:
    • src/services/psrestful.ts, src/services/psrestful-Inventory.ts
    • src/app/api/psrestful/**
    • src/lib/data/products.ts, src/lib/data/suppliers.ts
  • Coupled Downstream Domains (Blast Radius):
    • Domain 2 (Pricing): Supplier wholesale tier costs (unitCosts per size) feed garment markup matrices.
    • Domain 3 (Mockup Generator): Supplier product colorways and high-res blank images feed the mockup canvas and image proxy (/api/image-proxy).
    • Domain 6 & 7 (Design Lab & Online Stores): Storefront products and Design Lab blank selectors depend on normalized style/color/size structures.
    • Domain 11 (Inventory & POs): Ready-to-Order and Purchase Orders group items by supplier, style number, color, and size.

Domain 2: Pricing & Markup Matrices

  • Authoritative Docs:
  • Key Files:
  • Coupled Downstream Domains (Blast Radius):
    • Domain 5 (Quote/Invoice Builder): computeProjectsWithCalculations() and computeQuoteGrandTotal() compute every line item's unit price, size upcharges, fleece upcharges, decoration run charges, setup fees, personalization fees, discounts, and sales tax.
    • Domain 6 (Public Quote & Design Lab): Self-serve quantity edits (updatePublicQuoteQuantities) and Design Lab estimates run the exact same computeProjectsWithCalculations() and computeQuoteGrandTotal() functions on the server.
    • Domain 8 (Payments & QuickBooks): quote.subtotal, quote.taxAmount, quote.shippingCost, and quote.total drive computeBalanceDue() and QuickBooks invoice line sync.

Domain 3: Art Library, Vector Renderer & Mockup Generator

  • Authoritative Docs:
  • Key Files:
    • src/lib/utils/mockup.ts (getDecorationMockups, checkAllMockupsApproved, isDecorationApproved, getDecorationRejectedMockups)
    • src/lib/data/art-library.ts
    • src/app/api/image-proxy/route.ts (uses fetchWithSsrfGuard)
  • Coupled Downstream Domains (Blast Radius):
    • Domain 5 & 6 (Quote Builder & Public Quote /q/[id]): Mockup proofs saved on project.decorations[] render on /q/[id] for customer approval/rejection.
    • Domain 8 (Payments): When a customer pays (or staff records a payment), checkAllMockupsApproved() determines whether the all_mockups_approved_paid automation fires or first_payment fires.
    • Domain 9 (Automations): Sending mockups fires mockups_sent; approving all mockups fires all_mockups_approved or all_mockups_approved_paid (with { fallbackTrigger: 'all_mockups_approved' }); rejecting fires mockup_change_request.
    • Domain 12 (Job Cards, Work Orders & Contractor Portal): Print dimensions, Pantone/ink colors, stitch counts, and proof thumbnails render directly on shop floor Job Cards and Vendor Work Orders.

Domain 4: Customers, Contacts, Locations & Tax Exemptions

  • Authoritative Docs:
  • Key Files:
    • src/lib/data/customers.ts
    • src/app/api/tenants/[tenantId]/customers/**
    • src/lib/data/public-actions.ts (addPublicQuoteCustomerLocation, updatePublicQuoteCustomerAddress, updatePublicQuoteContact)
  • Coupled Downstream Domains (Blast Radius):
    • Domain 5 & 6 (Quotes & Public Quote): Updating a customer's contacts, billing/shipping locations, isTaxExempt status, or creditTermsDays syncs into embedded quote.customer and quote.contact snapshots across open quotes (tenants/{tenantId}/quotes and publicQuotes).
    • Domain 8 (Payments & AR): customer.creditTermsDays unlocks the "Credit Terms / Net Terms" payment option on /q/[id] and calculates invoice dueDate; isTaxExempt zeroes out sales tax in computeQuoteGrandTotal().
    • Domain 9 (Emails): quote.contact.email (or quote.customer.contacts[0].email) is the recipient for automated quote/invoice emails and payment receipts.

Domain 5: Central Quote & Invoice Document Engine

  • Authoritative Docs:
  • Key Files:
    • src/lib/data/quotes.ts
    • src/app/api/tenants/[tenantId]/quotes/route.ts
    • src/app/api/tenants/[tenantId]/quotes/[id]/route.ts
    • src/app/(app)/quotes-invoices/**
  • Coupled Downstream Domains (Blast Radius):
    • Every single domain in PrintLife Studio reads or mutates tenants/{tenantId}/quotes/{quoteId}.
    • Any mutation to a quote MUST keep publicQuotes/{quoteId} in sync via .set(publicQuoteRef, { ...data, tenantId }, { merge: true }).
    • Converting documentType to 'Invoice' with a dueDate automatically triggers autoScheduleTenantInvoices(tenantId) (Domain 10).
    • Moving statusId cancels pending scheduled automations configured to cancel on status change, triggers /api/tenants/[tenantId]/quotes/[id]/status-log-email, and (when statusId === 'system_complete') triggers order_completed automations.

Domain 6: Public Quote (/q/[id]), Customer Portal & Design Lab

  • Authoritative Docs:
  • Key Files:
    • src/app/q/[id]/page.tsx
    • src/lib/data/public-actions.ts (getPublicQuoteData, approveMockup, rejectMockup, approveRoster, rejectRoster, updatePublicQuoteQuantities, selectTurnaroundOption, acceptPaymentTerms, selectPayLater)
    • src/lib/utils/tenant-subdomain.ts, src/proxy.ts
  • Coupled Downstream Domains (Blast Radius):
    • Domain 2 & 5 (Pricing & Quotes): Customer quantity edits and turnaround option selections recalculate quote totals on the server via @/lib/utils/quote-pricing-calculations and update both tenants/{tenantId}/quotes/{quoteId} and publicQuotes/{quoteId}.
    • Domain 8 (Payments): Public Stripe, Square, Credit Terms (acceptPaymentTerms), and Pay Later (selectPayLater) convert quotes to invoices, record payments, and trigger automations.
    • Domain 9 (Automations): Public mockup/roster approvals (approveMockup, approveRoster) evaluate alreadyPaid = (quoteData.paidAmount || 0) > 0 || quoteData.isTermsPayment === true and call executePublicAutomation with 'all_mockups_approved_paid' and { fallbackTrigger: 'all_mockups_approved' }.

Domain 7: Online Stores, Value Offers & Gang Sheet Builder

  • Authoritative Docs:
  • Key Files:
    • src/app/s/[slug]/**, src/lib/data/stores.ts
    • src/lib/data/public-actions.ts (getPublicStoreData, processStoreCheckout)
    • src/app/api/gang-sheet/**, src/lib/data/gang-sheets.ts
    • src/lib/data/value-offers.ts
  • Coupled Downstream Domains (Blast Radius):
    • Domain 8 (Payments & Refunds): Storefront checkout (/s/[slug]), Gang Sheet checkout, and Value Offer checkout process live Stripe/Square payments and support processor-first refunds (/api/tenants/[tenantId]/stores/[storeId]/orders/[orderId]/refund).
    • Domain 11 (Inventory & POs): Store orders aggregate garment demand into Ready-to-Order / Purchase Orders.
    • Domain 12 (Shipping): Storefront and Gang Sheet checkouts calculate live carrier rates via /api/public/shipping/store-rates and /api/public/shipping/gang-sheet-rates.

Domain 8: Payments, Surcharges, Credit Terms, Refunds, Financials & QuickBooks


Domain 9: Automation Engine & Two-Way Communication Hub

  • Authoritative Docs:
  • Key Files:
    • src/lib/server/automation-scheduler.ts (executeOrScheduleAutomationActions, cancelPendingScheduledAutomations)
    • src/lib/server/quote-email-dispatch.ts (dispatchQuoteEmail)
    • src/lib/server/email-utils.ts (sendTenantEmail, replaceEmailShortcodes)
    • src/lib/server/inbox-providers.ts (sanitizeEmailHtml, invalidateInboxCaches)
    • src/app/api/tenants/[tenantId]/quotes/[id]/manual-action/route.ts
  • Coupled Downstream Domains (Blast Radius):
    • Domain 5 & 10 (Quote Status & Kanban): Automation move actions transition quote.statusId on the Kanban board (unless quote.statusId === 'system_complete').
    • Domain 6 (White-Label URLs): Email shortcodes ({{quoteLink}}, {{portalLink}}) resolve tenant custom subdomain URLs via getTenantQuoteUrl and getTenantPortalLoginUrl.

Domain 10: Production Dashboard, Kanban & Capacity Auto-Scheduler


Domain 11: Inventory, Ready-to-Order, Purchase Orders & Receiving

  • Authoritative Docs:
  • Key Files:
    • src/lib/data/inventory.ts, src/lib/data/purchase-orders.ts
    • src/app/api/tenants/[tenantId]/purchase-orders/**
    • src/lib/server/supacolor/client.ts
  • Coupled Downstream Domains (Blast Radius):
    • Domain 5 & 7 (Invoices & Store Orders): Ready-to-Order aggregates unfulfilled lineItems[] across active invoices and store orders. Creating or receiving a PO updates item fulfillment status and stock levels across linked orders.

Domain 12: Work Orders, Contractor Portal, Printables & Shipping

  • Authoritative Docs:
  • Key Files:
    • src/lib/server/shipping/shipping-service.ts (getActiveShippingProvider, EasyPost -> ShipStation)
    • src/app/api/shipping/**, src/app/api/public/shipping/**
    • src/lib/data/work-orders.ts, src/app/portal/vendor/**
    • src/app/(app)/quotes-invoices/[id]/job-card/**, work-order/**, packing-slip/**
  • Coupled Downstream Domains (Blast Radius):
    • Domain 5 & 9 (Quotes & Emails): Purchasing a shipping label (POST /api/shipping/create-label) writes tracking numbers and label URLs onto the quote/order and populates {{trackingNumber}}, {{trackingLink}}, and {{carrier}} shortcodes for shipping confirmation emails.

4. Complete Documentation Index (docs/*.md)

DomainSpecification Documents in docs/
Master Overview & Navigationproduct-feature-bible.md, UI_NAVIGATION_MAP.md, API_INTERACTIONS.md
Security & CASA ControlsCASA_AUDIT_CONTROLS.md, SECURITY_RULES.md, SECRETS_ACCESS_CONTROL.md, ENCRYPTION_KEY_MANAGEMENT.md, SESSION_LOGOUT_SECURITY.md, FILE_UPLOAD_SECURITY.md
1. Suppliers & ProductsSUPPLIERS_AND_CATALOG.md, PRODUCTS.md
2. Pricing & MatricesMATRICES.md, LINE_ITEMS.md
3. Art & MockupsART_LIBRARY_AND_COLOR_SEPARATIONS.md, MOCKUP_GENERATOR.md, VECTOR_RENDERER.md
4. Customers & PortalCUSTOMERS_AND_PORTAL.md, WHITE_LABEL_SUBDOMAINS.md
5. Quotes & InvoicesQUOTES_INVOICE.md, LINE_ITEMS.md, TURNAROUND_TIMES.md
6. Public Quote & Design LabCUSTOMERS_AND_PORTAL.md, DESIGN_LAB_AND_WIDGET.md, WHITE_LABEL_SUBDOMAINS.md
7. Stores, Offers & Gang SheetsONLINE_STORES.md, VALUE_OFFERS.md, GANG_SHEETS.md
8. Payments, AR & QuickBooksFINANCIALS_AND_REPORTING.md, ACCOUNTS_RECEIVABLE.md, QUICKBOOKS_INTEGRATION.md, NANGO_CONNECTIONS.md
9. Automations & Email/InboxAUTOMATIONS.md, EMAIL_INTEGRATION.md, COMMUNICATION_HUB.md
10. Dashboard & Auto-SchedulerDASHBOARD.md, auto-scheduling-capacity.md, PRODUCTION_CAPACITY_AND_DECORATION_DEPARTMENTS.md
11. Inventory & Purchase OrdersINVENTORY_AND_PURCHASE_ORDERS.md, SUPACOLOR_INTEGRATION.md, MATERIALS.md
12. Work Orders, Printables & ShippingVENDOR_CONTRACTOR_PORTAL.md, PRINTABLES.md, JOBCARD.md, EASYPOST_INTEGRATION.md, SHIPPING_RATES.md
Platform Ops & BillingSUBSCRIPTION_AND_BILLING.md, TEAM_AND_ROLES.md, SUPERADMIN.md, SUPPORT_TICKETS.md, ACHIEVEMENTS_AND_ONBOARDING.md
Interactive Setup Support

Have a question about this feature?

Log into your Print Life dashboard anytime and click the Shop Co-Pilot button. You can ask anything from margin math to work center capacity, and the AI wizard will guide you through step-by-step.

    PrintLife Studio — 12-Domain System Coupling & Blast-Radius Map | Print Life Software Documentation