Connector — diagram coverage (registry side vs caller side)

Updated · View the entry on sijie.xyz ↗

The connector module is two designs sharing one package: the registry side (how a connector gets installed, credentialed, activated) and the caller side (how a consumer invokes a category verb without ever seeing a provider or a credential). One diagram would blur exactly the boundary the module exists to enforce — so, two.

1 · Registry side — install, credential, activate

classDiagram
  class connectorService {
    <<connector.Service - the admin-facing side, service.go + svc_*.go>>
    Repo.SaveUploaded / Service.UpdateUploaded - plugin upload
    connect / oauth / activate / disconnect
    credential seal-unseal via cryptobox
  }
  class Hub {
    -conns map[string]Connector
    -mu sync.RWMutex
    +Register(c Connector)
    +Upsert(c Connector)
    +Resolve(name) (Connector, bool)
  }
  class Connector {
    <<interface>>
    +Name() string
    +Kind() string
    +Connected(ctx, ownerID) (bool, error)
  }
  class Verifier {
    <<interface - optional>>
    +Verify(ctx, ownerID) error
  }
  class cryptobox {
    AES-GCM seal and open
    creds ciphertext at rest
  }
  class owner_connectors {
    <<postgres>>
    per-owner connection rows
    credential ciphertext lives here
  }
  connectorService --> Hub : Register / Upsert on activate
  Hub o-- Connector : by name
  Connector <|-- Verifier : optionally also
  connectorService ..> cryptobox : seal creds
  cryptobox ..> owner_connectors : ciphertext

The registry side is the ONLY place credentials are plaintext, and only transiently. Everything downstream of Hub.Resolve sees a Connector — name, kind, connected; nothing else.

2 · Caller side — category verbs, no provider, no creds

classDiagram
  class Consumer {
    agent tool / platform feature
    future IM-gateway, job-loop
  }
  class CalendarProxy {
    <<interface - connector/contract>>
    +Connected(ctx, ownerID) (bool, error)
    +FreeBusy(ctx, ownerID, FreeBusyReq) ([]BusyInterval, error)
    +InsertEvent(ctx, ownerID, *InsertEventReq) (InsertedEvent, error)
    +DeleteEvent(ctx, ownerID, eventID, attendeeEmail) error
  }
  class MailProxy {
    <<interface - connector/contract>>
    +Connected(ctx, ownerID) (bool, error)
    +Send(ctx, ownerID, MailMessage) (MailReceipt, error)
  }
  class DepRegistry {
    +AllConnected(ctx, ownerID, names) (bool, error)
    gate BEFORE exposure - fail-closed
  }
  class openapiRuntime {
    -spec *Spec
    -binding *Binding - JSONata
    -doer Doer
    -baseURL string
    +Call(ctx, op, input, dst, AuthInjector) error
  }
  class AuthInjector {
    <<func type>>
    func(req *http.Request) error
    built inside the connector pkg per call
  }
  class protocolImpl {
    built-in Go clients - SMTP, CalDAV
    telegram - token vault only, no contract
  }
  class StatusError {
    Code int
    Transient bool - retry per call-class
  }
  Consumer ..> DepRegistry : exposure gated first
  Consumer --> CalendarProxy : category verbs only
  Consumer --> MailProxy : category verbs only
  CalendarProxy <|.. openapiRuntime
  CalendarProxy <|.. protocolImpl
  MailProxy <|.. openapiRuntime
  MailProxy <|.. protocolImpl
  openapiRuntime ..> AuthInjector : injected per request
  openapiRuntime --> StatusError : transient vs fatal

The caller's world contains no provider names and no credentials — the proxy interfaces are the whole vocabulary. AuthInjector is constructed inside the package at call time; the consumer cannot even name it.

Coverage checklist (anti-omission gate)

type / area diagrammed at verified
Hub, Connector, Verifier this page §1 ✓ code
connector.Service responsibilities (was connectorsvc until 2026-07-26, 1bc9ba8b0) this page §1 ✓ names, ☐ full signatures
cryptobox / owner_connectors this page §1 ✓ mechanism, ☐ column list
CalendarProxy / MailProxy + DTOs this page §2, connector-plugins ✓ code
openapi Runtime / AuthInjector / StatusError this page §2 ✓ code
DepProvider / DepRegistry / RequiresDeps connector-deps ✓ code
ingest (spec parse, binding validate) ☐ not yet diagrammed —
egress guard types connector-egress-guard (prose) ☐ no class diagram

Related notes