Skip to content

Frontend Developer Onboarding

A practical guide to becoming productive on the Microtec ERP Angular micro-frontend.

Prerequisites: Complete Day 1 Checklist first
Stack: Angular 17, Nx workspace, NgRx, PrimeNG, Bootstrap 5, NgModule architecture


Workspace Overview

The frontend lives in the MFE-Apps/ submodule (Nx workspace) and FrontApps/ (legacy workspace):

MFE-Apps/                          ← Primary: Nx-managed micro-frontend workspace
├── projects/
│   ├── apps-accounting/           # Accounting module (port 4402)
│   ├── apps-hr/                   # HR module (port 4403)
│   ├── apps-finance/              # Finance module (port 4404)
│   ├── apps-sales/                # Sales module (port 4405)
│   ├── apps-purchase/             # Purchase module (port 4406)
│   ├── apps-inventory/            # Inventory module (port 4407)
│   ├── app-distribution/          # Distribution module (port 4408)
│   ├── fixed-assets/              # Fixed assets module (port 4409)
│   ├── erp-home/                  # ERP portal shell (port 4401)
│   └── bussiness-owners/          # Business owner portal (port 4301)
└── libs/
    ├── shared-lib/                # Shared components, services, auth logic
    └── shared-assets/             # i18n translations, images, fonts

[INFO] FrontApps/ contains an older version of the same workspace. For new features, work in MFE-Apps/. Check with your team lead which one is current for your sprint.


Getting Started

bash
cd ~/Projects/microtec/Erp/MFE-Apps

# Install dependencies
npm i --f

# Start the Accounting app
npx nx serve accounting

# App opens at http://localhost:4402

Start all apps simultaneously

bash
# [WARNING] Requires ~32 GB RAM — not recommended on 16 GB machines
npm run start:all
bash
# Start ERP home shell + the module you're working on
npx nx serve erp-home &
npx nx serve apps-accounting

App Architecture

Each app follows Module Federation — independently deployable Angular apps that load into the ERP shell at runtime.

erp-home (shell)
  ├── Lazy loads → apps-accounting (remote)
  ├── Lazy loads → apps-hr (remote)
  ├── Lazy loads → apps-inventory (remote)
  └── ... (other remotes)

Key architectural rules

  1. NgModule-based architecture onlystandalone: false on all components. Do NOT create standalone components.
  2. No direct cross-app imports — use the shell's routing or shared-lib instead.
  3. All shared UI components go in libs/shared-lib/src/lib/components/
  4. All auth logic uses microtec-auth-lib from shared-lib — never implement auth directly in an app.

Module Structure

Inside each app (apps-accounting as example):

apps-accounting/
├── src/
│   ├── app/
│   │   ├── app.module.ts          # Root NgModule
│   │   ├── app-routing.module.ts  # Feature routes
│   │   └── features/
│   │       ├── invoices/
│   │       │   ├── invoices.module.ts
│   │       │   ├── invoices-routing.module.ts
│   │       │   ├── components/
│   │       │   │   ├── invoice-list/
│   │       │   │   └── invoice-form/
│   │       │   ├── services/
│   │       │   │   └── invoice.service.ts
│   │       │   └── store/          # NgRx
│   │       │       ├── invoice.actions.ts
│   │       │       ├── invoice.reducer.ts
│   │       │       ├── invoice.effects.ts
│   │       │       └── invoice.selectors.ts
│   │       └── ...
│   └── environments/
│       ├── environment.ts           # development
│       ├── environment.stage.ts     # stage
│       ├── environment.cloud.ts     # cloud/preprod
│       └── environment.prod.ts      # production

Shared Libraries

shared-lib — common UI components

typescript
// Import shared components via the library
import { MicrotecTableModule }   from '@microtec/shared-lib';
import { MicrotecFormModule }    from '@microtec/shared-lib';
import { MicrotecDialogModule }  from '@microtec/shared-lib';
typescript
// Auth service — always use this, never roll your own
import { AuthService } from '@microtec/shared-lib/auth';

@Component({...})
export class MyComponent {
  constructor(private auth: AuthService) {}

  getCurrentUser() {
    return this.auth.currentUser$;  // Observable<User>
  }
}

shared-assets — i18n translations

Add translation keys to both language files:

json
// shared-assets/i18n/en.json
{
  "invoice": {
    "title": "Invoices",
    "form": {
      "number": "Invoice Number",
      "total":  "Total Amount"
    }
  }
}
json
// shared-assets/i18n/ar.json
{
  "invoice": {
    "title": "الفواتير",
    "form": {
      "number": "رقم الفاتورة",
      "total":  "المبلغ الإجمالي"
    }
  }
}

Usage in templates:

html
<h1>{{ 'invoice.title' | translate }}</h1>
<label>{{ 'invoice.form.number' | translate }}</label>

State Management with NgRx

Every feature that communicates with the API uses NgRx:

typescript
// actions
export const loadInvoices      = createAction('[Invoice] Load Invoices');
export const loadInvoicesSuccess = createAction('[Invoice] Load Invoices Success',
  props<{ invoices: Invoice[] }>());
export const loadInvoicesFailure = createAction('[Invoice] Load Invoices Failure',
  props<{ error: string }>());

// effects
@Injectable()
export class InvoiceEffects {
  loadInvoices$ = createEffect(() =>
    this.actions$.pipe(
      ofType(loadInvoices),
      switchMap(() => this.invoiceService.getAll().pipe(
        map(invoices  => loadInvoicesSuccess({ invoices })),
        catchError(err => of(loadInvoicesFailure({ error: err.message })))
      ))
    )
  );
  constructor(private actions$: Actions, private invoiceService: InvoiceService) {}
}

UI Components

The platform uses PrimeNG for complex UI components and Bootstrap 5 for layout:

html
<!-- PrimeNG DataTable with pagination -->
<p-table [value]="invoices$ | async"
         [paginator]="true"
         [rows]="10"
         [loading]="loading$ | async">
  <ng-template pTemplate="header">
    <tr>
      <th>{{ 'invoice.form.number' | translate }}</th>
      <th>{{ 'invoice.form.total' | translate }}</th>
    </tr>
  </ng-template>
  <ng-template pTemplate="body" let-invoice>
    <tr>
      <td>{{ invoice.number }}</td>
      <td>{{ invoice.total | currency:'SAR' }}</td>
    </tr>
  </ng-template>
</p-table>

<!-- Bootstrap layout -->
<div class="container-fluid">
  <div class="row">
    <div class="col-md-6">...</div>
    <div class="col-md-6">...</div>
  </div>
</div>

Styling Conventions

  • Use SCSS for all component styles
  • BEM naming convention for custom CSS classes: .invoice-form__field--error
  • Use CSS variables from the Microtec design tokens:
    scss
    .my-component {
      color: var(--primary-color);        // Microtec brand primary
      background: var(--surface-ground);  // PrimeNG surface token
      border-radius: var(--border-radius);
    }
  • RTL support is built in via Angular CDK — always test in both dir="ltr" and dir="rtl"

Running Tests

bash
cd MFE-Apps

# Run tests for a specific project
npx nx test apps-accounting

# Run with coverage
npx nx test apps-accounting --coverage

# Run all tests
npx nx run-many --target=test --all

# Watch mode (recommended during TDD)
npx nx test apps-accounting --watch

Building for Production

bash
# Build a single app
npx nx build apps-accounting --configuration=production

# Build all apps
npm run build:all:prod

# Output goes to: dist/apps/apps-accounting/

Environment Configuration

Each app has 4 environment files. The active one is selected at build time:

Fileng build configurationDeployed to
environment.tsdevelopment (default)Local dev
environment.stage.tsstageStage
environment.cloud.tscloudPreprod / UAT
environment.prod.tsproductionProduction
typescript
// environment.ts example
export const environment = {
  production:  false,
  apiBaseUrl:  'http://localhost:5000',
  keycloakUrl: 'http://localhost:8080/auth',
  realm:       'microtec',
  clientId:    'apps-accounting'
};

Nx Useful Commands

bash
# Show dependency graph
npx nx graph

# Lint a project
npx nx lint apps-accounting

# Generate a new component
npx nx g @schematics/angular:component features/invoices/components/invoice-form \
  --project=apps-accounting \
  --module=invoices

# Generate a new service
npx nx g @schematics/angular:service features/invoices/services/invoice \
  --project=apps-accounting

# Show affected projects (useful before running tests)
npx nx affected:graph

Common Issues

ProblemSolution
npm i failsUse npm i --f (force)
Module federation error on startupStart the shell app (erp-home) before remote apps
i18n key not translatingCheck both ar.json and en.json have the key
standalone: true component breaksUse standalone: false — project standard
CORS error calling APIUse the API proxy config in proxy.conf.json
NgRx action not dispatchedCheck that the module imports StoreModule.forFeature(...)

Internal Documentation — Microtec Platform Team