var c=Object.defineProperty;var s=(t)=>t;function l(t,o){this[t]=s.bind(null,o)}var d=(t,o)=>{for(var a in o)c(t,a,{get:o[a],enumerable:!0,configurable:!0,set:l.bind(o,a)})};var m=(t,o)=>()=>(t&&(o=t(t=0)),o);import{CodeBlock as i}from"@contractspec/lib.design-system";import r from"@contractspec/lib.ui-link";import{ChevronRight as p}from"lucide-react";import{jsx as e,jsxs as n}from"react/jsx-runtime";function h(){return n("div",{className:"space-y-8",children:[n("div",{className:"space-y-4",children:[e("h1",{className:"font-bold text-4xl",children:"Integration Binding"}),e("p",{className:"text-muted-foreground",children:"Integration binding connects your app's capabilities to external service providers. Each tenant can configure their own integration connections while sharing the same app blueprint."})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"How it works"}),e("p",{className:"text-muted-foreground",children:"Integration binding follows a three-layer model:"}),n("ol",{className:"list-inside list-decimal space-y-3 text-muted-foreground",children:[n("li",{children:[e("strong",{children:"IntegrationSpec"})," (global) - Defines what an integration provides"]}),n("li",{children:[e("strong",{children:"IntegrationConnection"})," (per-tenant) - A tenant's configured connection"]}),n("li",{children:[e("strong",{children:"AppIntegrationBinding"})," (per-app) - Maps named slots to concrete tenant connections"]})]})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Example: Payment processing"}),e("p",{className:"text-muted-foreground",children:"Let's walk through a complete example of binding Stripe for payments."}),n("div",{className:"space-y-3",children:[e("h3",{className:"font-semibold text-lg",children:"Step 1: Blueprint declares requirement"}),e(i,{language:"typescript",code:`// AppBlueprintSpec
{
  meta: { name: "invoice-app", version: '1.0.0', appId: "invoice" },
  integrationSlots: [
    {
      slotId: "payments.primary",
      requiredCategory: "payments",
      allowedModes: ["managed", "byok"],
      requiredCapabilities: [
        { key: "payments.createPaymentIntent", version: '1.0.0' },
        { key: "payments.createRefund", version: '1.0.0' }
      ],
      required: true,
      description: "Primary PSP used for Checkout and Subscription flows"
    }
  ],
  workflows: {
    checkout: { name: "invoice.checkout", version: '1.0.0' }
  },
  branding: {
    appNameKey: "invoice.appName",
    assets: [{ type: "logo", url: "https://cdn.acme.dev/logo.png" }],
    colorTokens: { primary: "colors.brand.primary" }
  }
}`})]}),n("div",{className:"space-y-3",children:[e("h3",{className:"font-semibold text-lg",children:"Step 2: Tenant creates connection"}),e(i,{language:"typescript",code:`// IntegrationConnection
{
  meta: {
    id: "conn_stripe_acme_prod",
    tenantId: "acme-corp",
    integrationKey: "payments.stripe",
    integrationVersion: 1,
    label: "Stripe Production",
    environment: "production",
    createdAt: "2025-01-15T09:00:00Z",
    updatedAt: "2025-01-15T10:30:00Z"
  },
  ownershipMode: "byok",
  externalAccountId: "acct_123",
  config: {
    accountId: "acct_123",
    webhookUrl: "https://acme.app/webhooks/stripe"
  },
  secretRef: "vault://integrations/acme/conn_stripe_acme_prod",
  status: "active"
}`})]}),n("div",{className:"space-y-3",children:[e("h3",{className:"font-semibold text-lg",children:"Step 3: TenantAppConfig binds connection"}),e(i,{language:"typescript",code:`// TenantAppConfig
{
  meta: {
    tenantId: "acme-corp",
    blueprintName: "invoice-app",
    blueprintVersion: 1,
    environment: "production",
    version: 4,
    status: "published"
  },
  integrations: [
    {
      slotId: "payments.primary",
      connectionId: "conn_stripe_acme_prod",
      scope: {
        workflows: ["checkout", "subscription-renewal", "refund-process"],
        operations: ["payments.stripe.*"]
      },
      priority: 1
    }
  ],
  branding: {
    appName: { en: "Acme Billing Portal" },
    customDomain: "billing.acme.com",
    assets: [{ type: "logo", url: "https://assets.acme.com/logo.svg" }]
  }
}`})]}),n("div",{className:"space-y-3",children:[e("h3",{className:"font-semibold text-lg",children:"Step 4: Runtime resolves and executes"}),e(i,{language:"typescript",code:`// ResolvedAppConfig (runtime)
{
  integrations: {
    "payments.createPaymentIntent": {
      provider: { /* IntegrationSpec for Stripe */ },
      connection: { /* IntegrationConnection */ },
      config: { /* Merged configuration */ }
    }
  }
}

// When workflow executes:
const result = await executeCapability(
  "payments.createPaymentIntent",
  { amount: 5000, currency: "usd" },
  resolvedConfig
);
// → Uses Stripe connection automatically`})]})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Multi-integration scenarios"}),e("p",{className:"text-muted-foreground",children:"A single app can use multiple integrations across different categories:"}),e(i,{language:"typescript",code:`integrations: [
  {
    slotId: "payments.primary",
    connectionId: "conn_stripe_prod",
    scope: {
      workflows: ["checkout", "subscription-*"]
    }
  },
  {
    slotId: "email.outbound",
    connectionId: "conn_postmark_prod"
  },
  {
    slotId: "email.inbound",
    connectionId: "conn_gmail_support",
    scope: {
      workflows: ["support-ticket-creation"]
    }
  },
  {
    slotId: "knowledge.vector-store",
    connectionId: "conn_qdrant_prod",
    scope: {
      workflows: ["semantic-search", "rag-query"]
    }
  }
]`})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Sandbox vs Production"}),e("p",{className:"text-muted-foreground",children:"Tenants typically maintain separate connections for sandbox and production environments:"}),e(i,{language:"typescript",code:`// Sandbox environment
{
  meta: { environment: "sandbox", status: "preview" },
  integrations: [
    {
      slotId: "payments.primary",
      connectionId: "conn_stripe_acme_test"
    }
  ]
}

// Production environment
{
  meta: { environment: "production", status: "published" },
  integrations: [
    {
      slotId: "payments.primary",
      connectionId: "conn_stripe_acme_prod"
    }
  ]
}`})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Security & validation"}),n("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[e("li",{children:"Integration connections are validated before binding - health checks ensure connectivity"}),e("li",{children:"Secrets are never stored in TenantAppConfig - only references to encrypted secrets"}),e("li",{children:"Policy Decision Point (PDP) enforces which workflows can use which integrations"}),e("li",{children:"All integration calls are audited with full request/response logging"}),e("li",{children:"Rate limiting and quotas are enforced per connection"})]})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Best practices"}),n("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[n("li",{children:["Use wildcard patterns sparingly in ",e("code",{children:"allowedWorkflows"})," - be explicit about access"]}),e("li",{children:"Always maintain separate sandbox and production connections"}),e("li",{children:"Monitor integration health checks and set up alerts for failures"}),e("li",{children:"Document the purpose of each integration binding for your team"}),e("li",{children:"Test integration changes in sandbox before promoting to production"})]})]}),n("div",{className:"flex items-center gap-4 pt-4",children:[e(r,{href:"/docs/architecture/app-config",className:"btn-ghost",children:"Previous: App Configuration"}),n(r,{href:"/docs/architecture/knowledge-binding",className:"btn-primary",children:["Knowledge Binding ",e(p,{size:16})]})]})]})}export{h as ArchitectureIntegrationBindingPage};
