View on GitHub

incap

Test Project: MEAN stack with Typescript

Frontend Technical Details

Overview

The INCAP frontend is an Angular 21 Single Page Application (SPA) built with TypeScript, featuring a responsive Bootstrap 5 UI and modern Component-driven architecture.

Technology Stack

Core Technologies

Build & Development

Project Structure

frontend/
├── src/
│   ├── index.html                 # Entry HTML file
│   ├── main.ts                    # Bootstrap entry point
│   ├── styles.scss                # Global styles
│   ├── proxy.conf.json            # Dev proxy configuration
│   ├── app/
│   │   ├── app.component.ts       # Root component
│   │   ├── app.component.html     # Root template
│   │   ├── app.component.scss     # Root styles
│   │   ├── app.module.ts          # Root module
│   │   ├── app-routing.module.ts  # Root routing
│   │   ├── app.settings.ts        # Configuration service
│   │   │
│   │   ├── admin/                 # Admin feature module
│   │   │   ├── admin.component.ts
│   │   │   ├── admin.component.html
│   │   │   ├── admin.module.ts
│   │   │   └── ...
│   │   │
│   │   ├── articles/              # Articles feature module
│   │   │   ├── articles.component.ts
│   │   │   ├── articles.component.html
│   │   │   ├── articles.module.ts
│   │   │   └── ...
│   │   │
│   │   └── assets/
│   │       └── settings.json      # Environment configuration
│   │
│   ├── environments/               # Environment files
│   │   ├── environment.ts         # Development config
│   │   └── environment.prod.ts    # Production config
│   │
│   ├── browserslist               # Browser support definition
│   └── proxy.conf.json            # API proxy config
│
├── angular.json                   # Angular CLI config
├── tsconfig.json                  # TypeScript config
├── vitest.config.ts               # Vitest configuration
├── vitest.setup.ts                # Vitest setup file
├── nginx.conf                     # Nginx configuration
├── Dockerfile                     # Container definition
├── package.json                   # Dependencies
└── README.md                      # README

Module Architecture

Root Module (app.module.ts)

AppModule
├── BrowserModule
├── AppRoutingModule
├── NgbModule (ng-bootstrap)
├── FontAwesomeModule
└── AppComponent (Root Component)

Configuration:

@NgModule({
  declarations: [],
  bootstrap: [AppComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
    RouterModule,
    NgbModule,
    FontAwesomeModule,
    AppComponent // Standalone component
  ],
  providers: [
    provideAppInitializer(...),
    provideHttpClient(withInterceptorsFromDi())
  ]
})

Routing Structure

const routes: Routes = [
  { path: '', component: AppComponent },                    // Home
  { path: 'admin', loadChildren: () => AdminModule },      // Lazy-loaded
  { path: 'articles', loadChildren: () => ArticlesModule } // Lazy-loaded
];

Routing Features:

Key Components

App Component

Purpose: Root application component

Responsibilities:

App Settings Service

Location: app/app.settings.ts

Purpose: Configuration management and initialization

// Configuration interface
export class AppSettings {
  categoriesApiUrl: string;
  usersApiUrl: string;
  articlesApiUrl: string;
}

// Service for configuration
@Injectable({ providedIn: 'root' })
export class AppSettingsService {
  public settings: AppSettings;
}

// HTTP-based initialization
@Injectable({ providedIn: 'root' })
export class AppSettingsHttpService {
  public initializeApp(): void {
    this.http.get('assets/settings.json')
      .subscribe((res: AppSettings) => 
        this.appSettingsService.settings = res);
  }
}

Configuration File (assets/settings.json):

{
  "categoriesApiUrl": "http://backend:4000/categories",
  "usersApiUrl": "http://backend:4000/users",
  "articlesApiUrl": "http://backend:4000/articles"
}

Initialization Strategy:

export function app_Init(appSettingsHttpService: AppSettingsHttpService): () => void {
  return () => appSettingsHttpService.initializeApp();
}

// Used in providers
provideAppInitializer(() => {
  const initializerFn = app_Init(inject(AppSettingsHttpService));
  return initializerFn();
})

Admin Module

Purpose: Content management interface (lazy-loaded)

Features:

Articles Module

Purpose: Article browsing and display (lazy-loaded)

Features:

Styling Strategy

Bootstrap 5 Integration

// In app.module.ts
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

// Provides:
// - Modal components
// - Accordion/collapse
// - Pagination
// - Dropdowns
// - Tabs

Global Styles

File: styles.scss

Includes:

Component Styles

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.scss']
})

HTTP Communication

HttpClient Integration

Configuration in app.module.ts:

providers: [
  provideHttpClient(withInterceptorsFromDi())
]

Usage Pattern:

constructor(private http: HttpClient) {}

// GET request
this.http.get<Article[]>(this.settings.articlesApiUrl)
  .subscribe((articles) => this.articles = articles);

// POST request
this.http.post<Article>(this.settings.articlesApiUrl, newArticle)
  .subscribe((created) => this.articles.push(created));

API URLs

Dynamically configured from settings.json:

Testing Strategy

Test Framework: Vitest

Configuration (vitest.config.ts):

{
  environment: 'jsdom',
  include: ['**/*.spec.ts', '**/*.spec.tsx', 'src/**/*.spec.ts'],
  globals: true,
  setupFiles: ['./vitest.setup.ts'],
  coverage: {
    provider: 'v8',
    reporter: ['text', 'lcov'],
    reportsDirectory: 'coverage'
  }
}

Test Patterns

Component Testing:

describe('ArticlesComponent', () => {
  it('should fetch articles on init', () => {
    // Arrange
    const mockArticles = [...];
    
    // Act
    component.ngOnInit();
    
    // Assert
    expect(component.articles).toEqual(mockArticles);
  });
});

Running Tests

# Unit tests
npm run test:unit

# Watch mode
npm test

# Coverage report
npm run coverage

Build Process

Development Build

npm start

Production Build

npm run build

Proxy Configuration (proxy.conf.json)

{
  "/categories": {
    "target": "http://localhost:4000",
    "secure": false
  },
  "/users": {
    "target": "http://localhost:4000",
    "secure": false
  },
  "/articles": {
    "target": "http://localhost:4000",
    "secure": false
  }
}

Deployment

Docker Deployment

Dockerfile:

nginx Configuration (nginx.conf):

Code Quality

ESLint Configuration

Features:

Coverage Goals

Development Best Practices

Standalone Components

@Component({
  selector: 'app-feature',
  standalone: true,
  imports: [CommonModule, FormsModule]
})

Lazy-Loading

{ 
  path: 'admin', 
  loadChildren: () => import('./admin/admin.module')
    .then(m => m.AdminModule) 
}

Dependency Injection

constructor(private http: HttpClient) {}

Reactive Programming

articles$ = this.articles.asObservable();

ngOnInit() {
  this.articles$
    .pipe(
      map(articles => articles.filter(a => a.category === this.selectedCategory)),
      tap(filtered => console.log(filtered))
    )
    .subscribe();
}

Environment Configuration

Development Environment (environment.ts)

Production Environment (environment.prod.ts)

Angular Version Features

Angular 21 Capabilities Used


For API implementation details, see Backend Technical Details.