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
interfaces/ - Repository Contracts
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
models/ - Domain Entities
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.
guards/ - Route Protection
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 : [ ... ]
}
enums/ - Domain Constants
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
firebase/firebase-auth.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:
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 ) { ... }
}
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/...' )},
];
Pages (Route Components)
Smart components connected to facades. @ Component ({ ... })
export class LoginPageComponent {
authFacade = inject ( AuthFacade );
}
Components (Presentational)
Reusable UI components within the feature. @ Component ({ ... })
export class LoginFormComponent {
@ Input () loading = false ;
@ Output () submitForm = new EventEmitter ();
}
Why separate pages/ and components/?
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
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:
export * from './user-base.model' ;
export * from './client.model' ;
export * from './specialist.model' ;
export * from './appointment.model' ;
// ...
// 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
Features can import from
core/ (models, interfaces, enums)
shared/ (shared components, services)
Same feature only
Services can import from
core/ (interfaces they implement)
External libraries (Firebase, etc.)
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
View full directory structure
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
Create folder in features/
Add facade, routes, pages, components
Register routes in app.routes.ts
Add a new repository
Define interface in core/interfaces/
Create InjectionToken
Implement in services/
Register in app.config.ts
Add a shared component
Create in shared/components/
Make it reusable and configurable
Use in multiple features
Add a route guard
Create in core/guards/
Implement as functional guard
Apply in route configuration
Next Steps
Architecture Overview High-level architecture and design principles
Clean Architecture Three-layer architecture pattern explained