Skip to main content
The S-Parking web dashboard is a vanilla JavaScript SPA deployed on Firebase Hosting, providing global CDN distribution, automatic SSL, and HTTP/2 support.

Prerequisites

1

Install Firebase CLI

npm install -g firebase-tools
2

Login to Firebase

firebase login
This opens a browser window for Google authentication.
3

Initialize Project

cd web-dashboard
firebase init hosting
Select your existing Firebase project or create a new one.

Firebase Configuration

The S-Parking project uses the following firebase.json configuration:
firebase.json
{
  "hosting": {
    "public": ".",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**",
      "gcp-functions/**",
      "**/*.ps1",
      "**/*.md",
      ".vscode/**"
    ],
    "headers": [
      {
        "source": "**/*.html",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "no-cache"
          }
        ]
      },
      {
        "source": "css/**",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "public, max-age=86400"
          }
        ]
      },
      {
        "source": "js/**",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "public, max-age=86400"
          }
        ]
      },
      {
        "source": "assets/**",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "public, max-age=604800"
          }
        ]
      }
    ]
  }
}

Configuration Breakdown

Public Directory

"public": "."
Serves files from the current directory (web-dashboard/). All HTML, CSS, JS, and assets are in the root.

Ignored Files

"ignore": [
  "firebase.json",
  "**/.*",
  "**/node_modules/**",
  "gcp-functions/**",
  "**/*.ps1",
  "**/*.md",
  ".vscode/**"
]
Excludes backend functions, config files, and development artifacts from deployment.

Cache Headers Strategy

S-Parking implements a multi-tier caching strategy for optimal performance:
{
  "source": "**/*.html",
  "headers": [{
    "key": "Cache-Control",
    "value": "no-cache"
  }]
}
Resource TypeCache DurationRationale
HTMLNo cacheEnsures users always get the latest version
CSS/JS24 hours (86400s)Balance between performance and update frequency
Assets7 days (604800s)Static images/icons rarely change
The no-cache directive for HTML files forces browsers to revalidate with the server on each request. This ensures users receive updated JavaScript/CSS references immediately after deployment.

Deployment Process

Standard Deployment

1

Build and Deploy

cd web-dashboard
firebase deploy --only hosting
This uploads all files to Firebase Hosting and applies cache headers.
2

Verify Deployment

Firebase CLI outputs the hosting URL:
✔  Deploy complete!

Hosting URL: https://your-project.web.app
3

Test Live Site

Open the URL in a browser and verify:
  • Dashboard loads correctly
  • Google Maps renders
  • Real-time parking data appears

Preview Deployment (Testing)

Test changes before going live:
firebase hosting:channel:deploy preview
This creates a temporary URL like https://your-project--preview-abc123.web.app valid for 7 days.
Preview channels are publicly accessible. Do not deploy sensitive data or credentials.

Custom Domain Setup

1

Add Custom Domain

firebase hosting:sites:create your-custom-domain
Or use Firebase Console → Hosting → Add custom domain.
2

Verify Domain Ownership

Add TXT record to your DNS provider:
TXT @ firebase=your-project-id
3

Configure DNS Records

Add A records pointing to Firebase:
A @ 151.101.1.195
A @ 151.101.65.195
4

Wait for SSL Provisioning

Firebase automatically provisions a free SSL certificate. This may take 24-48 hours.

Update Configuration Before Deploy

Before deploying, update API endpoints in js/config/config.js:
js/config/config.js
export const CONFIG = {
    DEBUG: false, // Disable debug logs in production
    
    GOOGLE_MAPS_API_KEY: "YOUR_PRODUCTION_API_KEY",
    GOOGLE_MAPS_ID: "YOUR_MAP_ID",
    
    // Update with deployed Cloud Run URLs
    GET_STATUS_API_URL: "https://get-parking-status-[hash].run.app",
    RESERVATION_API_URL: "https://reserve-parking-spot-[hash].run.app",
    RELEASE_API_URL: "https://release-parking-spot-[hash].run.app",
    CREATE_SPOT_URL: "https://create-parking-spot-[hash].run.app",
    DELETE_SPOT_URL: "https://delete-parking-spot-[hash].run.app",
    GET_ZONES_URL: "https://get-zones-[hash].run.app",
    MANAGE_ZONES_URL: "https://manage-zones-[hash].run.app",
    GET_HISTORY_URL: "https://get-occupancy-history-[hash].run.app",
    
    FIREBASE: {
        apiKey: "YOUR_FIREBASE_KEY",
        authDomain: "your-project.firebaseapp.com",
        projectId: "your-project-id",
        storageBucket: "your-project.appspot.com",
        messagingSenderId: "123456789",
        appId: "1:12345:web:abcdef"
    }
};
NEVER commit API keys to version control! Copy config.example.js to config.js and add config.js to .gitignore.

Rollback to Previous Version

Firebase retains deployment history:
# List all releases
firebase hosting:releases:list

# Rollback to specific version
firebase hosting:rollback
Select the target release from the interactive menu.

Performance Optimization

Enable Compression

Firebase Hosting automatically compresses assets with gzip and Brotli. No configuration needed.

Verify Compression

curl -H "Accept-Encoding: gzip" -I https://your-project.web.app/js/map/core.js
Response should include:
Content-Encoding: gzip

Preconnect to External Services

Add to index.html <head>:
<!-- Preconnect to Google Maps API -->
<link rel="preconnect" href="https://maps.googleapis.com">
<link rel="preconnect" href="https://maps.gstatic.com" crossorigin>

<!-- Preconnect to Cloud Run endpoints -->
<link rel="preconnect" href="https://[region]-[project].run.app">

Monitoring and Analytics

View Hosting Metrics

firebase hosting:channel:list
Or use Firebase Console → Hosting → Usage to see:
  • Bandwidth usage
  • Request count
  • Geographic distribution

Integrate Google Analytics

Add to index.html:
<!-- Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXXX');
</script>

Troubleshooting

Issue: “Error: HTTP Error: 403, Permission Denied”

Solution: Re-authenticate Firebase CLI:
firebase logout
firebase login --reauth

Issue: Stale cached content after deployment

Solution: HTML files use no-cache, but hard refresh to clear browser cache:
  • Chrome/Edge: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac)
  • Firefox: Ctrl+F5 (Windows) or Cmd+Shift+R (Mac)

Issue: 404 errors on direct URL access

Solution: Add rewrites to firebase.json for SPA routing:
"rewrites": [
  {
    "source": "**",
    "destination": "/index.html"
  }
]

Issue: CORS errors when calling Cloud Run

Solution: Ensure Cloud Run functions include CORS headers. S-Parking functions use the cors package:
const cors = require('cors')({origin: true});

exports.yourFunction = (req, res) => {
  cors(req, res, () => {
    // Your function logic
  });
};

CI/CD Integration

Automate deployments with GitHub Actions:
.github/workflows/deploy.yml
name: Deploy to Firebase Hosting

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: '${{ secrets.GITHUB_TOKEN }}'
          firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT }}'
          channelId: live
          projectId: your-project-id
Generate a service account key in Firebase Console → Project Settings → Service Accounts, then add it as a GitHub secret.

Next Steps

Configure Cloud Run

Deploy backend services to Google Cloud Run

Environment Variables

Manage API keys and configuration

Flash ESP32 Firmware

Deploy IoT sensors with production endpoints

Build docs developers (and LLMs) love