Skip to main content

Overview

BarberApp follows a feature-based folder structure with clear separation between domain logic, infrastructure, and presentation layers. This organization makes it easy to locate files and understand the application architecture at a glance.
Total TypeScript files: 114+ across features, core, services, and shared modules

Root Structure

src/app/
├── core/               # Domain layer (business logic, entities, interfaces)
├── services/           # Adapters layer (Firebase, Cloudinary implementations)
├── features/           # Use cases layer (feature modules)
├── shared/             # Shared UI components and utilities
├── layouts/            # Application layouts (main, dashboard)
├── app.config.ts       # Application configuration
├── app.routes.ts       # Root routing configuration
└── app.ts              # Root component
Each top-level folder has a specific responsibility based on Clean Architecture principles.

Core Directory (core/)

The domain layer containing framework-independent business logic.

Structure

core/
├── interfaces/         # Repository contracts and tokens
│   ├── auth.repository.ts
│   ├── auth.repository.token.ts
│   ├── user.repository.ts
│   ├── user.repository.token.ts
│   ├── specialty.repository.ts
│   ├── specialty.repository.token.ts
│   ├── appointment.repository.ts
│   └── appointment.repository.token.ts
├── models/             # Domain entities
│   ├── user-base.model.ts
│   ├── client.model.ts
│   ├── specialist.model.ts
│   ├── appointment.model.ts
│   ├── specialty.model.ts
│   ├── availability.model.ts
│   ├── rating.model.ts
│   ├── diagnosis.model.ts
│   ├── info-page.model.ts
│   └── index.ts        # Barrel export
├── enums/              # Business enumerations
│   ├── user-roles.enum.ts
│   ├── user-status.enum.ts
│   ├── sex.enum.ts
│   ├── appointment-status.enum.ts
│   ├── enum-labels.ts
│   └── index.ts
├── guards/             # Route guards (access control)
│   ├── auth.guard.ts
│   ├── public.guard.ts
│   ├── role.guard.ts
│   ├── id.guard.ts
│   └── record.guard.ts
├── validators/         # Custom form validators
├── constants/          # Business constants
│   ├── availability-presets.ts
│   └── weekdays-map.ts
├── utils/              # Pure utility functions
├── data/               # Static data or fixtures
└── config/             # Application configuration

Key Files

Each repository has two files:
// 1. Interface definition (*.repository.ts)
export interface AuthRepository {
  login(email: string, password: string): Promise<void>;
  logout(): Promise<void>;
}

// 2. InjectionToken (*.repository.token.ts)
export const AUTH_REPOSITORY = new InjectionToken<AuthRepository>(
  'AUTH_REPOSITORY'
);
Current repositories:
  • AuthRepository - Authentication operations
  • UserRepository - User CRUD operations
  • SpecialtyRepository - Specialty management
  • AppointmentRepository - Appointment scheduling
TypeScript interfaces representing business entities:
export interface UserBase {
  id: string;
  firstName: string;
  lastName: string;
  email: string;
  role: UserRoles;
  status: UserStatus;
  // ... other fields
}
Models include:
  • User models (UserBase, Client, Specialist)
  • Appointment, Specialty, Availability
  • Rating, Diagnosis
  • InfoPage (CMS content)
All models are exported through index.ts for clean imports.
Functional guards implementing access control:
  • auth.guard.ts - Requires authentication
  • public.guard.ts - Redirects authenticated users
  • role.guard.ts - Role-based access control
  • id.guard.ts - Parameter validation
  • record.guard.ts - Resource ownership validation
// Usage in routes
{
  path: 'dashboard',
  canActivate: [authGuard],
  children: [...]
}
Enumerations for type-safe constants:
export enum UserRoles {
  CLIENT = 'client',
  SPECIALIST = 'specialist',
  ADMIN = 'admin',
}

export enum AppointmentStatus {
  PENDING = 'pending',
  CONFIRMED = 'confirmed',
  CANCELLED = 'cancelled',
  COMPLETED = 'completed',
}

Services Directory (services/)

The adapters layer with concrete implementations of repository interfaces.

Structure

services/
├── firebase/
│   ├── firebase-auth.service.ts
│   ├── firebase-user.service.ts
│   ├── firebase-specialty.service.ts
│   └── firebase-appointment.service.ts
└── cloudinary/
    └── cloudinary.service.ts
@Injectable({ providedIn: 'root' })
export class FirebaseAuthService implements AuthRepository {
  private auth: Auth = inject(Auth);

  async login(email: string, password: string): Promise<void> {
    await signInWithEmailAndPassword(this.auth, email, password);
  }

  async logout(): Promise<void> {
    await signOut(this.auth);
  }

  // ... other methods
}
Services are registered in app.config.ts using their corresponding InjectionTokens.

Features Directory (features/)

The use cases layer organized by feature domains.

Structure

features/
├── auth/                   # Authentication feature
│   ├── auth.facade.ts      # State management & business logic
│   ├── auth.routes.ts      # Feature routes
│   ├── pages/
│   │   ├── login-page/
│   │   │   ├── login-page.component.ts
│   │   │   ├── login-page.component.html
│   │   │   └── login-page.component.css
│   │   └── register-page/
│   │       ├── register-page.component.ts
│   │       ├── register-page.component.html
│   │       └── register-page.component.css
│   ├── components/
│   │   ├── login-form/
│   │   ├── register-form/
│   │   ├── input-custom/
│   │   ├── select-custom/
│   │   ├── specialty-selector/
│   │   └── fast-login-card/
│   └── services/           # Feature-specific services (if needed)
├── dashboard/              # Dashboard feature
│   ├── dashboard.routes.ts
│   ├── pages/
│   │   ├── client-dashboard/
│   │   └── specialist-dashboard/
│   └── components/
│       ├── appointments-table/
│       ├── stats-card/
│       └── quick-actions/
├── appointments/            # Appointments feature
│   └── components/
│       ├── appointment-form/
│       └── appointment-card/
├── clients/                # Clients management
│   └── components/
├── specialties/            # Specialties management
├── landing/                # Landing page
│   ├── landing.routes.ts
│   ├── pages/
│   │   └── home-page/
│   └── components/
│       ├── hero-section/
│       ├── features-section/
│       └── testimonials/
├── info/                   # Information pages (CMS)
│   ├── info.routes.ts
│   └── pages/
│       ├── info-page/
│       └── help-page/
└── errors/                 # Error pages
    └── pages/
        └── not-found/

Feature Module Pattern

Each feature follows this structure:
1

Facade (Business Logic)

Manages state and orchestrates repository calls.
@Injectable({ providedIn: 'root' })
export class AuthFacade {
  private authService = inject(AUTH_REPOSITORY);
  private _user = signal<UserBase | null>(null);
  
  async login(email: string, password: string) { ... }
}
2

Routes (Lazy Loading)

Defines feature-specific routes.
export const AUTH_ROUTES: Routes = [
  { path: 'login', loadComponent: () => import('./pages/login-page/...')},
  { path: 'register', loadComponent: () => import('./pages/register-page/...')},
];
3

Pages (Route Components)

Smart components connected to facades.
@Component({ ... })
export class LoginPageComponent {
  authFacade = inject(AuthFacade);
}
4

Components (Presentational)

Reusable UI components within the feature.
@Component({ ... })
export class LoginFormComponent {
  @Input() loading = false;
  @Output() submitForm = new EventEmitter();
}
  • pages/: Route-connected components (smart/container)
  • components/: Reusable presentational components (dumb)
This separation follows the Container/Presentational pattern:
  • Pages handle state and business logic
  • Components focus on UI and emit events

Shared Directory (shared/)

Reusable components and services used across multiple features.

Structure

shared/
├── components/
│   ├── header/
│   │   ├── header.component.ts
│   │   ├── header.component.html
│   │   └── header.component.css
│   ├── header-dashboard/
│   ├── footer/
│   ├── navbar/
│   ├── dialog/
│   ├── splash/
│   ├── checkbox-custom/
│   ├── title-description/
│   └── user-submenu/
├── services/
│   ├── dialog/
│   │   └── dialog.service.ts
│   └── navigation/
│       └── navigation.service.ts
└── icons/                  # SVG icon components
Components in shared/ should be generic and reusable. Feature-specific components belong in features/*/components/.

Layouts Directory (layouts/)

Application-level layout components.

Structure

layouts/
├── main-layout/
│   ├── main-layout.component.ts
│   ├── main-layout.component.html
│   └── main-layout.component.css
└── dashboard-layout/
    ├── dashboard-layout.component.ts
    ├── dashboard-layout.component.html
    └── dashboard-layout.component.css

Usage in Routes

app.routes.ts
export const routes: Routes = [
  // Main layout for public pages
  {
    path: '',
    component: MainLayoutComponent,
    children: [
      { path: 'home', loadChildren: () => import('./features/landing/...') },
      { path: 'auth', loadChildren: () => import('./features/auth/...') },
    ],
  },
  // Dashboard layout for authenticated pages
  {
    path: 'dashboard',
    component: DashboardLayoutComponent,
    canActivate: [authGuard],
    children: [
      { path: '', loadChildren: () => import('./features/dashboard/...') },
    ],
  },
];

File Naming Conventions

Component Files

<name>.component.ts      # Component class
<name>.component.html    # Template
<name>.component.css     # Styles

Page Components

<name>.page.ts           # Page component (alternative)
<name>-page.component.ts # Page component (standard)

Services & Facades

<name>.service.ts        # Service class
<name>.facade.ts         # Facade (business logic + state)

Models, Interfaces, Enums

<name>.model.ts          # Domain model
<name>.repository.ts     # Repository interface
<name>.enum.ts           # Enumeration
<name>.guard.ts          # Route guard
Naming Rule: Use kebab-case for all file names. Avoid camelCase or PascalCase in filenames.

Import Paths

Barrel Exports

Use index.ts files to simplify imports:
core/models/index.ts
export * from './user-base.model';
export * from './client.model';
export * from './specialist.model';
export * from './appointment.model';
// ...
Usage
// Instead of:
import { UserBase } from '../../core/models/user-base.model';
import { Client } from '../../core/models/client.model';

// Use:
import { UserBase, Client } from '../../core/models';

Relative Imports

BarberApp uses relative imports (no path aliases configured):
// From features/auth/auth.facade.ts
import { AUTH_REPOSITORY } from '../../core/interfaces/auth.repository.token';
import { UserBase } from '../../core/models';
import { UserRoles } from '../../core/enums';
You can optionally configure path aliases in tsconfig.json for cleaner imports:
{
  "compilerOptions": {
    "paths": {
      "@core/*": ["src/app/core/*"],
      "@features/*": ["src/app/features/*"],
      "@shared/*": ["src/app/shared/*"]
    }
  }
}

Directory Best Practices

Colocation

Keep related files together (component, template, styles in same folder)

Feature Independence

Features should be self-contained and not import from other features

Shallow Nesting

Avoid deeply nested folders (max 3-4 levels)

Single Responsibility

Each file should have one clear purpose

Dependency Rules

1

Features can import from

  • core/ (models, interfaces, enums)
  • shared/ (shared components, services)
  • Same feature only
2

Services can import from

  • core/ (interfaces they implement)
  • External libraries (Firebase, etc.)
3

Core cannot import from

  • features/
  • services/
  • shared/
Core is framework-independent.
Anti-pattern: Never import from features/ in another feature. Use shared/ or create a facade/service instead.

Complete Directory Tree

src/app/
├── app.config.ts
├── app.routes.ts
├── app.ts
├── core/
│   ├── config/
│   ├── constants/
│   │   ├── availability-presets.ts
│   │   └── weekdays-map.ts
│   ├── data/
│   ├── enums/
│   │   ├── appointment-status.enum.ts
│   │   ├── enum-labels.ts
│   │   ├── index.ts
│   │   ├── sex.enum.ts
│   │   ├── user-roles.enum.ts
│   │   └── user-status.enum.ts
│   ├── guards/
│   │   ├── auth.guard.ts
│   │   ├── id.guard.ts
│   │   ├── public.guard.ts
│   │   ├── record.guard.ts
│   │   └── role.guard.ts
│   ├── interfaces/
│   │   ├── appointment.repository.token.ts
│   │   ├── appointment.repository.ts
│   │   ├── auth.repository.token.ts
│   │   ├── auth.repository.ts
│   │   ├── specialty.repository.token.ts
│   │   ├── specialty.repository.ts
│   │   ├── user.repository.token.ts
│   │   └── user.repository.ts
│   ├── models/
│   │   ├── appointment.model.ts
│   │   ├── availability.model.ts
│   │   ├── client.model.ts
│   │   ├── diagnosis.model.ts
│   │   ├── index.ts
│   │   ├── info-page.model.ts
│   │   ├── rating.model.ts
│   │   ├── specialist.model.ts
│   │   ├── specialty.model.ts
│   │   └── user-base.model.ts
│   ├── utils/
│   └── validators/
├── features/
│   ├── appointments/
│   │   └── components/
│   ├── auth/
│   │   ├── auth.facade.ts
│   │   ├── auth.routes.ts
│   │   ├── components/
│   │   │   ├── fast-login-card/
│   │   │   ├── input-custom/
│   │   │   ├── login-form/
│   │   │   ├── register-form/
│   │   │   ├── select-custom/
│   │   │   └── specialty-selector/
│   │   ├── pages/
│   │   │   ├── login-page/
│   │   │   └── register-page/
│   │   └── services/
│   ├── clients/
│   │   └── components/
│   ├── dashboard/
│   │   ├── dashboard.routes.ts
│   │   ├── components/
│   │   └── pages/
│   │       ├── client-dashboard/
│   │       └── specialist-dashboard/
│   ├── errors/
│   │   └── pages/
│   │       └── not-found/
│   ├── info/
│   │   ├── info.routes.ts
│   │   └── pages/
│   │       ├── help-page/
│   │       └── info-page/
│   ├── landing/
│   │   ├── landing.routes.ts
│   │   ├── components/
│   │   └── pages/
│   │       └── home-page/
│   └── specialties/
├── layouts/
│   ├── dashboard-layout/
│   │   ├── dashboard-layout.component.css
│   │   ├── dashboard-layout.component.html
│   │   └── dashboard-layout.component.ts
│   └── main-layout/
│       ├── main-layout.component.css
│       ├── main-layout.component.html
│       └── main-layout.component.ts
├── services/
│   ├── cloudinary/
│   │   └── cloudinary.service.ts
│   └── firebase/
│       ├── firebase-appointment.service.ts
│       ├── firebase-auth.service.ts
│       ├── firebase-specialty.service.ts
│       └── firebase-user.service.ts
└── shared/
    ├── components/
    │   ├── checkbox-custom/
    │   ├── dialog/
    │   ├── footer/
    │   ├── header/
    │   ├── header-dashboard/
    │   ├── navbar/
    │   ├── splash/
    │   ├── title-description/
    │   └── user-submenu/
    ├── icons/
    └── services/
        ├── dialog/
        │   └── dialog.service.ts
        └── navigation/
            └── navigation.service.ts

Quick Reference

Add a new feature

  1. Create folder in features/
  2. Add facade, routes, pages, components
  3. Register routes in app.routes.ts

Add a new repository

  1. Define interface in core/interfaces/
  2. Create InjectionToken
  3. Implement in services/
  4. Register in app.config.ts

Add a shared component

  1. Create in shared/components/
  2. Make it reusable and configurable
  3. Use in multiple features

Add a route guard

  1. Create in core/guards/
  2. Implement as functional guard
  3. Apply in route configuration

Next Steps

Architecture Overview

High-level architecture and design principles

Clean Architecture

Three-layer architecture pattern explained

Build docs developers (and LLMs) love