Join our FREE personalized newsletter for news, trends, and insights that matter to everyone in America

Newsletter
New

Introducing Caf: Clean Architecture Frontend

Card image cap

Write your business logic once. Run it in React, Vue, or Angular—or the next framework. CAF (Clean Architecture Frontend) is a library that gives you a framework-agnostic core so the same domain and use cases can run in any frontend by swapping adapters.

The problem

Frontend apps often mix UI, state, and business rules. When you switch frameworks or need to share logic across React, Vue, and Angular, you usually rewrite a lot of code. Clean Architecture helps, but doing it well with a single, framework-agnostic core is hard. CAF provides that core: primitives and interfaces so your domain and use cases stay framework-free.

What is CAF?

CAF is a framework-agnostic core for building frontends with Clean Architecture. You implement domain and application layers once; React, Vue, or Angular (and future frameworks) plug in via small adapter packages. No lock-in to a single UI stack.

In short:

  • Framework-agnostic — One core; many UIs.
  • Clean Architecture — Clear domain, application, and infrastructure layers.
  • Reactive primitives — A single reactive engine (Pulse) and Ploc for presentation logic.
  • Pluggable adapters — Routing, HTTP, and UI are interfaces; you (or the ecosystem) implement them.
  • TypeScript-first — Typed UseCases, RequestResult, and Plocs end-to-end.

Core ideas

Concept What it does
Pulse A single reactive value (like a ref). Use it for one piece of state (e.g. loading flag, current user).
Ploc Presentation Logic Component — a stateful bloc built on Pulse. Holds UI-related state and methods.
UseCase An application operation (command or query). Returns RequestResult<T> (loading, data, error) so the UI can show loading/error/success.
RouteRepository Abstraction over routing. Your app implements it (e.g. with React Router or Vue Router); RouteManager uses it for auth and navigation.

Domain and application code depend only on these abstractions. Infrastructure (HTTP, routing, storage) and the UI layer depend on your framework; the core does not.

Example: React + TypeScript

You put your domain, use cases, and Plocs in a caf/ folder (framework-agnostic), then wire them at the app root and use React hooks in components.

1. Wire the app with CAFProvider (e.g. in main.tsx or App.tsx):

import { CAFProvider } from '@c-a-f/infrastructure-react';  
import { setupUserPloc } from './caf/setup';  
  
const userPloc = setupUserPloc();  
  
export default function App() {  
  return (  
    <CAFProvider plocs={{ user: userPloc }}>  
      <YourApp />  
    </CAFProvider>  
  );  
}  

2. In a component, read state from the Ploc and call methods:

import { usePlocFromContext, usePloc } from '@c-a-f/infrastructure-react';  
import type { UserPloc } from '../caf/application';  
  
export function UserList() {  
  const ploc = usePlocFromContext<UserPloc>('user');  
  if (!ploc) return null;  
  
  const [state] = usePloc(ploc);  
  
  return (  
    <div>  
      {state.loading && <p>Loading...</p>}  
      {state.error && <p>Error: {state.error}</p>}  
      <button onClick={() => ploc.loadUsers()} disabled={state.loading}>  
        Refresh  
      </button>  
      <ul>  
        {state.users.map((u) => (  
          <li key={u.id}>{u.name}{u.email}</li>  
        ))}  
      </ul>  
    </div>  
  );  
}  

The same UserPloc and use cases can drive a Vue or Angular UI; only the hooks (or composables/injectors) change.

The repo at a glance

The CAF repository is a monorepo with:

  • Core: @c-a-f/core — UseCase, Ploc, Pulse, ApiRequest, RouteManager, and shared interfaces.
  • Infrastructure (adapters):
    • @c-a-f/infrastructure-react — React hooks (usePloc, useUseCase, CAFProvider, useRouteManager, useRouteRepository).
    • @c-a-f/infrastructure-vue — Vue composables and providers.
    • @c-a-f/infrastructure-angular — Angular services and injectors.
  • Optional modules: @c-a-f/validation (Zod, Yup, etc.), @c-a-f/workflow, @c-a-f/permission, @c-a-f/i18n, @c-a-f/testing, @c-a-f/devtools, @c-a-f/cli for scaffolding.

Examples live in the same repo: example-react, example-vue, example-angular, plus example-vue-graphql and example-angular-websocket. Each app has its own caf/ folder (domain, application, infrastructure) so you can copy the structure into your project.

Who is it for?

  • Teams that want one domain/application layer and the option to ship with React, Vue, or Angular.
  • Developers who care about testability and clear boundaries (domain vs application vs infrastructure).
  • Anyone tired of framework-specific "Clean Architecture" recipes and wants a small, shared core and conventions.

Quick start

# Core + your framework  
npm install @c-a-f/core  
npm install @c-a-f/infrastructure-react   # or -vue, -angular  
  
# Optional: scaffold a project  
npm install -g @c-a-f/cli  
caf-init  

Then create a caf/ folder with domain/, application/, infrastructure/, and a setup that wires repositories, use cases, and Plocs. The docs and README in the repo walk through the exact layout and a minimal flow (e.g. GetUsers UseCase → Ploc → React/Vue/Angular UI).

Where to go next

If you're looking for a small, type-safe core to share Clean Architecture across React, Vue, and Angular, CAF is worth a look.