Angular Architecture Kit / v22

Coming in October 2026

The architecture lives in the lint config, not in the wiki.

A reference Angular 22 codebase for teams that keep re-litigating the same technical decisions. Here, it's not the code that matters most, but the decision. It comes with its context, and also with the cases where it doesn't apply.

Early access at 40% off. One email at launch, nothing else.

pnpm lint
src/app/features/invoicing/domain/invoice.ts:3:1

  3 | import { HttpClient } from '@angular/common/http';
    | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

✖  The domain layer must not know about the framework.
   Move this dependency to infrastructure, behind a port.
   boundaries/dependencies

1 problem (1 error, 0 warnings)

Three layers, one rule, enforced by CI

Every team has a wiki where coding rules get written down. Every developer is supposed to follow them, and six months later, only the person who wrote a rule still remembers it exists. Here, CI is the memory instead.

presentation
Components, Signal Store, Signal Forms
imports domain
infrastructure
HTTP adapters, mappers, MSW handlers
imports domain
domain
Entities, value objects, ports
imports nothing
feature A
Invoicing, billing, anything else
never imports feature B

Three layers, not four. The fourth one, the application layer, only shows up when a use case touches more than one port.

One feature, built end to end

Invoicing: list, detail, creation. Real business rules, real value objects, real error paths. Read it once, and you can copy it straight into your own feature.

invoicing/
├── domain/
│   ├── invoice.ts              entity + state machine
│   ├── money.ts                value object
│   └── invoice-repository.ts   port
├── application/
│   └── issue-invoice.ts        two ports, so it earns a use case
├── infrastructure/
│   ├── http-invoice-repository.ts
│   └── invoice.mapper.ts
└── presentation/
    ├── invoice-list.store.ts   calls the port directly
    ├── invoice-form.component.ts
    └── invoice-form.component.spec.ts

The decisions, not just the code

The rule above can fail CI, but that's not the case for every decision. Signal Store instead of a service isn't something that can be checked automatically, it's a judgment call that needs a different kind of approval.

Twelve architecture decisions ship with the repo. Each one comes with its context, the decision itself, and where that decision stops applying. This is the part your team will actually argue about.

ADR 004: Signal Store over a service with signals

Context

Feature state is shared across sibling components, loaded asynchronously, and derived in several places.

Decision

One NgRx Signal Store per feature, exposed read-only to components.

Rejected alternatives

  • A service holding private signals with public computed values. Fine for local state, but no devtools, no shared convention. Every developer invents their own shape.
  • Classic NgRx. Too much ceremony for CRUD.

When this is the wrong call

State that never leaves a single component (an isolated form, a toggle) does not need a store. Use a signal in the component and move on. A store here costs you a file and buys you nothing.

You're not buying code. You're buying a position you can defend in an architecture review.

And these rules aren't set in stone. Updates are included because an architecture evolves along with the project. When a decision is no longer valid, it gets revised, dated, and explained. You're buying a development philosophy that reflects current practices, not the one from two years ago.

Who wrote this

I'm Sébastien, a freelance Angular developer. Nine years on the framework, most of the last three spent inside other people's legacy codebases, the ones with 3,000-line components, no tests, and a backlog that keeps growing faster than anyone can touch it.

This kit is the architecture I keep rebuilding on those engagements, written down properly once, with the arguments that made it stick.

Angular 22, standalone, pnpm

NgRx Signal Store, Signal Forms

Jest, Testing Library, MSW

eslint-plugin-boundaries, GitHub Actions

CLAUDE.md and four slash commands for Claude Code

Pricing at launch

Lifetime licence, private GitHub repository, updates included. Invoiced, so you can expense it.

€99
Solo: one developer
€59 for the waitlist
€399
Team: up to ten developers
€239 for the waitlist
30 days
If the kit isn't a fit, tell me in one line what's missing and I'll refund you.
You keep reading the ADRs either way