smallbox

The connections, not the parts

The Smallbox Foundation Map

The boxes on this map are the easy part — any developer can build them. What a parts list never shows is the connective tissue between them: which connections are allowed, which are deliberately forbidden, and why every responsibility has exactly one home. That is what this map documents, drawn from the production systems behind CompanyGraph and the site you are reading.

The shape

Websitethe product surface
Adminthe operator surface
Your product’s backendthe composition seam — the one place meaning is assembled
Identityaccounts · roles · tokens
Emailqueue · templates · history
Imagesbytes · metadata · picker
Translationlanguage infrastructure
Your domain enginewhat makes it yours — same boundary, separate work
Loggingevery box on this map reports here — frontends included

The diagram refuses to draw twelve arrows into the logging box; the sentence inside it is the honest version. Position carries the rest: surfaces on top, one seam in the middle, reusable modules below it, your engine beside them.

Admin Logs page filtered to startup heartbeats, one row per service: twelve running services across two products — backends, modules, and frontends — each tagged with its own colour.
The same map, as the logging module sees it: the admin Logs page filtered to startup heartbeats, one row per service. Twelve services across two products — backends, modules, and both products’ frontends — report into one surface. This screenshot is the “everything → logging” edge, photographed.

The un-abstracted version of this map is public too: every real service behind both products, every real line, clickable — the live architecture map.

The edges — every arrow, and why it exists

Website Backend

The public site depends on one contract, not on the layout of five modules. The backend can re-wire its internals without the site noticing.

Admin Backend

Operators work the same API the product runs on — not a side door with its own rules.

In the production system this map is drawn from, the admin's TypeScript types are generated from the backend's OpenAPI spec — contract drift fails the build, not the operator.

Backend Identity

Accounts, sessions, roles, and tokens are the same problem in every product. The product keeps only a user id and asks for the rest — a product that owns its identity tables rebuilds them in the next product.

Backend Email

Product code decides when an email should exist; the email module owns how — templates, queue, retries, history. A send that goes through the queue can be seen, retried, and audited.

Backend Images

Media is a generic capability: upload, metadata, a library, a picker. Products reference an image by id and never hold bytes.

Backend Translation

Language infrastructure — providers, keys, caching — should not leak into product code. The product asks for a translation, not for a vendor.

Everything Logging

Failure visibility must survive module boundaries. Every module, the backend, and both frontends report here, so “why did this break” is one query, not one log search.

The startup heartbeats of all twelve running services — both products, frontends included — land on one admin page.

Backend Your domain engine

The deliberate slot: scoring, matching, interpretation — whatever makes the product yours. Separate scoped work, but it has a named place from day one, behind the same kind of boundary as every module.

The forbidden edges — what never happens here

Restraint is most of architecture. The arrows above say what the system does; the list below says what it refuses to do — and the refusals are why the arrows stay simple.

A frontend never calls a module directly.

The moment the UI knows a module's address, the module stops being replaceable — and authorization gets enforced in two places.

Modules never call each other. (Only infrastructure reporting to logging.)

Composition belongs in exactly one place. Module-to-module knowledge quietly rebuilds the tangle the boundaries exist to prevent.

No foreign key crosses a module boundary — references are by id only.

Each module's schema must evolve on its own clock. A cross-module foreign key welds two release cycles together.

Business rules never live in controllers.

Transport and meaning change at different speeds. A rule in a controller is invisible to every other caller.

Your product's nouns never enter a module.

A module that knows your product cannot be reused in the next one — and, in the other direction, your domain stays yours.

Email is never sent inline from a request.

An inline send has no queue, no retry, and no history. It works until the day nobody can say whether it worked.

The module catalogue

ModuleOwnsStatusRunning behind
Structured backend coreLayers, typed contracts, domain modelFoundation coreCompanyGraph · Smallbox Labs
IdentityAccounts, sessions, roles, tokensRunning in productionBoth products
EmailTemplates, queue, retries, historyRunning in productionBoth products
LoggingFailures as records, heartbeatsRunning in productionBoth products + every frontend
ImagesBytes, metadata, library, pickerRunning in productionBoth products
TranslationLanguage infrastructureRunning in productionCompanyGraph
Admin patternOperator surfaces on the same domain modelRunning in both; shared kit extraction plannedBoth products
BillingSubscriptions, webhooks, gated accessProven inside CompanyGraph; not yet extracted as a moduleCompanyGraph

Foundation clients hold a licence that grows with this catalogue: every module version released — current and future — is theirs to take. The terms are on the ownership & terms page.

The parts are buildable. The connections are the argument.

Any experienced developer can build the boxes on this map — sign-in in a few weeks, an email sender in another. What the map actually documents is the way the boxes are connected. Frontend types are generated from backend contracts, so drift fails the build. Module clients are typed, so a contract change is a compile error. Failures from every box land as records on one page. One real workflow proves the pattern end to end, and orientation docs tell the next contributor why each rule exists. That connective layer is what a first hire cannot rebuild in a quarter while also shipping product — and it is why a foundation arrives as one working system rather than a parts list.

How this becomes your foundation

The package installs the relevant modules into your product and deployment, then wires one real workflow end to end through them — sign-up to email to admin to failure record — so the map above stops being a diagram and becomes your system.

Drawn from the running systems, not from a slide. When this page and production disagree, production wins — and this page gets fixed.