Architecture · 2026-07-16

Boja: Local-First Chat & Learning Platform

Boja is a TypeScript-first, PostgreSQL-backed chat and learning community platform — think Discord meets Skool — built for instant offline resume. Two native frontends (Expo/React Native and React DOM) share design tokens, domain logic, and Zero-powered sync over a single PostgreSQL source of truth. The API plane is Elysia/OpenAPI self-hosted, with Rocicorp Zero providing query-driven partial sync so clients load instantly from local state and catch up in the background. Infrastructure is self-hosted with Cloudflare enterprise services (Stream, R2, Images, CDN) as the media and delivery plane. Billing runs on NMI + value.io through an in-repo immutable double-entry ledger.

31 Decisions Made ✅
5 Open Items 🟡
TypeScript Full Stack
PostgreSQL + Zero Sync
self-hosted + Cloudflare
System Architecture

Full Stack Diagram

CLIENTS SHARED PKG API PLANE DATA SERVICES EXTERNAL Expo / React Native iOS · Android React DOM Web App TanStack Router · Vite @app/design-tokens DTCG → Terrazzo @app/domain permissions · entitlements zero-queries/mutators Rocicorp Zero shared AppRuntime commands · lifecycle Durable Outbox (msg) offline sends · nonce dedupe Elysia OpenAPI REST · MCP · bojastack CLI Zero cache / sync zero-cache · logical repl. Ephemeral WS presence · typing · Redis TTL Better Auth identity · sessions · passkeys PostgreSQL source of truth · server_id tenancy · self-hosted infrastructure zero-cache logical replication replica Redis / Valkey ephemeral TTL only · self-hosted infrastructure pg-boss workers jobs · outbox delivery Billing Service ledger · NMI · entitlements Files Control Plane R2 signed · TS workers Search Indexer Meilisearch · permission pre-filter LiveKit (self-hosted infrastructure) interactive rooms · fast-follow Cloudflare Stream broadcast · VOD R2 + Images + CDN private objects · edge delivery LiveKit Egress RTMPS → CF Stream Meilisearch (self-hosted infrastructure) search engine · self-hosted NMI + value.io TSYS deal · payments Tax API Anrok/Avalara TBD logical repl outbox Self-hosted production CF Enterprise
Decided Stack

Every Major Decision, One Line Each

Domain Decision Rationale
Language / runtimeTypeScript + Bun-compatible serverFull-stack type safety, single language, monorepo
MonorepoBun workspacesConsistent with Bun runtime, avoids extra toolchain
DatabasePostgreSQL — source of truth, server_id tenancyRelational membership, transactions, Zero logical replication
Sync engineRocicorp Zero (query-driven partial)Unbounded history + jump-to-message; instant local resume
Offline contractCached reads + instant resume + durable message-send outbox onlyServer authority preserved; narrow local command boundary
Native frontendExpo / React NativeTrue native rendering, Expo SDK 52+, New Architecture
Web frontendReact DOM + Vite + TanStack RouterSeparate renderer; shares domain logic and tokens only
Design tokensDTCG format → Terrazzo → web CSS + native TSOne token source; DaisyUI vocabulary on both platforms
Web stylingTailwind v4 + shadcn-style owned components on Base UIAccessible headless primitives + owned themed components
Native stylingUnistyles 3Zero-re-render theme switching; typed TS themes; updateTheme for server branding
AuthenticationBetter Auth — identity/sessions onlyBoja owns servers, memberships, roles; no auth-plugin drift
PermissionsShared pure-TS layered calculator over capability_key/effect rowsDeterministic, auditable, testable; same code on client + server
API layerElysia OpenAPI from day oneVersioned HTTP contract; generated MCP + CLI clients
Ephemeral realtimeBun WS gateway + Redis/Valkey TTLPresence + typing only; no replay requirement
Jobs / backgroundpg-boss (Graphile Worker fallback)PostgreSQL-native enqueue; transactional outbox→job dispatch
Infrastructureself-hosted production + Cloudflare enterprise planeSelf-hosted ownership; contracted CF edge/media services
FilesPrivate R2 + CF Images/Workers/CDN + self-hosted scan workersDirect upload, edge delivery, Postgres authorization authority
Video / liveCloudflare Stream (broadcast/VOD) + LiveKit self-hosted (fast-follow)V1 broadcast bounded; interactive rooms via self-hosted LiveKit
BillingIn-repo NMI + value.io service, immutable double-entry ledgerCustom TSYS deal retained; explicit payment/accounting/entitlement facts
Merchant of recordBoja is default MoR; future Whop/Stripe as verified adaptersOne community membership + entitlement projection
TaxAdapter-isolated Anrok/Avalara candidateRegulatory specialty; still posts to balanced ledger
SearchMeilisearch v1.48 self-hosted (ParadeDB challenger spike)Hybrid BM25+vector; synonym-friendly; known TRW experience
ThreadsThreads as channelsReuses message history, unreads, permissions primitives
BotsFirst-class service principals, capability-row grants, webhook-firstExplicit identity, scope, rate and audit boundaries
Ops CLIbojastack — admin-API-first with redaction + access-explainOperator tooling meets same authorization standards as product APIs
History boundary90-day hot Zero publication + authorized archive APIBounded synced dataset; explicit source-tier seam
DMsv1 — global dm_conversations modelLaunch surface; not modeled as server-owned channels
Access modelInvite-only v1; no anonymous or guest accessReduces authorization ambiguity and public surface
CoursesFull TRW-style learning v1 — modules, prerequisites, role rewardsCourses are paid-community core, not later add-on
SynonymsPlatform-wide dictionary v1; per-server fast-followDomain jargon + creator terminology is a launch hard requirement
Greenfield postureNew company; TRW is prior-art evidence only, no migrationNo legacy data, compatibility machinery or service coupling
Decision Record

31 Decided ✅ · 5 Open 🟡

#1
Product name: "Boja" — working name pending founder confirmation
#2
Rocicorp Zero for query-driven partial sync. Offline = cached reads + instant resume + durable message-send outbox only.
#3
PostgreSQL as source of truth with shared-schema server_id tenancy.
#4
Better Auth for identity/sessions only. Boja owns servers, memberships, invitations, roles.
#5
Layered permission algebra: rank-ordered roles, cross-server attributes, allow/deny effects, timeout mask, bounded owner bypass.
#6
capability_key + effect rows under generated manifest; one pure-TS calculator. Optional bitsets are derived caches only.
#7
Separate Expo/RN + React DOM renderers. Share DTCG tokens, DaisyUI vocab, domain logic. Web: Base UI. Native: Unistyles 3.
#8
self-hosted production + Cloudflare enterprise plane. Other SaaS prototype-only except tax API.
#9
pg-boss for jobs after Bun spike. Graphile Worker fallback if spike fails.
#10
V1 live = broadcast only via Cloudflare Stream. LiveKit self-hosted interactive rooms + Egress = fast-follow.
#11
R2 + CF Images/CDN for files. Thin TS control plane + self-hosted scan workers.
#12
NMI + value.io under custom TSYS deal. Immutable double-entry ledger in-repo.
#13
Boja is default MoR. Future Whop/Stripe = verified external subscription-source adapters only.
#14
Seller payouts + affiliate commissions/reserves are launch-critical. 27-day card-updater + hu2-baseline dunning.
#15
V1 billing scope: no trials, coupons, proration, pauses, crypto, escrow, gift balances, or non-NMI processors.
#16
Tax = adapter-isolated production SaaS (Anrok/Avalara TBD). Posts to tax_payable:<jurisdiction>.
#17
Threads as channels. Bots are v1 first-class service principals with capability-row grants + webhook-first events.
#18
Elysia OpenAPI day one. MCP + CLI clients generated from same contracts.
#19
bojastack = admin-API-first ops CLI with redaction, audit, access-explain, break-glass.
#20
Greenfield new company. TRW = prior-art evidence only. No TRW data migration or runtime dependency.
#21
90-day hot Zero publication + authorized archive API. Explicit source-tier seam.
#22
Offline revocation risk accepted for all servers. No sensitive-server mode in v1.
#23
DMs in v1 — global dm_conversations model, not server-owned channels.
#24
Invite-only v1. No anonymous users, guest access, or public discovery.
#25
Full learning in v1: modules, prerequisites, server-authoritative completion-to-role rewards.
#26
Unreads: dot + exact mention counts.
#27
Push notifications: minimal content, per-server/channel/thread preferences.
#28
Moderation v1: timeout, ban, tombstones, audit only.
#29
All 6 platform surface questions decided: thread auto-reopen, server-owned bots visible, content grant, CLI auth, break-glass policy, webhook 7×/24h retries.
#30
Scale posture: growth from zero, many small servers. Capacity models reflect this distribution.
#31
Synonym search is a hard launch requirement. V1 = one platform-wide dictionary. Per-server = fast-follow.
🟡
Tax vendor: Finance must select Anrok, Avalara or other. Confirm jurisdictions + remittance ops. (See 11 §22.2)
🟡
MoR contract — counsel review: Confirm Boja's default-MoR contract, seller/affiliate liability, payout/KYC, refund/chargeback allocation. (See 11 §18.2)
🟡
Zero spike outcomes: Record zero-cache topology, publication size, failover, rebuild, migration, RN lifecycle results. (See 07 §2, §6)
🟡
Product name confirmation: "Boja" = assumed working name until founder confirms final brand.
🟡
Per-server synonym timing: Platform-wide synonyms confirmed v1. Confirm whether per-server dictionaries move into launch scope. (See 13 Addendum)
Architecture Sections

Deep Dives by Domain

Sync & Offline
Rocicorp Zero query-driven sync, durable message-send outbox, instant-resume contract, 90-day hot/archive boundary.
Sync architecture →
🗄️
Data Model
PostgreSQL schema: messages, channels, roles, courses, attachments. ULID PKs, sort_id cursors, server_id tenancy.
Schema reference →
🔒
Permissions
Layered capability_key/effect rows, rank-ordered roles, timeout mask, owner bypass. One pure-TS shared calculator.
Permission system →
🔑
Authentication
Better Auth for identity/sessions only. Instant-start startup pattern. SecureStore native, HttpOnly web. Passkeys v1.
Auth boundaries →
🎨
Frontends & Theming
DTCG tokens → Terrazzo → Tailwind v4 (web) + Unistyles 3 (native). DaisyUI semantic vocabulary. Per-server runtime branding.
Token pipeline →
🏗️
Infrastructure
pg-boss jobs, outbox delivery, Cloudflare Stream + LiveKit video, private R2 files plane, self-hosted workers.
Infra & services →
💳
Billing
NMI + value.io, immutable double-entry ledger, HU2-baseline dunning, seller payouts, affiliate commissions, entitlement projection.
Billing architecture →
🤖
Platform Surfaces
Threads-as-channels, first-class bots/service principals, Elysia OpenAPI, MCP + CLI generation, bojastack ops CLI.
API surfaces →
🔍
Search
Meilisearch v1.48 hybrid BM25+vector, permission pre-filter + recheck, synonym management, Smart Vault retrieval pipeline.
Search architecture →
🚀
Delivery Plan
Stage 0 Zero viability spike, Stage 1 chat foundation, Stage 2 platform, Stage 3 live rooms. Pass/fail criteria.
Spike plan →
Research Corpus

Level 2 — Full Research Docs

00 — Final Recommendation 01 — TRW Chat Spec 02 — TRW Platform Spec 03 — Sync Engine Landscape 04 — Better Auth Evaluation 05 — Shared TS Domain Architecture 06 — UI/Theming Frameworks 07 — Deep Dive Open Questions 08 — Core Data Model Spec 09 — Infra Services 10 — Platform Surfaces Spec 11 — Billing Service Spec 12 — Decision Record ★ 13 — Search Spec