A reference implementation showing how a well-organised, production-ready frontend enterprise application should be structured using Angular 20. Every architectural decision is intentional and documented.
This is not a tutorial app. It is a blueprint for teams starting a large-scale Angular project. Every layer, pattern, and file exists to answer the question: "How should we do this in production?"
- ✅ Feature-driven folder structure that scales to 20+ developers
- ✅ Strict one-way dependency rules between layers
- ✅ Signal-based state management without third-party libraries
- ✅ Full HTTP infrastructure with typed interceptor chain
- ✅ Role-based access control at route and template level
- ✅ Lazy-loaded routes throughout
- ✅
OnPushchange detection on every component - ✅ Dark mode with localStorage persistence
- ✅ PrimeNG 20 + TailwindCSS 4 — no style conflicts
| Package | Version |
|---|---|
| Angular Core / CLI | 20.3.x |
| PrimeNG | 20.4.0 |
| TailwindCSS | 4.2.1 |
| RxJS | 7.8.0 |
| TypeScript | 5.9.2 |
| json-server (mock API) | 1.0.0-beta.12 |
# Install dependencies
npm install
# Start Angular dev server + mock REST API together
npm run dev| URL | Service |
|---|---|
http://localhost:4200 |
Angular app |
http://localhost:3000 |
json-server REST API |
| Password | Role | |
|---|---|---|
| admin@demo.com | admin123 | Admin — full access |
| viewer@demo.com | viewer123 | Viewer — read only |
The project enforces a strict one-way dependency flow:
features → shared → core → (nobody)
layout → shared → core
src/app/
├── core/ # Singleton services, guards, interceptors, tokens
├── shared/ # Reusable dumb UI — zero business logic, zero API calls
├── layout/ # App shell (sidebar, topbar, route outlets)
└── features/
├── auth/ # Login flow
├── dashboard/ # KPI overview, charts
└── users/ # Full CRUD user management
Each feature is fully self-contained: pages, components, service, signal store, models, and routes all live together under one folder. Features never import from other features.
Each feature owns a single @Injectable() store scoped to its page
component. State lives in one signal<State> atom, exposed via
computed() selectors. No NgRx, no BehaviorSubject.
All guards and interceptors use Angular's functional API.
The interceptor chain runs: logging → auth → error.
Route :id params bind directly to component input() signals via
withComponentInputBinding() — no ActivatedRoute injection needed.
roleGuardon the route definition*hasRole="'admin'"structural directive in templates
Every component is ChangeDetectionStrategy.OnPush.
Signals make change detection surgical — only components whose
inputs actually changed are checked.
| Feature | Description |
|---|---|
| Login / Logout | JWT simulation, AuthService with signal state |
| Dashboard | Stat cards, user growth line chart, role donut chart |
| User List | Paginated table, role + status filters, skeleton loader |
| User Create | Reactive form, admin-only route guard |
| User Detail | Pre-filled edit form, route param via signal input |
| Dark Mode | ThemeService, toggles .dark on <html>, persisted |
npm run dev # Start everything (Angular + json-server)
npm start # Angular dev server only
npm run api # json-server only on :3000
npm run build # Production buildCheckout the DOCUMENTATION.md for the full architecture deep-dive including diagrams, interceptor chain details, state management patterns, and a complete file catalogue.

