Skip to main content
Refract is a layered TypeScript monorepo. Each layer has a single responsibility and communicates with the next through explicit typed contracts — so AI agents and human developers always know where a change belongs. That sounds like ceremony, but it is really about damage control: Stripe, Redis, and your mailer never become “hidden globals” in React components, and the stuff that must stay correct (billing, RBAC) lives in utilities you can test without booting HTTP.

The layers

Key principles

Resolvers are thin. A GraphQL resolver receives input, calls a utility function, and returns a result. It never contains business logic, never calls the database directly, and never imports a vendor SDK. Tools are injected, not imported. Every resolver and utility receives a tools object. No part of the codebase imports pino, Stripe, or redis directly — it only calls tools.logger, tools.paymentProcessor, tools.cache. Configuration resolves once. process.env is read exactly once, in apps/backend/src/configuration/<env>.ts. Everything downstream receives a typed, validated ConfigType. Implementations are swappable. Every external dependency — logger, queue, metrics, mailer, analytics — is pluggable. Change the client value in config and the loader dynamically imports the right package. Nothing else changes.

Architecture deep dives

What’s next?

Start with whichever system you’re about to touch:
  • Authentication — sessions, Passport, email verification, OAuth
  • Platform MCP — super-admin MCP server, OAuth, registry
  • GDPR Consent Flow — cookie/session consent propagation and analytics gates
  • RBAC — roles, scopes, and how feature access is gated
  • Billing — Stripe subscriptions, webhooks, checkout, downgrades
  • Tooling system — how pluggable tools are loaded and swapped
  • Frontend app — React + GraphQL wiring, generated hooks, and Apollo caching