Skip to main content

Introduction

The Sushi Restaurant App is built on a modern, scalable architecture that combines Ionic Framework, Angular, and Capacitor to deliver a cross-platform mobile experience. This architecture enables code reuse across web, iOS, and Android platforms while maintaining native performance.

Technology Stack

Ionic Framework

UI components and cross-platform tools (v8.0.0)

Angular

Application framework and dependency injection (v20.0.0)

Capacitor

Native runtime for mobile deployment (v8.1.0)

Architectural Patterns

Component-Service-Model Pattern

The application follows Angular’s best practices with a clear separation of concerns:
1

Components

Handle presentation logic and user interactions
2

Services

Manage business logic and data operations
3

Models

Define type-safe data structures using TypeScript interfaces
Model (src/app/home/home.model.ts)
export interface Registro {
  id: string;
  nombre: string;
  foto: string;
  observaciones: string[];
}
Service (src/app/home/home.service.ts)
@Injectable({
  providedIn: 'root',
})
export class RegistrosServiceTs {
  private registros: Registro[] = [
    {
      id: '1',
      nombre: 'Ceviche de Pescado',
      foto: 'https://images.unsplash.com/...',
      observaciones: ['Pescado fresco', 'Limón', 'Cebolla morada']
    },
    // ... more items
  ];

  getRegistros() {
    return [...this.registros];
  }

  getRegistro(registroId: string) {
    return {
      ...this.registros.find((registro) => registro.id === registroId),
    };
  }
}
Component (src/app/home/home.page.ts)
@Component({
  selector: 'app-home',
  templateUrl: './home.page.html',
  styleUrls: ['./home.page.scss'],
  standalone: false,
})
export class HomePage implements OnInit {
  registros: Registro[] = [];

  constructor(private registrosService: RegistrosServiceTs) {}

  ngOnInit() {
    this.registros = this.registrosService.getRegistros();
  }
}

Dependency Injection

Angular’s dependency injection system provides services throughout the application:
src/app/home/home.service.ts
@Injectable({
  providedIn: 'root', // Service available application-wide
})
export class RegistrosServiceTs {
  // Service implementation
}
The providedIn: 'root' configuration creates a singleton service instance that’s shared across the entire application, ensuring data consistency.

Ionic Framework Integration

IonicModule Configuration

The application bootstraps Ionic through the root module:
src/app/app.module.ts
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    IonicModule.forRoot(), // Initializes Ionic components
    AppRoutingModule
  ],
  providers: [
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

Ionic Components

The app leverages Ionic’s pre-built UI components for a native look and feel:
  • ion-header / ion-toolbar: Navigation headers
  • ion-content: Scrollable content areas
  • ion-card: Display restaurant menu items
  • ion-button: Interactive buttons
  • ion-alert: Confirmation dialogs
Ionic components automatically adapt to platform-specific design guidelines (Material Design for Android, Cupertino for iOS)

Capacitor: Mobile Runtime

Capacitor bridges web code to native platforms, enabling deployment to iOS and Android.

Capacitor Configuration

capacitor.config.ts
import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'io.ionic.starter',
  appName: 'Restaurant',
  webDir: 'www' // Output directory from Angular build
};

export default config;

Native Plugins

The application uses Capacitor plugins for native functionality:
package.json
{
  "dependencies": {
    "@capacitor/app": "8.0.1",
    "@capacitor/haptics": "8.0.1",
    "@capacitor/keyboard": "8.0.1",
    "@capacitor/status-bar": "8.0.1"
  }
}

@capacitor/app

App lifecycle and state management

@capacitor/haptics

Tactile feedback for user interactions

@capacitor/keyboard

Keyboard behavior and events

@capacitor/status-bar

Status bar styling and control

Build and Deployment Flow

1

Development

Run ng serve for web development with hot reload
2

Build

Execute ng build to compile to www/ directory
3

Sync

Run npx cap sync to copy web assets to native projects
4

Native Build

Use npx cap open ios or npx cap open android to build native apps
Always run ng build before npx cap sync to ensure native platforms have the latest web assets.

Module Organization

Root Module (AppModule)

The root module bootstraps the entire application:
src/app/app.module.ts
@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,           // Browser-specific services
    IonicModule.forRoot(),   // Ionic initialization
    AppRoutingModule         // Application routing
  ],
  providers: [
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Feature Modules

Features are organized as lazy-loaded modules:
src/app/home/home.module.ts
@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    HomePageRoutingModule  // Feature-specific routing
  ],
  declarations: [HomePage]
})
export class HomePageModule {}
Feature modules encapsulate related components, services, and routing, promoting code organization and reusability.

Application Entry Point

The application bootstraps through Angular’s platform-browser-dynamic:
src/main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch(err => console.log(err));

Key Architectural Benefits

Write once, deploy to web, iOS, and Android with a single codebase. The combination of Ionic and Capacitor abstracts platform differences.
TypeScript interfaces and models provide compile-time type checking, reducing runtime errors and improving code quality.
The component-service-model pattern ensures business logic is separated from presentation, making the codebase maintainable and testable.
Route-based code splitting reduces initial bundle size and improves application load time.
Capacitor provides direct access to native APIs while maintaining the development speed of web technologies.

Next Steps

Project Structure

Explore the directory layout and file organization

Routing System

Learn about navigation and lazy loading

Build docs developers (and LLMs) love