Skip to main content

Overview

The Happy Habitat frontend is an Angular 19 single-page application (SPA) that serves as the user interface for the condominium management system. This guide covers building and deploying to various hosting platforms.

Prerequisites

  • Node.js 18+ and npm
  • Angular CLI 19.2.15 or higher
  • Production backend API (see Backend Deployment)

Technology Stack

The frontend application uses (see package.json):
  • Angular 19.2.0 - Framework
  • TypeScript 5.7.2 - Language
  • Tailwind CSS 4.1.13 - Styling framework
  • DaisyUI 5.1.7 - Component library
  • Chart.js 4.5.0 - Data visualization
  • RxJS 7.8.0 - Reactive programming

Building for Production

Install Dependencies

cd ~/workspace/source/happy-habitat-frontend
npm install

Configure Production Environment

Edit src/environments/environment.prod.ts with your production API URL:
import { LogLevel } from '../app/shared/interfaces/log.interface';

export const environment = {
  production: true,
  apiUrl: 'https://api.happyhabitat.com/api', // Your backend API URL
  apiVersion: 'v1',
  appName: 'Happy Habitat',
  appVersion: '1.0.0',
  logging: {
    level: LogLevel.WARN,
    enableConsole: false,
    enableRemote: true,
    enableStackTraces: true
  },
  auth: {
    useMockAuth: false
  }
};
The build process automatically replaces environment.ts with environment.prod.ts when building for production (see angular.json:49-54).

Build the Application

npm run build
This creates an optimized production build in dist/happy-habitat/browser/ with:
  • Minified JavaScript and CSS
  • Output hashing for cache busting
  • Tree-shaking for smaller bundle sizes
  • AOT (Ahead-of-Time) compilation
The application uses hash-based routing (HashLocationStrategy in app.config.ts:24). URLs will use the # symbol (e.g., https://app.example.com/#/dashboard). This simplifies deployment as all routes can be handled by index.html without server-side rewrite rules.

Build Output

The production build generates:
  • index.html - Main HTML file
  • main-[hash].js - Application code
  • polyfills-[hash].js - Browser polyfills
  • styles-[hash].css - Compiled styles
  • Static assets from public/ directory

Bundle Size Optimization

The Angular configuration sets bundle size limits (angular.json:36-46):
  • Initial bundle: 900kB warning, 1MB error
  • Component styles: 4kB warning, 8kB error
To analyze bundle size:
npm run build -- --stats-json
npx webpack-bundle-analyzer dist/happy-habitat/browser/stats.json

Deployment Options

Option 1: Static Web Hosting (Nginx)

  1. Install Nginx:
sudo apt update
sudo apt install nginx
  1. Copy Build Files:
sudo mkdir -p /var/www/happyhabitat
sudo cp -r dist/happy-habitat/browser/* /var/www/happyhabitat/
  1. Configure Nginx (/etc/nginx/sites-available/happyhabitat):
server {
    listen 80;
    listen [::]:80;
    server_name app.happyhabitat.com;

    root /var/www/happyhabitat;
    index index.html;

    # Gzip compression
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_vary on;
    gzip_min_length 1000;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Cache static assets
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Angular routing - serve index.html for all routes
    location / {
        try_files $uri $uri/ /index.html;
    }

    # API proxy (optional - if API is on same domain)
    location /api {
        proxy_pass https://api.happyhabitat.com;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  1. Enable Site and Reload:
sudo ln -s /etc/nginx/sites-available/happyhabitat /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
  1. Configure SSL with Let’s Encrypt:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d app.happyhabitat.com

Option 2: Azure Static Web Apps

  1. Install Azure CLI:
npm install -g @azure/static-web-apps-cli
  1. Create Static Web App:
az staticwebapp create \
  --name happyhabitat-frontend \
  --resource-group happyhabitat-rg \
  --location "East US 2" \
  --sku Standard
  1. Configure Build (staticwebapp.config.json):
{
  "routes": [
    {
      "route": "/api/*",
      "rewrite": "https://api.happyhabitat.com/api/{path}"
    },
    {
      "route": "/*",
      "serve": "/index.html",
      "statusCode": 200
    }
  ],
  "navigationFallback": {
    "rewrite": "/index.html",
    "exclude": ["/images/*.{png,jpg,gif}", "/css/*"]
  },
  "globalHeaders": {
    "X-Content-Type-Options": "nosniff",
    "X-Frame-Options": "SAMEORIGIN",
    "X-XSS-Protection": "1; mode=block"
  },
  "mimeTypes": {
    ".json": "application/json"
  }
}
  1. Deploy:
npm run build
az staticwebapp deploy \
  --name happyhabitat-frontend \
  --resource-group happyhabitat-rg \
  --app-location dist/happy-habitat/browser

Option 3: AWS S3 + CloudFront

  1. Create S3 Bucket:
aws s3 mb s3://happyhabitat-frontend
aws s3 website s3://happyhabitat-frontend \
  --index-document index.html \
  --error-document index.html
  1. Configure Bucket Policy:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::happyhabitat-frontend/*"
    }
  ]
}
  1. Upload Files:
npm run build
aws s3 sync dist/happy-habitat/browser/ s3://happyhabitat-frontend \
  --delete \
  --cache-control "public, max-age=31536000" \
  --exclude "index.html" \
  --exclude "*.json"

# Upload index.html without caching
aws s3 cp dist/happy-habitat/browser/index.html s3://happyhabitat-frontend/ \
  --cache-control "no-cache, no-store, must-revalidate"
  1. Create CloudFront Distribution:
aws cloudfront create-distribution \
  --origin-domain-name happyhabitat-frontend.s3-website-us-east-1.amazonaws.com \
  --default-root-object index.html
  1. Configure Error Pages:
  • Set custom error response for 404 to return /index.html with 200 status

Option 4: Vercel

  1. Install Vercel CLI:
npm install -g vercel
  1. Create vercel.json:
{
  "version": 2,
  "builds": [
    {
      "src": "package.json",
      "use": "@vercel/static-build",
      "config": {
        "distDir": "dist/happy-habitat/browser"
      }
    }
  ],
  "routes": [
    {
      "src": "/(.*)",
      "dest": "/index.html"
    }
  ]
}
  1. Add Build Script to package.json:
{
  "scripts": {
    "vercel-build": "ng build --configuration production"
  }
}
  1. Deploy:
vercel --prod

Option 5: Docker + Nginx

  1. Create Dockerfile:
# Build stage
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM nginx:alpine
COPY --from=build /app/dist/happy-habitat/browser /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
  1. Create nginx.conf:
server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}
  1. Build and Run:
docker build -t happyhabitat-frontend:latest .
docker run -d -p 80:80 happyhabitat-frontend:latest

Environment-Specific Builds

Runtime Configuration

For dynamic API URLs without rebuilding:
  1. Create assets/config.json:
{
  "apiUrl": "https://api.happyhabitat.com/api"
}
  1. Load Configuration in app.ts:
export function initializeApp(http: HttpClient) {
  return () =>
    http
      .get('/assets/config.json')
      .toPromise()
      .then((config: any) => {
        // Set runtime configuration
      });
}
  1. Update Configuration per Environment:
# Replace config.json during deployment
echo '{"apiUrl":"https://staging-api.example.com/api"}' > dist/happy-habitat/browser/assets/config.json

Performance Optimization

Enable Production Mode

Production builds automatically enable:
  • AOT compilation
  • Tree shaking
  • Minification
  • Output hashing

Lazy Loading

Implement route-based lazy loading:
const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
  }
];

Service Worker (PWA)

Add Progressive Web App capabilities:
ng add @angular/pwa
npm run build

Security Best Practices

Content Security Policy

Add to index.html:
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; 
               script-src 'self' 'unsafe-inline'; 
               style-src 'self' 'unsafe-inline'; 
               img-src 'self' data: https:; 
               connect-src 'self' https://api.happyhabitat.com;">

Security Headers

Configure via web server (Nginx, CloudFront, etc.):
  • X-Frame-Options: SAMEORIGIN
  • X-Content-Type-Options: nosniff
  • X-XSS-Protection: 1; mode=block
  • Strict-Transport-Security: max-age=31536000

CI/CD Integration

GitHub Actions

Create .github/workflows/deploy.yml:
name: Deploy Frontend

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: npm run build
      - name: Deploy to Azure
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_TOKEN }}
          app_location: "dist/happy-habitat/browser"

Troubleshooting

Blank Page After Deployment

  1. Check browser console for errors
  2. Verify API URL in environment.prod.ts
  3. Check CORS configuration on backend
  4. Ensure all routes return index.html (for Angular routing)

API Connection Failed

  1. Verify backend is accessible from frontend domain
  2. Check CORS configuration includes frontend URL
  3. Verify SSL certificates if using HTTPS
  4. Check browser network tab for request details

Assets Not Loading

  1. Verify base href in index.html: <base href="/">
  2. Check file permissions on server
  3. Verify nginx/server configuration for static files

Next Steps

Build docs developers (and LLMs) love