toolzer Internal Docs
Platform

How `core` fits together

The whole system in one page. Anything service-specific lives in that service's own docs folder — see the index.

The shape of it

                    ┌─────────────────────────────────────────┐
  customers ──────► │ api  (Hono, TypeScript, :2626)          │
  x-api-key         │   /v1 /v2      metered data APIs        │
                    │   /auth /hub   Toolzer Hub dashboard    │
  browsers ───────► │   /app         Vantage dashboard        │
  session cookie    │   /admin       staff, cross-tenant      │
                    │   /internal    unauthenticated tooling  │
                    └───┬──────────────┬──────────────┬───────┘
                        │              │              │
                  ┌─────▼─────┐  ┌─────▼─────┐  ┌─────▼──────────┐
                  │ worker    │  │ Postgres  │  │ ClickHouse     │
                  │ FastAPI   │  │ core_data │  │ core_analytics │
                  │ Python    │  │ identity  │  │ request + event│
                  │ + Redis   │  │ billing   │  │ analytics      │
                  └─────┬─────┘  └───────────┘  └────────────────┘
                        │
                   the public web

Web surfaces are separate Cloudflare Workers and talk to the API over HTTPS like any other client. They are not part of the same deployment.

The two halves of the request path

The API owns the contract. It authenticates, meters, validates, calls out, normalizes the answer, and shapes the response. It never returns an upstream body or an upstream status.

The worker owns the fetch. It is the only thing that touches the public web: proxy rotation, browser-grade TLS via curl_cffi, session minting and reuse, and the per-site quirks that make a request succeed. It speaks a raw internal contract, not the public one, and is not exposed to the internet.

The split exists because those two jobs fail differently. A site changing its anti-bot posture is a worker problem and changes weekly. A response shape a customer depends on is an API problem and must not change at all.

Not every route goes through the worker. Some sites are served from paid third-party providers, and /v2 is entirely external-sourced. The customer cannot tell, which is the point.

Where state lives

StoreDatabaseHolds
Postgrescore_data, schema platformusers, workspaces, sessions, API keys, subscriptions, credit balances and ledger
Postgrescore_data, schema rankingsVantage's rank-tracking data
ClickHousecore_analyticsone row per API request, plus the Apify event pipeline
Redis—worker fetch sessions, ~20 minute TTL

Postgres is the system of record. ClickHouse is analytical only — losing it loses reporting, not accounts or money. Redis is a cache; it starts cold without consequence.

The API applies its own Postgres migrations at boot under an advisory lock, so a deploy migrates and a bad migration fails the boot rather than serving on a half-built schema.

Identity and money

One identity layer serves both products. A workspace is the tenant; a subscription is (workspace, capability), where capability is api (Toolzer Hub), rankings (Vantage), or influencers. One credit wallet per workspace is shared across every capability it holds.

/v1 and /v2 authenticate with a per-workspace API key and spend credits. /hub and /app authenticate with a session and spend nothing. That is the whole distinction between the machine surface and the human one.

Details, including the credit reservation lifecycle and what is and is not charged, are in apps/api/docs/auth-and-credits.md.

Shared code

packages/ is the TypeScript code the API and any future Node service share: errors (the error class hierarchy the response contract is built on), fetch (the HTTP client, including the worker client), and logger. It is published to npm as @thenetaji/packages; see operations.md.

The API↔worker route contract is checked in CI (pnpm contracts:check), so a route renamed on one side fails the build rather than 404ing in production.

What ships where

Five deployables. The API and worker are Docker images on a Swarm; the three web apps are Cloudflare Workers. deployment.md has the table and the mechanics.

On this page