Circle V2 is a ground-up rebuild of the CircleHealth application. The legacy app is sometimes referred to as "legacy" and this codebase as "v2". The goal is a clean, maintainable codebase that follows strong conventions and makes it easy for developers to do the right thing by default.
| Layer | Technology | Version |
|---|---|---|
| Monorepo | Turborepo | latest |
| Package manager | pnpm | 10.23.0 |
| Language | TypeScript | 5.9 |
| Framework | Next.js (App Router) | 16 |
| UI library | React | 19 |
| Component system | Chakra UI | v3 |
| Database | PostgreSQL (Supabase) | -- |
| Schema management | Drizzle ORM | latest |
| Query builder | Kysely | latest |
| API layer | tRPC | v11 |
| Validation | Zod | 4 |
| Server data | TanStack React Query | latest |
| Linting/formatting | Biome | latest |
| Runtime | Node.js | >= 20 |
The codebase is organized as a monorepo with two apps (web and storybook) consuming a set of shared @repo/* packages.
subgraph packages [Packages] UI["@repo/ui"] TRPC["@repo/trpc"] Auth["@repo/auth + auth-next"] DB["@repo/db"] Services["@repo/services"] Shared["@repo/errors, safe, logger, utils"] end
subgraph infra [Infrastructure] Supabase["Supabase (Postgres + Auth)"] end
Web --> UI Web --> TRPC Web --> Auth Storybook --> UI
TRPC --> Services TRPC --> DB TRPC --> Auth Services --> DB Auth --> DB DB --> Supabase
Shared -.-> UI Shared -.-> TRPC Shared -.-> DB Shared -.-> Auth
subgraph packages [Packages] UI["@repo/ui"] TRPC["@repo/trpc"] Auth["@repo/auth + auth-next"] DB["@repo/db"] Services["@repo/services"] Shared["@repo/errors, safe, logger, utils"] end
subgraph infra [Infrastructure] Supabase["Supabase (Postgres + Auth)"] end
Web --> UI Web --> TRPC Web --> Auth Storybook --> UI
TRPC --> Services TRPC --> DB TRPC --> Auth Services --> DB Auth --> DB DB --> Supabase
Shared -.-> UI Shared -.-> TRPC Shared -.-> DB Shared -.-> Auth
graph TD
subgraph apps [Apps]
Web["apps/web (Next.js)"]
Storybook["apps/storybook"]
end
subgraph packages [Packages]
UI["@repo/ui"]
TRPC["@repo/trpc"]
Auth["@repo/auth + auth-next"]
DB["@repo/db"]
Services["@repo/services"]
Shared["@repo/errors, safe, logger, utils"]
end
subgraph infra [Infrastructure]
Supabase["Supabase (Postgres + Auth)"]
end
Web --> UI
Web --> TRPC
Web --> Auth
Storybook --> UI
TRPC --> Services
TRPC --> DB
TRPC --> Auth
Services --> DB
Auth --> DB
DB --> Supabase
Shared -.-> UI
Shared -.-> TRPC
Shared -.-> DB
Shared -.-> Auth
A typical data request flows through the following layers:
Browser->>NextApp: HTTP request NextApp->>TRPCRouter: /api/trpc/[procedure] TRPCRouter->>Middleware: authenticatedProcedure Middleware->>TRPCRouter: ctx with user TRPCRouter->>Repo: repo.method() Repo->>PG: Kysely query PG-->>Repo: rows Repo-->>TRPCRouter: Safe result TRPCRouter-->>NextApp: JSON response NextApp-->>Browser: rendered page / data
Browser->>NextApp: HTTP request NextApp->>TRPCRouter: /api/trpc/[procedure] TRPCRouter->>Middleware: authenticatedProcedure Middleware->>TRPCRouter: ctx with user TRPCRouter->>Repo: repo.method() Repo->>PG: Kysely query PG-->>Repo: rows Repo-->>TRPCRouter: Safe result TRPCRouter-->>NextApp: JSON response NextApp-->>Browser: rendered page / data
sequenceDiagram
participant Browser
participant NextApp as Next.js App Router
participant TRPCRouter as tRPC Router
participant Middleware as Auth Middleware
participant Repo as DB Repository
participant PG as PostgreSQL
Browser->>NextApp: HTTP request
NextApp->>TRPCRouter: /api/trpc/[procedure]
TRPCRouter->>Middleware: authenticatedProcedure
Middleware->>TRPCRouter: ctx with user
TRPCRouter->>Repo: repo.method()
Repo->>PG: Kysely query
PG-->>Repo: rows
Repo-->>TRPCRouter: Safe result
TRPCRouter-->>NextApp: JSON response
NextApp-->>Browser: rendered page / data
@repo/db, which return Safe<T> results instead of throwing.Safe<T> over try/catch: A Go-inspired result type used throughout the stack for explicit error handling.@repo/* packages: All shared code lives in monorepo packages, consumed by apps via the @repo/ scope.Next: Getting Started