Skip to content

Architecture Overview

PaperRun is a postcard marketing automation platform for e-commerce. Merchants create campaigns targeting customer segments, and the platform handles the full lifecycle: recipient syncing, address enrichment, image personalization, printing, mailing, delivery tracking, and order attribution.

Click any stage to jump to its detailed documentation.

System Flow

%%{init: {
  'theme': 'base',
  'themeVariables': {
    'primaryColor': '#f0edff',
    'primaryBorderColor': '#262667',
    'primaryTextColor': '#262667',
    'lineColor': '#262667',
    'fontSize': '14px',
    'fontFamily': 'Inter, sans-serif'
  },
  'flowchart': {
    'nodeSpacing': 60,
    'rankSpacing': 70,
    'subGraphTitleMargin': { 'top': 12, 'bottom': 12 },
    'padding': 24,
    'htmlLabels': true,
    'curve': 'basis'
  }
}}%%

graph TD
    Campaign["🎯 <b>Campaign</b><br/><i>status: active</i>"]
    Klaviyo["<b>Klaviyo</b><br/><span class='ext-label'>segments · profiles</span>"]
    Faraday["<b>Faraday</b><br/><span class='ext-label'>geocoding · append</span>"]
    Shopify["<b>Shopify</b><br/><span class='ext-label'>orders</span>"]
    PersonalizationLayer["<b>Personalization Layer</b><br/><span class='ext-label'>image rendering</span>"]
    PrinterGroup["<b>LOB · IntelliPrint · Stannp</b><br/><span class='ext-label'>postcard printers</span>"]

    subgraph sync["&nbsp;&nbsp;1 · Recipient Sync&nbsp;&nbsp;"]
        direction TB
        Automator["⏱️ <b>Automator</b><br/>every 15 min"]
        SyncDesc["Fetches active campaigns<br/>Looks up Klaviyo segment<br/>Creates new recipients"]
        Automator ~~~ SyncDesc
    end

    Pending[("Recipients<br/><b>Pending</b>")]

    enrich["1a · <b>Address Enrichment</b><br/><i>4× daily via Faraday</i>"]

    subgraph proof["&nbsp;&nbsp;2 · Proofing&nbsp;&nbsp;"]
        direction TB
        Proofer["⏱️ <b>Proofer</b><br/>every 7–15s"]
        ProofDesc["Generate front & back images<br/>Personalize with recipient data<br/>Upload to Cloudflare"]
        Proofer ~~~ ProofDesc
    end

    Proofed[("Recipients<br/><b>Proofed</b>")]

    subgraph mail["&nbsp;&nbsp;3 · Mailing&nbsp;&nbsp;"]
        direction TB
        Mailer["⏱️ <b>Mailer</b><br/>every 7–15s"]
        MailDesc["Select print strategy<br/>Route to printer<br/>Create postcards"]
        Mailer ~~~ MailDesc
    end

    Sent[("Recipients<br/><b>Sent</b>")]

    subgraph orders["&nbsp;&nbsp;4 · Order Sync & Attribution&nbsp;&nbsp;"]
        direction TB
        SyncOrders["⏱️ <b>Sync Orders</b><br/>every 5 min"]
        OrderDesc["Sync from Klaviyo & Shopify<br/>Match orders to sent recipients<br/>by email, address, or discount"]
        SyncOrders ~~~ OrderDesc
    end

    Attribution[("Attributed<br/><b>Orders</b>")]

    Campaign --> sync
    Klaviyo -.-> sync
    sync --> Pending
    Pending --> proof
    Pending -.- enrich
    Faraday -.-> enrich
    enrich -.- Pending
    PersonalizationLayer -.-> proof
    proof --> Proofed
    Proofed --> mail
    PrinterGroup -.-> mail
    mail --> Sent
    Sent --> orders
    Klaviyo -.-> orders
    Shopify -.-> orders
    orders --> Attribution

    click sync href "../recipient-pipeline/" "Recipient Pipeline details"
    click enrich href "../../data_flow/address_enrichment/" "Address Enrichment details"
    click proof href "../../proofing_and_mailing/" "Proofing & Mailing details"
    click mail href "../../proofing_and_mailing/" "Proofing & Mailing details"
    click orders href "../../data_flow/order_syncing/" "Order Syncing details"
    click Attribution href "../../attribution_methodology/" "Attribution Methodology"
    click Pending href "../../models/campaign_recipients/" "Campaign Recipients model"
    click Proofed href "../../models/campaign_recipients/" "Campaign Recipients model"
    click Sent href "../../models/campaign_recipients/" "Campaign Recipients model"
    click Campaign href "../../models/campaign/" "Campaign model"

    classDef stage fill:#f7f5ff,stroke:#262667,stroke-width:2px,rx:12,ry:12;
    classDef state fill:#e8e6f0,stroke:#262667,color:#262667,stroke-width:2px;
    classDef external fill:#e8f4ff,stroke:#4a90d9,stroke-width:1.5px,color:#262667,rx:8,ry:8;
    classDef trigger fill:#fff,stroke:#262667,stroke-width:1px,rx:6,ry:6;
    classDef desc fill:#f8f8fc,stroke:#ccc,stroke-width:1px,rx:6,ry:6,color:#555;

    class sync,proof,mail,orders stage;
    class Pending,Proofed,Sent,Attribution state;
    class Klaviyo,Shopify,Faraday,PersonalizationLayer,PrinterGroup,Campaign external;
    class Automator,Proofer,Mailer,SyncOrders trigger;
    class SyncDesc,ProofDesc,MailDesc,OrderDesc desc;
    class enrich desc;

    style Pending color:#fff
    style Proofed color:#fff
    style Sent color:#fff
    style Attribution color:#fff