Skip to main content

Frontend Overview

The Flo frontend is an Angular 21 SPA using standalone components, signals, OnPush change detection, and PrimeNG for UI.

Tech Stack

TechnologyVersionPurpose
Angular21Framework (standalone components, signals)
PrimeNG21UI component library (Lara theme)
Tailwind CSS3.4Utility-first styling
NGRX ComponentStore21State management
Transloco7.6Internationalization (Italian + English)
TipTap2.24Rich text editor (WYSIWYG)
Leaflet1.9Interactive maps
Chart.js4.5Data visualization
GSAP3.13Animations (sidebar, mobile tab bar)
Vitevia @angular/buildBuild tool

App Structure

src/app/
├── features/ # Feature modules (lazy-loaded)
│ ├── auth/ # Login, register, OTP, password reset
│ ├── dashboard/ # Main authenticated app
│ │ ├── prenotazioni/ # Booking management
│ │ ├── orari/ # Scheduling
│ │ ├── account/ # User profile & settings
│ │ └── amministrazione/ # Admin panel
│ │ ├── utenti/ # User management
│ │ ├── professionisti/ # Staff management
│ │ ├── servizi/ # Service/activity management
│ │ ├── locazioni/ # Locations
│ │ ├── chiusure/ # Studio closures
│ │ ├── blogs/ # Blog management (Strapi)
│ │ ├── newsletter/ # Newsletter management
│ │ ├── gallery/ # Media gallery
│ │ └── settings/ # App settings (SuperAdmin)
│ ├── immobili/ # Dynamic entity management
│ └── home/ # Privacy policy, terms
├── components/ # 33 shared components
├── services/ # API clients, stores, utilities
├── guards/ # Auth, role, feature flag guards
├── pipes/ # Custom pipes (branding, formatting)
├── directives/ # Custom directives
├── utils/ # Helper utilities
└── assets/i18n/ # Translation files (it.json, en.json)

Key Patterns

Standalone Components

All components are standalone (no NgModules):

@Component({
selector: 'app-feature',
standalone: true,
imports: [CommonModule, TranslocoModule, ButtonModule],
changeDetection: ChangeDetectionStrategy.OnPush
})

Signal-Based Reactivity

// Local component state
protected readonly loading = signal(false);
protected readonly searchTerm = signal('');

// Derived state
protected readonly hasFilters = computed(() => this.searchTerm().length > 0);

Thin Components

All business logic lives in stores/services. Components only handle:

  • Template bindings
  • UI event delegation to stores
  • Local UI state (signals)

Dependency Injection

Use inject() function, never constructor injection:

private readonly store = inject(GlobalStore);
private readonly messageService = inject(MessageService);

Template Control Flow

Use new Angular control flow syntax:

@if (loading()) {
<p-progressSpinner />
} @else {
@for (item of items(); track item.id) {
<app-item [data]="item" />
}
}

Icons

Material Symbols only. PrimeIcons are forbidden:

<!-- Correct -->
<span class="material-symbols-outlined">add</span>

<!-- Forbidden -->
<i class="pi pi-plus"></i>

API Clients

Auto-generated from backend OpenAPI spec using NSwag:

npm run generate-proxies

Produces:

  • src/app/services/client.ts — Private API client
  • src/app/services/public-api-client.ts — Public API client

PWA

  • Service worker enabled in production builds
  • Separate manifests per brand
  • Auto-update checks every 6 hours
  • Install prompts via @khmyznikov/pwa-install

Internationalization

Uses @jsverse/transloco with Italian as default:

  • Translations pre-loaded during APP_INITIALIZER
  • Language preference persisted in localStorage
  • PrimeNG component translations updated on language change
  • CI check validates both translation files have matching keys

All user-facing text must use the Transloco pipe:

{{ 'feature.title' | transloco }}

Translations must be added to both it.json and en.json.