Skip to main content

Introduction

BarberApp is a modern barber shop management SaaS platform built with Angular 20 and Firebase. The application follows Clean Architecture principles to ensure maintainability, testability, and scalability.

Technology Stack

Frontend Framework

Angular 20

Latest version with standalone components, signals, and modern reactive patterns

TypeScript 5.8

Type-safe development with latest TypeScript features

Backend & Services

Firebase

Authentication, Firestore database, and cloud functions

Cloudinary

Image upload and optimization service

UI & Styling

Tailwind CSS 4

Utility-first CSS framework for rapid UI development

Angular CDK

Material Design component development kit

Architecture Diagram

┌─────────────────────────────────────────────────────────────┐
│                     PRESENTATION LAYER                       │
│  ┌─────────────┐  ┌──────────────┐  ┌──────────────┐       │
│  │   Pages     │  │  Components  │  │   Layouts    │       │
│  │ (Features)  │  │   (Shared)   │  │  (Main/Dash) │       │
│  └──────┬──────┘  └──────┬───────┘  └──────┬───────┘       │
│         │                │                  │                │
│         └────────────────┴──────────────────┘                │
│                          │                                   │
└──────────────────────────┼───────────────────────────────────┘

┌──────────────────────────┼───────────────────────────────────┐
│                  USE CASES / FACADES                          │
│  ┌──────────────────────────────────────────────────┐        │
│  │  AuthFacade (Signals + Business Logic)           │        │
│  │  - State Management (user, loading, error)       │        │
│  │  - Business Rules (role-based routing)           │        │
│  └──────────────────────┬───────────────────────────┘        │
│                         │                                     │
└─────────────────────────┼─────────────────────────────────────┘

┌─────────────────────────┼─────────────────────────────────────┐
│                  ADAPTERS LAYER                               │
│  ┌───────────────────────────────────────────────┐           │
│  │  Injection Tokens (Dependency Inversion)      │           │
│  │  AUTH_REPOSITORY, USER_REPOSITORY, etc.       │           │
│  └──────────────────────┬────────────────────────┘           │
│                         │                                     │
│  ┌──────────────────────┴────────────────────────┐           │
│  │  Firebase Services (Implementation)           │           │
│  │  FirebaseAuthService, FirebaseUserService     │           │
│  └──────────────────────┬────────────────────────┘           │
│                         │                                     │
└─────────────────────────┼─────────────────────────────────────┘

┌─────────────────────────┼─────────────────────────────────────┐
│                   DOMAIN LAYER (CORE)                         │
│  ┌───────────────────────────────────────────────┐           │
│  │  Interfaces (Repository Contracts)            │           │
│  │  AuthRepository, UserRepository               │           │
│  └───────────────────────────────────────────────┘           │
│  ┌───────────────────────────────────────────────┐           │
│  │  Models (Domain Entities)                     │           │
│  │  UserBase, Client, Specialist, Appointment    │           │
│  └───────────────────────────────────────────────┘           │
│  ┌───────────────────────────────────────────────┐           │
│  │  Enums, Guards, Validators, Constants         │           │
│  └───────────────────────────────────────────────┘           │
└───────────────────────────────────────────────────────────────┘

Design Principles

1. Clean Architecture

BarberApp strictly follows Clean Architecture principles with clear separation of concerns:
Contains business entities, interfaces, and rules. This layer is independent of frameworks and external services.Location: src/app/core/
  • Pure TypeScript interfaces and models
  • No dependencies on Angular or Firebase
  • Framework-agnostic business logic
Implements the repository interfaces using specific technologies (Firebase, Cloudinary).Location: src/app/services/
  • Firebase implementations
  • External API integrations
  • Concrete implementations of repository contracts
Contains application-specific business rules, facades, and state management.Location: src/app/features/
  • Facades with Angular Signals
  • Feature-specific business logic
  • State management and orchestration
UI components, pages, and layouts.Locations: src/app/features/*/components/, src/app/shared/components/, src/app/layouts/
  • Standalone components
  • Reactive forms
  • Template-driven UI

2. Dependency Inversion Principle

Key Pattern: BarberApp uses Angular’s InjectionToken to implement dependency inversion, allowing the domain layer to remain independent of implementation details.
// Domain defines the contract (core/interfaces/auth.repository.ts)
export interface AuthRepository {
  login(email: string, password: string): Promise<void>;
  logout(): Promise<void>;
}

// Token for dependency injection (core/interfaces/auth.repository.token.ts)
export const AUTH_REPOSITORY = new InjectionToken<AuthRepository>('AUTH_REPOSITORY');

// Implementation (services/firebase/firebase-auth.service.ts)
@Injectable({ providedIn: 'root' })
export class FirebaseAuthService implements AuthRepository {
  // Firebase-specific implementation
}

// Configuration (app.config.ts)
{ provide: AUTH_REPOSITORY, useClass: FirebaseAuthService }
This pattern makes it easy to:
  • Switch between different backend providers (Firebase → Supabase)
  • Create mock implementations for testing
  • Keep business logic independent of infrastructure

3. Reactive State Management with Signals

BarberApp leverages Angular Signals for modern, efficient reactive state management:
// features/auth/auth.facade.ts
private _user = signal<UserBase | null>(null);
private _loading = signal<boolean>(false);

// Computed values
readonly isAuthenticated = computed(() => !!this._user());
Signals provide:
  • Fine-grained reactivity
  • Automatic change detection optimization
  • Type-safe reactive state
  • Better performance than RxJS for UI state

4. Feature-Based Module Organization

The application is organized by feature domains, each containing:
  • Pages: Route components
  • Components: Feature-specific UI components
  • Services: Feature-specific services (when needed)
  • Routes: Lazy-loaded route configuration
  • Facades: State management and business logic

5. Security & Access Control

Auth Guard

Protects authenticated routes

Public Guard

Restricts already-authenticated users

Role Guard

Enforces role-based access control
Guards are implemented as functional guards (Angular 20 pattern):
// core/guards/auth.guard.ts
export const authGuard = async () => {
  const authFacade = inject(AuthFacade);
  const router = inject(Router);
  
  const isAuthenticated = authFacade.isAuthenticated();
  if (isAuthenticated) return true;
  
  router.navigate(['/auth/login']);
  return false;
};

Key Architecture Benefits

Testability

Repository pattern and dependency injection enable easy unit testing with mock implementations

Maintainability

Clear separation of concerns makes the codebase easy to understand and modify

Scalability

Feature-based organization allows teams to work independently on different modules

Flexibility

Dependency inversion allows swapping implementations without changing business logic

Configuration

The application is configured in app.config.ts using Angular’s ApplicationConfig:
export const appConfig: ApplicationConfig = {
  providers: [
    // Firebase providers
    provideFirebaseApp(() => initializeApp(environment.firebaseConfig)),
    provideAuth(() => getAuth()),
    provideFirestore(() => getFirestore()),
    
    // Repository implementations (Dependency Injection)
    { provide: AUTH_REPOSITORY, useClass: FirebaseAuthService },
    { provide: USER_REPOSITORY, useClass: FirebaseUserService },
    { provide: SPECIALTY_REPOSITORY, useClass: FirebaseSpecialtyService },
    { provide: APPOINTMENT_REPOSITORY, useClass: FirebaseAppointmentService },
    
    // Router configuration
    provideRouter(routes, withInMemoryScrolling({ 
      scrollPositionRestoration: 'enabled' 
    })),
  ]
};
All repository implementations are registered in app.config.ts. This centralized configuration makes it easy to see all dependency bindings at a glance.

Next Steps

Clean Architecture Details

Learn about the three-layer architecture pattern

Folder Structure

Explore the complete directory organization

Build docs developers (and LLMs) love