Bondery Docs

Architecture

Bondery is a monorepo managed with Turborepo and npm workspaces. Apps and shared packages share tooling, types, and translations; Turborepo orchestrates dev, build, lint, and type-check across the tree.

GitHubusebondery/bondery

150

Mental model

LayerRole
PostgresSource of truth for all user data (packages/db, Prisma)
Fastify APIBetter Auth, business logic, list/search endpoints, imports, mobile sync (push/pull/bootstrap)
ClientsWebapp, mobile, and Chrome extension — OAuth sessions via Better Auth on the API; app data via the API

Better Auth runs on the API (/auth/*). Clients obtain session cookies or bearer tokens and attach them to API requests. The API uses Prisma (@bondery/db) to read and write Postgres — authorization is enforced in application code, not database RLS.

Domain mutations (create/update/delete contacts, groups, tags, etc.) live in apps/api/src/domains/. REST routes and POST /api/sync/push call the same functions so web, mobile, and future clients stay consistent.

Repository structure

webapp/
mobile/
api/
website/
chrome-extension/
db/
schemas/
translations/
helpers/
emails/
mantine-next/
branding/
vcard/
docs/

Apps

apps/webapp — Web application

Source: apps/webapp · Local dev: port 26632 · http://localhost:26632

The primary user-facing product at app.usebondery.com.

ConcernTechnology
FrameworkNext.js 16 (App Router, React Server Components)
LanguageTypeScript
UIMantine v9 via @bondery/mantine-next
Supplemental stylesTailwind CSS
Data fetchingTanStack Query + lib/query/ fetchers and hooks
API transportclientApi* / serverApi* wrappers in lib/api/client.ts
AuthenticationBetter Auth on the API — webapp uses OAuth 2.1 + PKCE against the API issuer; session cookie encrypted by the webapp
Rich textTiptap
Localizationi18next + react-i18next via @bondery/translations (useWebTranslations)
IconsTabler Icons

Server components and client hooks call the Fastify API with the user's session token. A small set of Next.js route handlers (e.g. streaming chat) proxy to the API after verifying the session locally.


apps/api — REST API server

Source: apps/api · Local dev: port 26631 · http://localhost:26631 · Production: api.usebondery.com

Mobile sync WebSocket: ws://localhost:26631/api/sync/ws (same port as the API).

Central backend for all product data and privileged operations.

ConcernTechnology
FrameworkFastify v5
LanguageTypeScript
DatabasePostgres via Prisma (@bondery/db)
Domain layersrc/domains/* — shared by REST routes and sync push
SyncChangelog pull/bootstrap (GET /api/sync/pull, GET /api/sync/bootstrap), mutation push (POST /api/sync/push)
EmailNodemailer + React Email templates
API contractZod schemas in @bondery/schemas → generated packages/openapi-spec/openapi.yaml → build-time Fumadocs OpenAPI MDX

API documentation pipeline

apps/api/src/routes/*
fastify-zod-openapi + @fastify/swagger
packages/openapi-spec/openapi.yaml (committed artifact)
docs/api/api-reference/_generated/ (build-time MDX)

CI enforces: every public route has description + response; openapi.yaml is up to date; Redocly lint passes. See API routes.

Every authenticated request validates the Better Auth session or API key. List endpoints follow a shared pagination contract (limit, offset, search, sort, nested pagination object).


apps/mobile — Mobile application

Source: apps/mobile · Local dev (Metro): port 26634 · http://localhost:26634

Native iOS and Android client built with Expo. Offline-capable via local SQLite and server-authoritative pull sync.

ConcernTechnology
FrameworkExpo + Expo Router
LanguageTypeScript
UITamagui
Local databaseexpo-sqlite
Read syncGET /api/sync/bootstrap + GET /api/sync/pull (batched sync_change_log)
Write syncREST when online; pending_mutations outbox → POST /api/sync/push when offline
AuthenticationBetter Auth (OAuth via API)
Localizationi18next via @bondery/translations (useMobileTranslations)

See Local development setup for running the sync stack locally.


apps/website — Marketing site

Source: apps/website · Local dev: port 26630 · http://localhost:26630

Public landing page at usebondery.com.

ConcernTechnology
FrameworkNext.js (App Router)
UIMantine v9
Localizationi18next via @bondery/translations

apps/chrome-extension — Browser extension

Source: apps/chrome-extension · Local dev (WXT HMR): port 26633 · http://localhost:26633

Saves contacts from social networks while browsing.

ConcernTechnology
Extension frameworkWXT
UIReact + Mantine v9
AuthenticationBetter Auth OAuth via chrome.identity (API as authorization server)
DataFastify API (contact create/update, redirect endpoint)
Supported sitesLinkedIn, Facebook, Instagram

packages/db — Database

Source: packages/db

PostgreSQL schema, Prisma migrations, and generated client shared by the API.

ConcernTechnology
DatabasePostgreSQL (PostGIS in self-host compose)
ORMPrisma
Migrationsprisma migrate in packages/db/prisma/migrations/
Raw SQLpnpm run db:functions for Postgres functions

Local dev: Postgres on port 54322 via deploy/bondery/docker-compose.dev-db.yml, then:

pnpm run db:migrate:dev

After schema changes, commit the new migration files and regenerate the Prisma client (pnpm run db:generate runs on install).


Fun fact: Bondery local apps use consecutive ports in the 2663x block — phone keypad B-O-N-D2-6-6-3 ("Dial BOND"). Local Postgres uses 54322 (direct connection, no gateway). Local API Redis uses 26636 (pnpm run start:redis). Port constants live in packages/schemas/src/constants/dev-ports.ts.

Shared packages

All compilable packages extend @bondery/typescript-config (NodeNext, declaration + declarationMap). Internal imports use #* subpath imports with .js extensions; external consumers use package.json exports (defaultdist/).

PackageRole
packages/typescript-configShared base.json, react-library.json, nextjs.json tsconfigs
packages/dbPrisma schema, migrations, generated client
packages/schemasZod schemas, types, sync protocol, locale catalog
packages/translationsi18next namespaces and JSON locale files (en, cs, de)
packages/helpersShared utilities, API_ROUTES, global URLs
packages/emailsReact Email templates (preview for local dev, dev for tsc --watch)
packages/mantine-nextReusable Mantine components for Next.js apps
packages/brandingLogos, icon assets, React icon components (@bondery/branding/react)
packages/vcardvCard generation for API export and share flows

Build: rimraf dist && tsc per package. Exports: run pnpm run sync-exports after adding public subpaths. Go-to-definition: declarationMap maps from dist/*.d.ts back to src/.

packages/schemas

Single source of truth for Zod schemas, inferred TypeScript types, and the mobile sync protocol (src/sync/). Import domain types from here — do not redefine them in apps. Database row shapes come from @bondery/db (Prisma).

Supported UI locales are declared in packages/schemas/locale/supported-locales.json and exported as SUPPORTED_LOCALES, DEFAULT_LOCALE, and APP_LOCALE_METADATA from @bondery/schemas/locale.

packages/translations

User-facing copy for webapp, website, mobile, and the Chrome extension. Built on i18next with react-i18next (web) / expo-localization + i18next (mobile). Namespace layout and preload groups live in manifest.json; CI runs i18next-cli for types and lint, and custom scanners (check:i18n:*) for structure, used keys, and locale parity.

Supported locales (source of truth: supported-locales.json above — add every new key under src/locales/{locale}/ for each):

CodeLanguage
enEnglish (reference / fallback)
csCzech
deGerman

In application code, import locale constants from the schemas package (translations re-exports them for convenience):

import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from "@bondery/schemas/locale";
import { i18nConfig, resourceLoader } from "@bondery/translations";

Markdown docs cannot import TypeScript modules; keep supported-locales.json in sync when adding a locale and update this table in the same change.

See also packages/translations/README.md.

packages/helpers

Shared pure utilities, API_ROUTES, global URL constants, and platform helpers used across apps.

packages/emails

React Email templates rendered and sent by the API.

Local dev: port 26639 · pnpm run dev:emailshttp://localhost:26639. Runs alongside the Chrome extension dev server (26633) without a port conflict.

packages/mantine-next

Reusable Mantine-based components (avatars, data tables, modals) shared by webapp and website.

packages/branding

Logos, icon assets, and React icon components.

packages/vcard

vCard generation used by API export and share flows.


Data flow

┌─────────────┐   session   ┌─────────────┐    Prisma     ┌──────────────┐
│   Clients   │ ──────────▶  │  apps/api   │ ────────────▶  │   Postgres   │
│ web / mobile│ ◀──────────  │  (Fastify)  │ ◀────────────  │              │
│  extension  │   JSON       └──────┬──────┘                └──────┬───────┘
└──────┬──────┘                     │                               │
       │                            │ pull / bootstrap              │ changelog
       │ Better Auth (API)          │                               │
       │ (login only)               ▼                               ▼
       └──────────────────▶  mobile SQLite ◀── sync_change_log ──┘

Webapp and extension: Better Auth on the API for login; all contact, group, tag, interaction, and settings data through the API.

Mobile: Better Auth for login; bootstrap + pull for reads; mutation outbox → sync push for tier-1 writes. Server state wins on pull; optimistic is_pending is UI-only until push completes.

API internals: Route handlers are thin. domains/* functions accept a DomainContext (user, Prisma client) and return { data, txid } where sync confirmation is required.


Sync (mobile)

The API validates the session and serves per-user changelog batches from sync_change_log.

PathPurpose
GET /api/sync/bootstrapInitial SQLite snapshot
GET /api/sync/pullIncremental batched changes
POST /api/sync/pushApply offline mutation outbox

Protocol version headers (X-Bondery-Sync-Protocol, X-Bondery-SQLite-Schema) gate compatibility. Full design: Sync architecture (mobile).


On this page