Architecture
How the Kwit platform is structured and how data flows
Design principles
Organization-scoped multi-tenancy
Every resource - product, customer, subscription, invoice, API key - belongs to an organization. The organization is the tenant boundary; there is no cross-org access.
Vertical feature slices
Features are built end-to-end: Prisma schema → Zod validation in @kwit/utils/schemas → service in @kwit/api → tRPC (dashboard) and/or REST v1 (public API) → UI. The same services power both surfaces.
Decimal money
Monetary amounts use Prisma Decimal end-to-end. API responses expose amounts as numbers/strings in the dashboard and SDK; never store floats for money.
Runtime components
| Component | Role |
|---|---|
apps/web | Dashboard, hosted checkout/portal pages, marketing |
apps/server | Express API: Better Auth, tRPC, /v1 REST, webhooks |
packages/api | Business logic and provider adapters |
packages/db | Prisma schema and generated client |
kwit-sdk | Typed HTTP client for /v1 |
Payment provider abstraction
Kwit is not a payment processor. The zahls.ch adapter tokenizes cards and charges pre-authorized tokens. Swiss QR Bill is generated on invoice PDFs when enabled in billing config - customers can pay by bank transfer without a card.
The provider adapter reports success/failure only. Dunning (retries, emails, cancellation) is owned by Kwit’s billing engine.
Public API vs dashboard
- Dashboard - Session auth via Better Auth; tRPC routers under
@kwit/api/routers - Public v1 -
Authorization: Bearer kwit_live_…; routes inapps/server/src/routes/v1.ts
Both call the same services, so behavior stays consistent.