Patterna Docs

What Patterna is

A recommendation service that proves what it earned and says why it showed each item.

Everyone 3 min read View as Markdown

Patterna is a multi-tenant recommendation service. It answers one question for you: what did the recommendations earn, and why was each item shown? Your app asks for a list for a placement. Patterna returns item ids, a reason per slot and a request id. Your backend shows the items and reports what the user saw, tapped or dismissed.

Three claims, each with a mechanism#

ClaimMechanism
Proof. You see what recommendations add over your current list.Every surface runs with a sticky holdout. The ledger reports the difference between the arms per impression with a 95% interval. Nothing else counts as proof.
A reason for every slot.The winning generator leaves a template key, but only when what it says is true; otherwise the slot says "Recommended". Your app shows the Dutch or English sentence. Nothing is recommended without a reason the user could read.
Works when the user says no.Three consent modes. In non_profiled mode Patterna stores no user id and still learns a global policy from context only.

How a request flows#

code
request(tenant, surface, mode, user_or_session, context)
  → consent mode gate (non_profiled: no user lookup)
  → generators (trending per surface, curated, item-to-item, session items, content affinity, persona and user models,
    surface-specific, time of day, format)
  → filters (status, locale, expiry and stock, premium policy, seen, dismissed, completed, bought,
    per-collection caps, freshness, the relevance floor)
  → ranker (linear; learned_linear or gbdt fitted nightly from taps)
  → exploration (Plackett-Luce sampling on a share of treatment and no-holdout requests, exact per-position
    propensities; caps and filters.diversity applied inside the sampler)
  → slate: items with reason keys; impression logged with arm, policy and propensities

Budgets: p99 60 ms from cache, 250 ms live, measured at the gateway. The engine's own budget is 120 ms by default; if Patterna cannot rank in time, it returns the surface's editorial list flagged fallback: true. Your backend falls back on top with its own list after a 150 ms timeout. Your app never depends on Patterna being up. See Timeouts and what counts in the ledger.

What runs where#

PartDoes
Engine (one Go binary)API gateway with scoped keys, rate limits and request ids; catalog; ingest; serve; proof (holdouts, ledger); admin (surfaces, flows, audit, deletion and export)
Jobs (Python)Learning and evaluation, LLM tagging and reason drafts, connectors (PostHog, GA4, Shopify, quiz CSV), the simulator, the monthly ledger. Jobs write models; serve never trains.
Postgres 17 + pgvectorEverything, with row-level security per tenant
PanelThis control panel: Proof, Surfaces, Flows, Audiences, Catalog, Connectors, Governance

Redis is optional: with REDIS_URL set, several engine instances share their cached aggregate answers; without it each instance caches on its own. Exports go to the engine's export directory; an S3 target is not built. See Status.

What stays with you#

  • Identity. You mint a random id per user. The mapping to your accounts stays on your side. Patterna never sees an email, a name or your identity provider's subject. See Identity across connectors.
  • Hydration. Patterna returns ids. Your backend loads the items and applies premium redaction, locale and status.
  • Sensitive context. Context that must not leave the device stays there. Do not send health measurements or anything you would not show in a reason. If a placement must react to such context, keep that logic in the app, or leave the placement out of recommendations altogether.

Security in one paragraph#

Every tenant table has row-level security, with a cross-tenant test in CI. API keys are scoped (serve keys start with pk_s_, ingest with pk_i_, admin with pk_a_) and stored hashed. Events are accepted only with an ingest or admin key, so from your backend; a signature, when present, is verified. The panel has MFA, roles and an audit log. Deletion and export reach the model artifacts through the retrain schedule. LLM calls go through EU endpoints with zero retention, pinned model versions and a daily cost ceiling per tenant. Details: Data we never store.

Sized for small data#

Patterna is built for catalogs of hundreds to a few thousand items and hundreds to thousands of daily users. Postgres holds everything. Extra stores (ClickHouse, Qdrant, a message bus) come only when a measured trigger fires, not by default.

esc
  • Type to search every page, heading and code sample.